1 /*
2 ** $Id$
3 ** Standard Operating System library
4 ** See Copyright Notice in lua.h
5 */
6
7 // FIXME: Get rid of all time.h stuff
8 #define FORBIDDEN_SYMBOL_EXCEPTION_time_h
9
10 #include <time.h>
11
12 #define loslib_c
13 #define LUA_LIB
14
15 #include "lua.h"
16
17 #include "lauxlib.h"
18 #include "lualib.h"
19
20 #include "common/system.h"
21 #include "common/textconsole.h"
22
23
os_execute(lua_State * L)24 static int os_execute (lua_State *L) {
25 // Non-portable call, removed in ScummVM.
26 // FIXME: Is this ever invoked? If so, investigate that code further.
27 lua_pushinteger(L, -1); // signal that an error occurred
28 return 1;
29 }
30
31
os_remove(lua_State * L)32 static int os_remove (lua_State *L) {
33 // Non-portable call that deletes a file. Removed in ScummVM.
34 // This call is invoked in sword25 when loading games in order to remove the
35 // temporary savegame thumbnail that the original engine code created. We
36 // embed the thumbnail in the savegame instead, so this call is not needed at
37 // all.
38 return 1;
39 }
40
41
os_rename(lua_State * L)42 static int os_rename (lua_State *L) {
43 // Non-portable call, removed in ScummVM.
44 return 1;
45 }
46
47
os_tmpname(lua_State * L)48 static int os_tmpname (lua_State *L) {
49 // Non-portable call, removed in ScummVM.
50 // FIXME: Why do we return an error in tmpname, but for other
51 // removed methods we just do nothing?
52 return luaL_error(L, "unable to generate a unique filename");
53 }
54
55
os_getenv(lua_State * L)56 static int os_getenv (lua_State *L) {
57 // Non-portable call, removed in ScummVM.
58 // FIXME: Is this ever invoked? If so, investigate that code further.
59 lua_pushstring(L, NULL);
60 return 1;
61 }
62
63
os_clock(lua_State * L)64 static int os_clock (lua_State *L) {
65 // Non-portable call to clock() replaced by invocation of OSystem::getMillis.
66 lua_pushnumber(L, ((lua_Number)g_system->getMillis())/(lua_Number)1000);
67 return 1;
68 }
69
70
71 /*
72 ** {======================================================
73 ** Time/Date operations
74 ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S,
75 ** wday=%w+1, yday=%j, isdst=? }
76 ** =======================================================
77 */
78
setfield(lua_State * L,const char * key,int value)79 static void setfield (lua_State *L, const char *key, int value) {
80 lua_pushinteger(L, value);
81 lua_setfield(L, -2, key);
82 }
83
setboolfield(lua_State * L,const char * key,int value)84 static void setboolfield (lua_State *L, const char *key, int value) {
85 if (value < 0) /* undefined? */
86 return; /* does not set field */
87 lua_pushboolean(L, value);
88 lua_setfield(L, -2, key);
89 }
90
getboolfield(lua_State * L,const char * key)91 static int getboolfield (lua_State *L, const char *key) {
92 int res;
93 lua_getfield(L, -1, key);
94 res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1);
95 lua_pop(L, 1);
96 return res;
97 }
98
99
getfield(lua_State * L,const char * key,int d)100 static int getfield (lua_State *L, const char *key, int d) {
101 int res;
102 lua_getfield(L, -1, key);
103 if (lua_isnumber(L, -1))
104 res = (int)lua_tointeger(L, -1);
105 else {
106 if (d < 0)
107 return luaL_error(L, "field " LUA_QS " missing in date table", key);
108 res = d;
109 }
110 lua_pop(L, 1);
111 return res;
112 }
113
114
os_date(lua_State * L)115 static int os_date (lua_State *L) {
116 #ifdef __PLAYSTATION2__ // missing: gmtime & strftime
117 lua_pushnil(L);
118 #else
119 const char *s = luaL_optstring(L, 1, "%c");
120 // FIXME: Rewrite the code below to use OSystem::getTimeAndDate
121 // Alternatively, remove it, if sword25 does not use it.
122 //
123 // The former would mean sacrificing the ability to choose the timezone, *or*
124 // we would have to drive an effort to add time zone support to OSystem (is it
125 // worth that, though???)
126 time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL));
127 struct tm *stm;
128 if (*s == '!') { /* UTC? */
129 stm = gmtime(&t);
130 s++; /* skip `!' */
131 }
132 else
133 stm = localtime(&t);
134 if (stm == NULL) /* invalid date? */
135 lua_pushnil(L);
136 else if (strcmp(s, "*t") == 0) {
137 lua_createtable(L, 0, 9); /* 9 = number of fields */
138 setfield(L, "sec", stm->tm_sec);
139 setfield(L, "min", stm->tm_min);
140 setfield(L, "hour", stm->tm_hour);
141 setfield(L, "day", stm->tm_mday);
142 setfield(L, "month", stm->tm_mon+1);
143 setfield(L, "year", stm->tm_year+1900);
144 setfield(L, "wday", stm->tm_wday+1);
145 setfield(L, "yday", stm->tm_yday+1);
146 setboolfield(L, "isdst", stm->tm_isdst);
147 }
148 else {
149 char cc[3];
150 luaL_Buffer b;
151 cc[0] = '%'; cc[2] = '\0';
152 luaL_buffinit(L, &b);
153 for (; *s; s++) {
154 if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */
155 luaL_addchar(&b, *s);
156 else {
157 size_t reslen;
158 char buff[200]; /* should be big enough for any conversion result */
159 cc[1] = *(++s);
160 reslen = strftime(buff, sizeof(buff), cc, stm);
161 luaL_addlstring(&b, buff, reslen);
162 }
163 }
164 luaL_pushresult(&b);
165 }
166 #endif
167 return 1;
168 }
169
170
os_time(lua_State * L)171 static int os_time (lua_State *L) {
172 // FIXME: Rewrite the code below to use OSystem::getTimeAndDate.
173 // Alternatively, remove it, if sword25 does not use it.
174 #ifdef __PLAYSTATION2__ // missing: mktime
175 lua_pushnil(L);
176 #else
177 time_t t;
178 if (lua_isnoneornil(L, 1)) /* called without args? */
179 t = time(NULL); /* get current time */
180 else {
181 struct tm ts;
182 luaL_checktype(L, 1, LUA_TTABLE);
183 lua_settop(L, 1); /* make sure table is at the top */
184 ts.tm_sec = getfield(L, "sec", 0);
185 ts.tm_min = getfield(L, "min", 0);
186 ts.tm_hour = getfield(L, "hour", 12);
187 ts.tm_mday = getfield(L, "day", -1);
188 ts.tm_mon = getfield(L, "month", -1) - 1;
189 ts.tm_year = getfield(L, "year", -1) - 1900;
190 ts.tm_isdst = getboolfield(L, "isdst");
191 t = mktime(&ts);
192 }
193 if (t == (time_t)(-1))
194 lua_pushnil(L);
195 else
196 lua_pushnumber(L, (lua_Number)t);
197 #endif
198 return 1;
199 }
200
201
os_difftime(lua_State * L)202 static int os_difftime (lua_State *L) {
203 // FIXME: difftime is not portable, unfortunately.
204 // So we either have to replace this code, or just remove it,
205 // depending on whether sword25 actually uses it.
206 #ifndef __PLAYSTATION2__ // missing: difftime
207 lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
208 (time_t)(luaL_optnumber(L, 2, 0))));
209 #endif
210 return 1;
211 }
212
213 /* }====================================================== */
214
215
os_setlocale(lua_State * L)216 static int os_setlocale (lua_State *L) {
217 // Non-portable call to set the numeric locale. Removed in ScummVM, as it's
218 // not used in sword25.
219 return 1;
220 }
221
222
os_exit(lua_State * L)223 static int os_exit (lua_State *L) {
224 // FIXME: Using exit is not portable!
225 // Using OSystem::quit() isn't really a great idea, either.
226 // We really would prefer to let the main run loop exit, so that
227 // our main() can perform cleanup.
228 if (0 == luaL_optint(L, 1, EXIT_SUCCESS))
229 g_system->quit();
230 error("LUA os_exit invokes with non-zero exit value");
231 }
232
233 static const luaL_Reg syslib[] = {
234 {"clock", os_clock},
235 {"date", os_date},
236 {"difftime", os_difftime},
237 {"execute", os_execute},
238 {"exit", os_exit},
239 {"getenv", os_getenv},
240 {"remove", os_remove},
241 {"rename", os_rename},
242 {"setlocale", os_setlocale},
243 {"time", os_time},
244 {"tmpname", os_tmpname},
245 {NULL, NULL}
246 };
247
248 /* }====================================================== */
249
250
251
luaopen_os(lua_State * L)252 LUALIB_API int luaopen_os (lua_State *L) {
253 luaL_register(L, LUA_OSLIBNAME, syslib);
254 return 1;
255 }
256