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