summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md13
-rw-r--r--package.json5
-rw-r--r--src/loslib.js96
-rw-r--r--tests/loslib.js42
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')