From b2581e143d7c9a564026fbe3bf4f471b2260fd0f Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Wed, 27 May 2009 22:48:50 +0000 Subject: Lua: add support for os library git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21106 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/lua/README | 2 + apps/plugins/lua/SOURCES | 3 + apps/plugins/lua/gmtime.c | 58 +++++++++++++ apps/plugins/lua/loslib.c | 199 ++++++++++++++++++++++++++++++++++++++++++++ apps/plugins/lua/rockconf.h | 2 + apps/plugins/lua/rocklua.c | 7 +- apps/plugins/lua/strftime.c | 130 +++++++++++++++++++++++++++++ 7 files changed, 398 insertions(+), 3 deletions(-) create mode 100644 apps/plugins/lua/gmtime.c create mode 100644 apps/plugins/lua/loslib.c create mode 100644 apps/plugins/lua/strftime.c (limited to 'apps/plugins/lua') diff --git a/apps/plugins/lua/README b/apps/plugins/lua/README index 593aad2ee7..db6933f517 100644 --- a/apps/plugins/lua/README +++ b/apps/plugins/lua/README @@ -1,7 +1,9 @@ The following files are (with slight modifications for Rockbox) from dietlibc version 0.31 which is licensed under the GPL version 2: + gmtime.c strcspn.c + strftime.c strncat.c strpbrk.c strtol.c diff --git a/apps/plugins/lua/SOURCES b/apps/plugins/lua/SOURCES index 3b9f9348bd..058b991417 100644 --- a/apps/plugins/lua/SOURCES +++ b/apps/plugins/lua/SOURCES @@ -11,6 +11,7 @@ llex.c lmem.c lobject.c lopcodes.c +loslib.c lparser.c lstate.c lstring.c @@ -24,7 +25,9 @@ lzio.c rockaux.c rocklib.c rockmalloc.c +gmtime.c strcspn.c +strftime.c strncat.c strpbrk.c strtoul.c diff --git a/apps/plugins/lua/gmtime.c b/apps/plugins/lua/gmtime.c new file mode 100644 index 0000000000..f13c855de8 --- /dev/null +++ b/apps/plugins/lua/gmtime.c @@ -0,0 +1,58 @@ +#include + +/* seconds per day */ +#define SPD 24*60*60 + +/* days per month -- nonleap! */ +const short __spm[13] = + { 0, + (31), + (31+28), + (31+28+31), + (31+28+31+30), + (31+28+31+30+31), + (31+28+31+30+31+30), + (31+28+31+30+31+30+31), + (31+28+31+30+31+30+31+31), + (31+28+31+30+31+30+31+31+30), + (31+28+31+30+31+30+31+31+30+31), + (31+28+31+30+31+30+31+31+30+31+30), + (31+28+31+30+31+30+31+31+30+31+30+31), + }; + +int __isleap(int year) { + /* every fourth year is a leap year except for century years that are + * not divisible by 400. */ +/* return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); */ + return (!(year%4) && ((year%100) || !(year%400))); +} + +struct tm *gmtime(const time_t *timep) { + static struct tm r; + time_t i; + register time_t work=*timep%(SPD); + r.tm_sec=work%60; work/=60; + r.tm_min=work%60; r.tm_hour=work/60; + work=*timep/(SPD); + r.tm_wday=(4+work)%7; + for (i=1970; ; ++i) { + register time_t k=__isleap(i)?366:365; + if (work>=k) + work-=k; + else + break; + } + r.tm_year=i-1900; + r.tm_yday=work; + + r.tm_mday=1; + if (__isleap(i) && (work>58)) { + if (work==59) r.tm_mday=2; /* 29.2. */ + work-=1; + } + + for (i=11; i && (__spm[i]>work); --i) ; + r.tm_mon=i; + r.tm_mday+=work-__spm[i]; + return &r; +} diff --git a/apps/plugins/lua/loslib.c b/apps/plugins/lua/loslib.c new file mode 100644 index 0000000000..9d29e905e1 --- /dev/null +++ b/apps/plugins/lua/loslib.c @@ -0,0 +1,199 @@ +/* +** $Id: loslib.c,v 1.19.1.3 2008/01/18 16:38:18 roberto Exp $ +** Standard Operating System library +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#define loslib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static int os_pushresult (lua_State *L, int i, const char *filename) { + int en = errno; /* calls to Lua API may change this value */ + if (i) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + lua_pushfstring(L, "%s: %s", filename, strerror(en)); + lua_pushinteger(L, en); + return 3; + } +} + + +static int os_remove (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + return os_pushresult(L, rb->remove(filename) == 0, filename); +} + + +static int os_rename (lua_State *L) { + const char *fromname = luaL_checkstring(L, 1); + const char *toname = luaL_checkstring(L, 2); + return os_pushresult(L, rb->rename(fromname, toname) == 0, fromname); +} + + +/* +** {====================================================== +** Time/Date operations +** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, +** wday=%w+1, yday=%j, isdst=? } +** ======================================================= +*/ + +static void setfield (lua_State *L, const char *key, int value) { + lua_pushinteger(L, value); + lua_setfield(L, -2, key); +} + +static void setboolfield (lua_State *L, const char *key, int value) { + if (value < 0) /* undefined? */ + return; /* does not set field */ + lua_pushboolean(L, value); + lua_setfield(L, -2, key); +} + +static int getboolfield (lua_State *L, const char *key) { + int res; + lua_getfield(L, -1, key); + res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); + lua_pop(L, 1); + return res; +} + + +static int getfield (lua_State *L, const char *key, int d) { + int res; + lua_getfield(L, -1, key); + if (lua_isnumber(L, -1)) + res = (int)lua_tointeger(L, -1); + else { + if (d < 0) + return luaL_error(L, "field " LUA_QS " missing in date table", key); + res = d; + } + lua_pop(L, 1); + return res; +} + + +static int os_date (lua_State *L) { + const char *s = luaL_optstring(L, 1, "%c"); + time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, +#if CONFIG_RTC + rb->mktime(rb->get_time()) +#else + 0 +#endif + ); + struct tm *stm; + if (*s == '!') /* UTC? */ /* Rockbox doesn't support timezones */ + s++; /* skip `!' */ + stm = gmtime(&t); + if (stm == NULL) /* invalid date? */ + lua_pushnil(L); + else if (strcmp(s, "*t") == 0) { + lua_createtable(L, 0, 9); /* 9 = number of fields */ + setfield(L, "sec", stm->tm_sec); + setfield(L, "min", stm->tm_min); + setfield(L, "hour", stm->tm_hour); + setfield(L, "day", stm->tm_mday); + setfield(L, "month", stm->tm_mon+1); + setfield(L, "year", stm->tm_year+1900); + setfield(L, "wday", stm->tm_wday+1); + setfield(L, "yday", stm->tm_yday+1); + setboolfield(L, "isdst", stm->tm_isdst); + } + else { + char cc[3]; + luaL_Buffer b; + cc[0] = '%'; cc[2] = '\0'; + luaL_buffinit(L, &b); + for (; *s; s++) { + if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */ + luaL_addchar(&b, *s); + else { + size_t reslen; + char buff[200]; /* should be big enough for any conversion result */ + cc[1] = *(++s); + reslen = strftime(buff, sizeof(buff), cc, stm); + luaL_addlstring(&b, buff, reslen); + } + } + luaL_pushresult(&b); + } + return 1; +} + +static int os_time (lua_State *L) { + time_t t = -1; +#if CONFIG_RTC + if (lua_isnoneornil(L, 1)) /* called without args? */ + t = rb->mktime(rb->get_time()); /* get current time */ + else { + struct tm ts; + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); /* make sure table is at the top */ + ts.tm_sec = getfield(L, "sec", 0); + ts.tm_min = getfield(L, "min", 0); + ts.tm_hour = getfield(L, "hour", 12); + ts.tm_mday = getfield(L, "day", -1); + ts.tm_mon = getfield(L, "month", -1) - 1; + ts.tm_year = getfield(L, "year", -1) - 1900; + ts.tm_isdst = getboolfield(L, "isdst"); + t = rb->mktime(&ts); + } +#endif + if (t == (time_t)(-1)) + lua_pushnil(L); + else + lua_pushnumber(L, (lua_Number)t); + return 1; +} + + +/* }====================================================== */ + + +static int os_exit (lua_State *L) { + exit(luaL_optint(L, 1, EXIT_SUCCESS)); +} + +static const luaL_Reg syslib[] = { + //{"clock", os_clock}, + {"date", os_date}, + //{"difftime", os_difftime}, + //{"execute", os_execute}, + {"exit", os_exit}, + //{"getenv", os_getenv}, + {"remove", os_remove}, + {"rename", os_rename}, + //{"setlocale", os_setlocale}, + {"time", os_time}, + //{"tmpname", os_tmpname}, + {NULL, NULL} +}; + +/* }====================================================== */ + + + +LUALIB_API int luaopen_os (lua_State *L) { + luaL_register(L, LUA_OSLIBNAME, syslib); + return 1; +} + diff --git a/apps/plugins/lua/rockconf.h b/apps/plugins/lua/rockconf.h index 7ae2245c3a..1b267c78e6 100644 --- a/apps/plugins/lua/rockconf.h +++ b/apps/plugins/lua/rockconf.h @@ -43,8 +43,10 @@ extern char curpath[MAX_PATH]; void *dlrealloc(void *ptr, size_t size); void dlfree(void *ptr); +struct tm *gmtime(const time_t *timep); long strtol(const char *nptr, char **endptr, int base); unsigned long strtoul(const char *str, char **endptr, int base); +size_t strftime(char* dst, size_t max, const char* format, const struct tm* tm); long floor(long x); long pow(long x, long y); diff --git a/apps/plugins/lua/rocklua.c b/apps/plugins/lua/rocklua.c index 5360090cab..1162c026d1 100644 --- a/apps/plugins/lua/rocklua.c +++ b/apps/plugins/lua/rocklua.c @@ -30,9 +30,10 @@ PLUGIN_HEADER static const luaL_Reg lualibs[] = { - {"", luaopen_base}, - {LUA_TABLIBNAME, luaopen_table}, - {LUA_STRLIBNAME, luaopen_string}, + {"", luaopen_base}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_OSLIBNAME, luaopen_os}, {LUA_ROCKLIBNAME, luaopen_rock}, {NULL, NULL} }; diff --git a/apps/plugins/lua/strftime.c b/apps/plugins/lua/strftime.c new file mode 100644 index 0000000000..df230f7bd0 --- /dev/null +++ b/apps/plugins/lua/strftime.c @@ -0,0 +1,130 @@ +#include +#include +#include "plugin.h" + +static const char sweekdays [7] [4] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; +static const char weekdays [7] [10] = { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" +}; +static const char smonths [12] [4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; +static const char* months [12] = { + "January", "February", "March", "April", smonths[5-1], "June", + "July", "August", "September", "October", "November", "December" +}; +static const char ampm [4] [3] = { + "am", "pm", + "AM", "PM" +}; + +static void i2a ( char* dest,unsigned long x ) +{ + int div = 10; + *dest++ = x/div + '0'; + *dest++ = x%div + '0'; + *dest++ = '\0'; +} + +size_t strftime ( char* dst, size_t max, const char* format, const struct tm* tm ) +{ + char* p = dst; + const char* src; + unsigned long no; + char buf [5]; + + if (!max) return 0; + for ( ; *format != '\0'; format++ ) { + if (*format == '%') { + if (*++format == '%') { + *p++ = '%'; + } + else +again: + switch (*format) { +// case '%': *p++ = '%'; break; // reduce size of jump table + case 'n': *p++ = '\n'; break; + case 't': *p++ = '\t'; break; + case 'O': case 'E': ++format; goto again; + case 'c': src = "%b %a %d %k:%M:%S %Z %Y"; goto _strf; + case 'r': src = "%I:%M:%S %p"; goto _strf; + case 'R': src = "%H:%M"; goto _strf; + case 'x': src = "%b %a %d"; goto _strf; + case 'X': src = "%k:%M:%S"; goto _strf; + case 'D': src = "%m/%d/%y"; goto _strf; + case 'T': src = "%H:%M:%S"; + _strf: p += strftime (p, (size_t)(dst+max-p), src, tm); break; + case 'a': src = sweekdays [tm->tm_wday]; goto _str; + case 'A': src = weekdays [tm->tm_wday]; goto _str; + case 'h': + case 'b': src = smonths [tm->tm_mon]; goto _str; + case 'B': src = months [tm->tm_mon]; goto _str; + case 'p': src = ampm [tm->tm_hour > 12 ? 3 : 2]; goto _str; + case 'P': src = ampm [tm->tm_hour > 12 ? 1 : 0]; goto _str; + case 'C': no = tm->tm_year/100 + 19; goto _no; + case 'd': no = tm->tm_mday; goto _no; + case 'e': no = tm->tm_mday; goto _nos; + case 'H': no = tm->tm_hour; goto _no; + case 'I': no = tm->tm_hour % 12; goto _no; + case 'j': no = tm->tm_yday; goto _no; + case 'k': no = tm->tm_hour; goto _nos; + case 'l': no = tm->tm_hour % 12; goto _nos; + case 'm': no = tm->tm_mon + 1; goto _no; + case 'M': no = tm->tm_min; goto _no; + case 'S': no = tm->tm_sec; goto _no; + case 'u': no = tm->tm_wday ? tm->tm_wday : 7; goto _no; + case 'w': no = tm->tm_wday; goto _no; + case 'U': no = (tm->tm_yday - tm->tm_wday + 7) / 7; goto _no; + case 'W': no = (tm->tm_yday - (tm->tm_wday - 1 + 7) % 7 + 7) / 7; goto _no; + case 's': { + time_t t = rb->mktime((struct tm*)tm); + char buf[101]; + char* c; + buf[100]=0; + for (c=buf+99; c>buf; --c) { + *c=(t%10)+'0'; + t/=10; + if (!t) break; + } + src=c; + goto _str; + } + case 'Z': +#ifdef WANT_TZFILE_PARSER + tzset(); src = tzname[0]; +#else + src = "[unknown timezone]"; +#endif + goto _str; + case 'Y': i2a ( buf+0, (unsigned int)(tm->tm_year / 100 + 19) ); + i2a ( buf+2, (unsigned int)(tm->tm_year % 100) ); + src = buf; + goto _str; + case 'y': no = tm->tm_year % 100; goto _no; + _no: i2a ( buf, no ); /* append number 'no' */ + src = buf; + goto _str; + _nos: i2a ( buf, no ); /* the same, but '0'->' ' */ + if (buf[0] == '0') + buf[0] = ' '; + src = buf; + _str: while (*src && p < dst+max) /* append string */ + *p++ = *src++; + break; + }; + } else { + *p++ = *format; + } + + if (p >= dst+max) + break; + } + + *p = '\0'; + return p - dst; +} + + -- cgit v1.2.3