From 91924d0b77999c9f1fd700ec60fc31c38f7d27b4 Mon Sep 17 00:00:00 2001
From: Benoit Giannangeli <benoit.giannangeli@boursorama.fr>
Date: Thu, 16 Mar 2017 15:37:09 +0100
Subject: string.sub

---
 README.md        |   2 +-
 src/lauxlib.js   |   2 +-
 src/lobject.js   |   4 ++-
 src/lstrlib.js   |  14 ++++++++
 tests/lstrlib.js | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 121 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 84195cf..e8257cc 100644
--- a/README.md
+++ b/README.md
@@ -104,6 +104,7 @@
         - [x] string.lower
         - [x] string.rep
         - [x] string.reverse
+        - [x] string.sub
         - [x] string.upper
         - [ ] string.dump
         - [ ] string.find
@@ -112,7 +113,6 @@
         - [ ] string.match
         - [ ] string.pack
         - [ ] string.packsize
-        - [ ] string.sub
         - [ ] string.unpack
     - [ ] Package
     - [ ] os
diff --git a/src/lauxlib.js b/src/lauxlib.js
index f77fe5e..3ee04a4 100644
--- a/src/lauxlib.js
+++ b/src/lauxlib.js
@@ -54,7 +54,7 @@ const findfield = function(L, objidx, level) {
 const pushglobalfuncname = function(L, ar) {
     let top = lapi.lua_gettop(L);
     ldebug.lua_getinfo(L, 'f', ar);  /* push function */
-    lapi.lua_getfield(L, lua.LUA_REGISTRYINDEX, lua.LUA_LOADED_TABLE);
+    lapi.lua_getfield(L, lua.LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
     if (findfield(L, top + 1, 2)) {
         let name = lapi.lua_tostring(L, -1);
         if (name.startsWith("_G.")) {
diff --git a/src/lobject.js b/src/lobject.js
index 719d7a6..e1c3e97 100644
--- a/src/lobject.js
+++ b/src/lobject.js
@@ -452,8 +452,10 @@ module.exports.LocVar         = LocVar;
 module.exports.TValue         = TValue;
 module.exports.Table          = Table;
 module.exports.UTF8BUFFSZ     = UTF8BUFFSZ;
+module.exports.intarith       = intarith;
 module.exports.luaO_chunkid   = luaO_chunkid;
 module.exports.luaO_hexavalue = luaO_hexavalue;
 module.exports.luaO_int2fb    = luaO_int2fb;
 module.exports.luaO_str2num   = luaO_str2num;
-module.exports.luaO_utf8desc  = luaO_utf8desc;
\ No newline at end of file
+module.exports.luaO_utf8desc  = luaO_utf8desc;
+module.exports.numarith       = numarith;
\ No newline at end of file
diff --git a/src/lstrlib.js b/src/lstrlib.js
index b3d5aea..1d3a7cc 100644
--- a/src/lstrlib.js
+++ b/src/lstrlib.js
@@ -18,6 +18,19 @@ const posrelat = function(pos, len) {
     else return len + pos + 1;
 };
 
+const str_sub = function(L) {
+    let s = lauxlib.luaL_checkstring(L, 1);
+    let l = s.length;
+    let start = posrelat(lauxlib.luaL_checkinteger(L, 2), l);
+    let end = posrelat(lauxlib.luaL_optinteger(L, 3, -1), l);
+    if (start < 1) start = 1;
+    if (end > l) end = l;
+    if (start <= end)
+        lapi.lua_pushstring(L, s.slice(start - 1, (start - 1) + (end - start + 1)));
+    else lapi.lua_pushliteral(L, "");
+    return 1;
+};
+
 const str_len = function(L) {
     lapi.lua_pushinteger(L, lauxlib.luaL_checkstring(L, 1).length);
     return 1;
@@ -371,6 +384,7 @@ const strlib = {
     "lower":   str_lower,
     "rep":     str_rep,
     "reverse": str_reverse,
+    "sub":     str_sub,
     "upper":   str_upper
 };
 
diff --git a/tests/lstrlib.js b/tests/lstrlib.js
index 0475a42..4df4283 100644
--- a/tests/lstrlib.js
+++ b/tests/lstrlib.js
@@ -284,6 +284,7 @@ test('string.format', function (t) {
     );
 });
 
+
 test('string.format', function (t) {
     let luaCode = `
         return string.format("%q", 'a string with "quotes" and \\n new line')
@@ -312,4 +313,105 @@ test('string.format', function (t) {
         '"a string with \\"quotes\\" and \\\n new line"',
         "Correct element(s) on the stack"
     );
+});
+
+
+test('string.sub', function (t) {
+    let luaCode = `
+        return string.sub("123456789",2,4),  -- "234"
+            string.sub("123456789",7),       -- "789"
+            string.sub("123456789",7,6),     --  ""
+            string.sub("123456789",7,7),     -- "7"
+            string.sub("123456789",0,0),     --  ""
+            string.sub("123456789",-10,10),  -- "123456789"
+            string.sub("123456789",1,9),     -- "123456789"
+            string.sub("123456789",-10,-20), --  ""
+            string.sub("123456789",-1),      -- "9"
+            string.sub("123456789",-4),      -- "6789"
+            string.sub("123456789",-6, -4)   -- "456"
+    `, L;
+    
+    t.plan(13);
+
+    t.doesNotThrow(function () {
+
+        L = lauxlib.luaL_newstate();
+
+        linit.luaL_openlibs(L);
+
+        lauxlib.luaL_loadstring(L, luaCode);
+
+    }, "Lua program loaded without error");
+
+    t.doesNotThrow(function () {
+
+        lapi.lua_call(L, 0, -1);
+
+    }, "Lua program ran without error");
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -11),
+        "234",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -10),
+        "789",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -9),
+         "",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -8),
+        "7",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -7),
+         "",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -6),
+        "123456789",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -5),
+        "123456789",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -4),
+         "",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -3),
+        "9",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -2),
+        "6789",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -1),
+        "456",
+        "Correct element(s) on the stack"
+    );
 });
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2