From 7cac7ddf2fbf1f49865b88cadcfd3704429df101 Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Tue, 2 May 2017 12:11:32 +0200 Subject: os.date --- README.md | 13 +------- package.json | 5 +-- src/loslib.js | 96 +++++++++++++++++++++++++++++++++++++++++++++++++-------- tests/loslib.js | 42 ++++++++++++++++++++++++- 4 files changed, 128 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index fd9b4ee..dcfafd4 100644 --- a/README.md +++ b/README.md @@ -22,19 +22,8 @@ - [x] String - [x] Table - [x] utf8 + - [x] os (~~`os.setlocale()`~~) - [ ] Package - - [ ] os - - [x] `os.clock()` - - [x] `os.difftime()` - - [x] `os.execute()` - - [x] `os.exit()` - - [x] `os.getenv()` - - [x] `os.remove()` - - [x] `os.rename()` - - [x] `os.time()` - - [x] `os.tmpname()` - - [ ] `os.date()` - - [ ] ~~`os.setlocale()`~~ - [ ] io - [ ] `io.stdin` - [ ] `io.stdout` diff --git a/package.json b/package.json index cdfd16d..73dc6fd 100644 --- a/package.json +++ b/package.json @@ -33,9 +33,10 @@ "tmp": "0.0.31" }, "dependencies": { - "tmp": "0.0.31", "readline-sync": "^1.4.7", "seedrandom": "^2.4.2", - "sprintf-js": "giann/sprintf.js" + "sprintf-js": "giann/sprintf.js", + "strftime": "^0.10.0", + "tmp": "0.0.31" } } diff --git a/src/loslib.js b/src/loslib.js index 98686c4..6fd5247 100644 --- a/src/loslib.js +++ b/src/loslib.js @@ -1,22 +1,37 @@ "use strict"; -const lua = require('./lua.js'); -const lauxlib = require('./lauxlib.js'); -const llimit = require('./llimit.js'); +const lua = require('./lua.js'); +const lauxlib = require('./lauxlib.js'); +const llimit = require('./llimit.js'); + +const strftime = require('strftime'); + +/* options for ANSI C 89 (only 1-char options) */ +const L_STRFTIMEC89 = lua.to_luastring("aAbBcdHIjmMpSUwWxXyYZ%", true); + +/* options for ISO C 99 and POSIX */ +const L_STRFTIMEC99 = lua.to_luastring("aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%||EcECExEXEyEYOdOeOHOIOmOMOSOuOUOVOwOWOy", true); /* two-char options */ + +/* options for Windows */ +const L_STRFTIMEWIN = lua.to_luastring("aAbBcdHIjmMpSUwWxXyYzZ%||#c#x#d#H#I#j#m#M#S#U#w#W#y#Y", true); /* two-char options */ + +// const LUA_STRFTIMEOPTIONS = L_STRFTIMEWIN; +const LUA_STRFTIMEOPTIONS = L_STRFTIMEC89; +// const LUA_STRFTIMEOPTIONS = L_STRFTIMEC99; const setfield = function(L, key, value) { lua.lua_pushinteger(L, value); lua.lua_setfield(L, -2, lua.to_luastring(key, true)); }; -const setallfields = function(L, time) { - setfield(L, "sec", time.getSeconds()); - setfield(L, "min", time.getMinutes()); - setfield(L, "hour", time.getHours()); - setfield(L, "day", time.getDate()); - setfield(L, "month", time.getMonth()); - setfield(L, "year", time.getFullYear()); - setfield(L, "wday", time.getDay()); +const setallfields = function(L, time, utc) { + setfield(L, "sec", !utc ? time.getSeconds() : time.getUTCSeconds()); + setfield(L, "min", !utc ? time.getMinutes() : time.getUTCMinutes()); + setfield(L, "hour", !utc ? time.getHours() : time.getUTCHours()); + setfield(L, "day", !utc ? time.getDate() : time.getUTCDate()); + setfield(L, "month", !utc ? time.getMonth() : time.getUTCMonth()); + setfield(L, "year", !utc ? time.getFullYear() : time.getUTCFullYear()); + setfield(L, "wday", !utc ? time.getDay() : time.getUTCDay()); let now = new Date(); setfield(L, "yday", Math.floor((now - (new Date(now.getFullYear(), 0, 0))) / (1000 * 60 * 60 * 24))); // setboolfield(L, "isdst", time.get); @@ -43,6 +58,60 @@ const getfield = function(L, key, d, delta) { return res; }; +const checkoption = function(L, conv, buff) { + let option = LUA_STRFTIMEOPTIONS; + let oplen = 1; /* length of options being checked */ + for (; option.length > 0 && oplen <= conv.length; option = option.slice(oplen)) { + if (option[0] === '|'.charCodeAt(0)) /* next block? */ + oplen++; /* will check options with next length (+1) */ + else if (lua.to_jsstring(conv.slice(0, oplen)) === lua.to_jsstring(option.slice(0, oplen))) { /* match? */ + buff.push(...conv.slice(0, oplen)); /* copy valid option to buffer */ + return conv.slice(oplen); /* return next item */ + } + } + lauxlib.luaL_argerror(L, 1, lua.lua_pushliteral(L, `invalid conversion specifier '%${conv}'`, conv)); +}; + +/* maximum size for an individual 'strftime' item */ +const SIZETIMEFMT = 250; + + +const os_date = function(L) { + let s = lauxlib.luaL_optlstring(L, 1, "%c"); + let t = lauxlib.luaL_opt(L, l_checktime, 2, new Date().getTime() / 1000) * 1000; + let stm = new Date(t); + let utc = false; + if (s[0] === '!'.charCodeAt(0)) { /* UTC? */ + utc = true; + s = s.slice(1); /* skip '!' */ + } + + if (stm === null) /* invalid date? */ + lauxlib.luaL_error(L, lua.to_luastring("time result cannot be represented in this installation", true)); + + if (lua.to_jsstring(s) === "*t") { + lua.lua_createtable(L, 0, 9); /* 9 = number of fields */ + setallfields(L, stm, utc); + } else { + let cc; /* buffer for individual conversion specifiers */ + let b = []; + while (s.length > 0) { + cc = ['%'.charCodeAt(0)]; + + if (s[0] !== '%'.charCodeAt(0)) { /* not a conversion specifier? */ + b.push(s[0]); + s = s.slice(1); + } else { + s = s.slice(1); /* skip '%' */ + s = checkoption(L, s, cc); /* copy specifier to 'cc' */ + b.push(...(lua.to_luastring(strftime(lua.to_jsstring(cc), stm)))); + } + } + lua.lua_pushstring(L, b); + } + return 1; +}; + const os_time = function(L) { let t = new Date(); if (!lua.lua_isnoneornil(L, 1)) /* called with arg */{ @@ -75,8 +144,9 @@ const os_difftime = function(L) { }; const syslib = { - "time": os_time, - "difftime": os_difftime + "date": os_date, + "difftime": os_difftime, + "time": os_time }; // Only with Node diff --git a/tests/loslib.js b/tests/loslib.js index 8555bc4..a80ccad 100644 --- a/tests/loslib.js +++ b/tests/loslib.js @@ -38,7 +38,11 @@ test('os.time', function (t) { test('os.time (with format)', function (t) { let luaCode = ` - return os.time({day=8,month=2,year=2015}) + return os.time({ + day = 8, + month = 2, + year = 2015 + }) `, L; t.plan(3); @@ -101,6 +105,42 @@ test('os.difftime', function (t) { }); +test('os.date', function (t) { + let luaCode = ` + return os.date('%Y-%m-%d', os.time({ + day = 8, + month = 2, + year = 2015 + })) + `, L; + + t.plan(3); + + t.doesNotThrow(function () { + + L = lauxlib.luaL_newstate(); + + lauxlib.luaL_openlibs(L); + + lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); + + }, "Lua program loaded without error"); + + t.doesNotThrow(function () { + + lua.lua_call(L, 0, -1); + + }, "Lua program ran without error"); + + t.strictEqual( + lua.lua_tojsstring(L, -1), + "2015-02-08", + "Correct element(s) on the stack" + ); + +}); + + test('os.getenv', function (t) { let luaCode = ` return os.getenv('HOME') -- cgit v1.2.3-70-g09d2