From 15a80aaffdba9ed8bd6f97cacf6120de838946eb Mon Sep 17 00:00:00 2001
From: Jan-Philipp Litza <janphilipp@litza.de>
Date: Sun, 30 Aug 2015 20:53:44 +0200
Subject: [PATCH] Switch from luci-lib-json to luci-lib-jsonc

Apart from replacing a patch for the former by two patches for latter,
this involved minimal adaptations of the lua scripts in the following
packages:

* gluon-announce
* gluon-announced
* gluon-mesh-batman-adv-core
* gluon-status-page
---
 package/gluon-announce/Makefile               |  2 +-
 .../files/lib/gluon/announce/collect.lua      |  5 +--
 .../files/usr/lib/lua/gluon/announce.lua      |  3 +-
 .../files/usr/lib/lua/gluon/announced.lua     |  6 +--
 .../lib/gluon/announce/neighbours.d/batadv    |  2 +-
 .../nodeinfo.d/network/mesh/bat0/interfaces   |  2 +-
 .../lib/gluon/announce/statistics.d/mesh_vpn  |  8 ++--
 package/gluon-status-page/Makefile            |  2 +-
 .../www/cgi-bin/dyn/neighbours-batadv         |  4 +-
 .../status-page/www/cgi-bin/dyn/stations      |  4 +-
 .../status-page/www/cgi-bin/dyn/statistics    |  4 +-
 .../gluon/status-page/www/cgi-bin/interfaces  |  4 +-
 .../gluon/status-page/www/cgi-bin/nodeinfo    |  4 +-
 .../lib/gluon/status-page/www/cgi-bin/status  |  8 ++--
 ...keys-to-allow-encoding-empty-objects.patch | 36 ------------------
 ...-non-string-or-number-keys-in-tables.patch | 32 ++++++++++++++++
 ...lib-jsonc-allow-encoding-empty-lists.patch | 38 +++++++++++++++++++
 17 files changed, 98 insertions(+), 66 deletions(-)
 delete mode 100644 patches/packages/luci/0004-luci-lib-json-ignore-null-keys-to-allow-encoding-empty-objects.patch
 create mode 100644 patches/packages/luci/0004-luci-lib-jsonc-Ignore-non-string-or-number-keys-in-tables.patch
 create mode 100644 patches/packages/luci/0005-luci-lib-jsonc-allow-encoding-empty-lists.patch

diff --git a/package/gluon-announce/Makefile b/package/gluon-announce/Makefile
index 3f62c8895..d2742cf7f 100644
--- a/package/gluon-announce/Makefile
+++ b/package/gluon-announce/Makefile
@@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/package.mk
 define Package/gluon-announce
   SECTION:=gluon
   CATEGORY:=Gluon
-  DEPENDS:=+gluon-core +luci-lib-json +lua-ethtool-stats
+  DEPENDS:=+gluon-core +luci-lib-jsonc +lua-ethtool-stats
   TITLE:=Lua scripts announcing various information
 endef
 
diff --git a/package/gluon-announce/files/lib/gluon/announce/collect.lua b/package/gluon-announce/files/lib/gluon/announce/collect.lua
index e2974b498..433920752 100755
--- a/package/gluon-announce/files/lib/gluon/announce/collect.lua
+++ b/package/gluon-announce/files/lib/gluon/announce/collect.lua
@@ -1,10 +1,9 @@
 #!/usr/bin/lua
 
 local announce = require 'gluon.announce'
-local json = require 'luci.json'
+local json = require 'luci.jsonc'
 local ltn12 = require 'luci.ltn12'
 
 local announce_dir = '/lib/gluon/announce/' .. arg[1] .. '.d'
 
-encoder = json.Encoder(announce.collect_dir(announce_dir))
-ltn12.pump.all(encoder:source(), ltn12.sink.file(io.stdout))
+print(json.stringify(announce.collect_dir(announce_dir)))
diff --git a/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua b/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua
index be855b3aa..fdd2479e0 100644
--- a/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua
+++ b/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua
@@ -3,7 +3,6 @@
 module('gluon.announce', package.seeall)
 
 fs = require 'nixio.fs'
-json = require 'luci.json'
 uci = require('luci.model.uci').cursor()
 util = require 'luci.util'
 
@@ -16,7 +15,7 @@ local function collect_entry(entry)
 end
 
 function collect_dir(dir)
-	local ret = { [json.null] = true }
+	local ret = { [{}] = true }
 
 	for entry in fs.dir(dir) do
 		if entry:sub(1, 1) ~= '.' then
diff --git a/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua b/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua
index 99116b81a..a9de80e63 100644
--- a/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua
+++ b/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua
@@ -1,6 +1,6 @@
 local announce = require 'gluon.announce'
 local deflate = require 'deflate'
-local json = require 'luci.json'
+local json = require 'luci.jsonc'
 
 
 local function collect(type)
@@ -12,7 +12,7 @@ module('gluon.announced', package.seeall)
 
 function handle_request(query)
   if query:match('^nodeinfo$') then
-    return json.encode(collect('nodeinfo'))
+    return json.stringify(collect('nodeinfo'))
   end
 
   local m = query:match('^GET ([a-z ]+)$')
@@ -27,7 +27,7 @@ function handle_request(query)
     end
 
     if next(data) then
-      return deflate.compress(json.encode(data))
+      return deflate.compress(json.stringify(data))
     end
   end
 end
diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv
index cfdd72dc6..e83f188f4 100644
--- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv
+++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv
@@ -22,7 +22,7 @@ function batadv()
     if mac1 ~= nil and mac1 == mac2 then
       ifaddress = ifname2address(ifname)
       if interfaces[ifaddress] == nil then
-        interfaces[ifaddress] = { neighbours = { [json.null] = true } }
+        interfaces[ifaddress] = { neighbours = { [{}] = true } }
       end
 
       interfaces[ifaddress].neighbours[mac1] = { tq = tonumber(tq)
diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces
index e0c3c9acd..1ac22d30c 100644
--- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces
+++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces
@@ -49,5 +49,5 @@ return {
   wireless = nil_table(wireless),
   tunnel = nil_table(tunnel),
   other = nil_table(other),
-  [json.null] = true
+  [{}] = true
 }
diff --git a/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn b/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn
index a67b9a07b..0d6d66f0b 100644
--- a/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn
+++ b/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn
@@ -1,4 +1,4 @@
-local json = require 'luci.json'
+local json = require 'luci.jsonc'
 local ltn12 = require 'luci.ltn12'
 local nixio = require 'nixio'
 local site = require 'gluon.site_config'
@@ -11,8 +11,8 @@ if not fastd_sock:connect(socket_path) then
   return nil
 end
 
-local decoder = json.Decoder()
-ltn12.pump.all(ltn12.source.file(fastd_sock), decoder:sink())
+local decoder = json.new()
+ltn12.pump.all(ltn12.source.file(fastd_sock), function(chunk) decoder:parse(chunk) end)
 
 local status = decoder:get()
 
@@ -27,7 +27,7 @@ local function peer_connection(config)
         established = peer.connection.established/1000
       }
     else
-      return json.null
+      return function()end -- nil
     end
   end
 end
diff --git a/package/gluon-status-page/Makefile b/package/gluon-status-page/Makefile
index 3d9edbfe1..2543ea2ad 100644
--- a/package/gluon-status-page/Makefile
+++ b/package/gluon-status-page/Makefile
@@ -12,7 +12,7 @@ define Package/gluon-status-page
   SECTION:=gluon
   CATEGORY:=Gluon
   TITLE:=Adds a status page showing information about the node.
-  DEPENDS:=+gluon-core +uhttpd +gluon-neighbour-info +gluon-announce +libiwinfo-lua
+  DEPENDS:=+gluon-core +uhttpd +gluon-neighbour-info +gluon-announce +libiwinfo-lua +luci-lib-jsonc
 endef
 
 define Package/gluon-status-page/description
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-batadv b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-batadv
index addecd605..3bcdf89bd 100755
--- a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-batadv
+++ b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-batadv
@@ -1,6 +1,6 @@
 #!/usr/bin/lua
 
-local json = require 'luci.json'
+local json = require 'luci.jsonc'
 local nixio = require 'nixio'
 
 function neighbours()
@@ -25,7 +25,7 @@ io.write("Access-Control-Allow-Origin: *\n")
 io.write("Content-type: text/event-stream\n\n")
 
 while true do
-  local neighbours = json.encode(neighbours())
+  local neighbours = json.stringify(neighbours())
   io.write("data: " .. neighbours .. "\n\n")
   io.flush()
   nixio.nanosleep(1, 0)
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/stations b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/stations
index 4745c3422..637de6499 100755
--- a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/stations
+++ b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/stations
@@ -1,7 +1,7 @@
 #!/usr/bin/lua
 
 util = require 'luci.util'
-json = require 'luci.json'
+json = require 'luci.jsonc'
 nixio = require 'nixio'
 iwinfo = require 'iwinfo'
 
@@ -45,7 +45,7 @@ io.write("Access-Control-Allow-Origin: *\n")
 io.write("Content-type: text/event-stream\n\n")
 
 while true do
-  local stations = json.encode(get_stations(iw, ifname))
+  local stations = json.stringify(get_stations(iw, ifname))
   io.write("data: " .. stations .. "\n\n")
   io.flush()
   nixio.nanosleep(0, 150e6)
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/statistics b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/statistics
index 7805afe83..194564b98 100755
--- a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/statistics
+++ b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/statistics
@@ -1,7 +1,7 @@
 #!/usr/bin/lua
 
 local announce = require 'gluon.announce'
-local json = require 'luci.json'
+local json = require 'luci.jsonc'
 local util = require 'luci.util'
 local nixio = require 'nixio'
 
@@ -11,7 +11,7 @@ io.write("Access-Control-Allow-Origin: *\n")
 io.write("Content-type: text/event-stream\n\n")
 
 while true do
-  local data = json.encode(announce.collect_dir(announce_dir))
+  local data = json.stringify(announce.collect_dir(announce_dir))
   io.write("data: " .. data .. "\n\n")
   io.flush()
   nixio.nanosleep(1, 0)
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/interfaces b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/interfaces
index 2615ed823..4eabf8158 100755
--- a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/interfaces
+++ b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/interfaces
@@ -1,7 +1,7 @@
 #!/usr/bin/lua
 
 util = require 'luci.util'
-json = require 'luci.json'
+json = require 'luci.jsonc'
 fs = require 'nixio.fs'
 
 io.write("Access-Control-Allow-Origin: *\n")
@@ -21,4 +21,4 @@ for _, line in ipairs(util.split(list)) do
   end
 end
 
-io.write(json.encode(interfaces))
+io.write(json.stringify(interfaces))
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/nodeinfo b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/nodeinfo
index a2ef61c7a..787892444 100755
--- a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/nodeinfo
+++ b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/nodeinfo
@@ -1,7 +1,7 @@
 #!/usr/bin/lua
 
 local announce = require 'gluon.announce'
-local json = require 'luci.json'
+local json = require 'luci.jsonc'
 local util = require 'luci.util'
 local nixio = require 'nixio'
 
@@ -10,6 +10,6 @@ local announce_dir = '/lib/gluon/announce/nodeinfo.d/'
 io.write("Access-Control-Allow-Origin: *\n")
 io.write("Content-type: application/json\n\n")
 
-local data = json.encode(announce.collect_dir(announce_dir))
+local data = json.stringify(announce.collect_dir(announce_dir))
 io.write(data)
 io.flush()
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/status b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/status
index f0c8cbd85..fe4ba0af7 100755
--- a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/status
+++ b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/status
@@ -4,7 +4,7 @@ local util = require("luci.util")
 local fs = require("nixio.fs")
 local ltn12 = require 'luci.ltn12'
 local sys = require("luci.sys")
-local json = require("luci.json")
+local json = require("luci.jsonc")
 local nixio = require 'nixio'
 local platform_info = require("platform_info")
 
@@ -20,7 +20,7 @@ function neighbours(ifname)
   local info = util.exec("gluon-neighbour-info -d ff02::2:1001 -p 1001 -r nodeinfo -t 3 -i " .. ifname)
   local macs = {}
   for _, line in ipairs(util.split(info)) do
-    local data = json.decode(line)
+    local data = json.parse(line)
     if data then
       local function add_macs(list)
         if list then
@@ -93,8 +93,8 @@ local stat, fastd_status = pcall(
     local fastd_sock = nixio.socket('unix', 'stream')
     assert(fastd_sock:connect('/var/run/fastd.mesh_vpn.socket'))
 
-    decoder = json.Decoder()
-    ltn12.pump.all(ltn12.source.file(fastd_sock), decoder:sink())
+    decoder = json.new()
+    ltn12.pump.all(ltn12.source.file(fastd_sock), function(chunk) decoder:parse(chunk) end)
     return decoder:get()
   end
 )
diff --git a/patches/packages/luci/0004-luci-lib-json-ignore-null-keys-to-allow-encoding-empty-objects.patch b/patches/packages/luci/0004-luci-lib-json-ignore-null-keys-to-allow-encoding-empty-objects.patch
deleted file mode 100644
index ab02429c8..000000000
--- a/patches/packages/luci/0004-luci-lib-json-ignore-null-keys-to-allow-encoding-empty-objects.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From: Matthias Schiffer <mschiffer@universe-factory.net>
-Date: Thu, 4 Jun 2015 21:03:24 +0200
-Subject: luci-lib-json: ignore null keys to allow encoding empty objects
-
-There is currently no way to encode an empty object {}, as empty tables are
-encoded as empty lists [].
-
-With this patch, encode() will ignore table fields with the key json.null (which
-doesn't make sense anyways). This allows adding a field with key json.null to
-force encoding it as an object.
-
-Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
-
-diff --git a/libs/luci-lib-json/luasrc/json.lua b/libs/luci-lib-json/luasrc/json.lua
-index 416b25f..f7b57f9 100644
---- a/libs/luci-lib-json/luasrc/json.lua
-+++ b/libs/luci-lib-json/luasrc/json.lua
-@@ -149,11 +149,13 @@ function Encoder.parse_iter(self, obj)
- 		local first = true
- 
- 		for key, entry in pairs(obj) do
--			first = first or self:put(",")
--			first = first and false
--			self:parse_string(tostring(key))
--			self:put(":")
--			self:dispatch(entry)
-+			if key ~= null then
-+				first = first or self:put(",")
-+				first = first and false
-+				self:parse_string(tostring(key))
-+				self:put(":")
-+				self:dispatch(entry)
-+			end
- 		end
- 
- 		self:put("}")
diff --git a/patches/packages/luci/0004-luci-lib-jsonc-Ignore-non-string-or-number-keys-in-tables.patch b/patches/packages/luci/0004-luci-lib-jsonc-Ignore-non-string-or-number-keys-in-tables.patch
new file mode 100644
index 000000000..584a2fab8
--- /dev/null
+++ b/patches/packages/luci/0004-luci-lib-jsonc-Ignore-non-string-or-number-keys-in-tables.patch
@@ -0,0 +1,32 @@
+From: Jan-Philipp Litza <janphilipp@litza.de>
+Date: Sun, 30 Aug 2015 15:42:52 +0200
+Subject: luci-lib-jsonc: Ignore non-string-or-number keys in tables
+
+Previously, the following caused a segmentation fault:
+
+    json.stringify({[{}] = true})
+
+This was caused by lua_tostring() returning NULL for anything but
+strings and numbers, letting json_object_object_add crash.
+
+This patch makes jsonc ignore all keys which have no string
+representation altogether.
+
+Signed-off-by: Jan-Philipp Litza <janphilipp@litza.de>
+
+diff --git a/libs/luci-lib-jsonc/src/jsonc.c b/libs/luci-lib-jsonc/src/jsonc.c
+index 49cb21f..827fde8 100644
+--- a/libs/luci-lib-jsonc/src/jsonc.c
++++ b/libs/luci-lib-jsonc/src/jsonc.c
+@@ -286,8 +286,9 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
+ 			lua_pushvalue(L, -2);
+ 			key = lua_tostring(L, -1);
+ 
+-			json_object_object_add(obj, key,
+-								   _lua_to_json(L, lua_gettop(L) - 1));
++			if (key)
++				json_object_object_add(obj, key,
++				                       _lua_to_json(L, lua_gettop(L) - 1));
+ 
+ 			lua_pop(L, 2);
+ 		}
diff --git a/patches/packages/luci/0005-luci-lib-jsonc-allow-encoding-empty-lists.patch b/patches/packages/luci/0005-luci-lib-jsonc-allow-encoding-empty-lists.patch
new file mode 100644
index 000000000..8d6b6842e
--- /dev/null
+++ b/patches/packages/luci/0005-luci-lib-jsonc-allow-encoding-empty-lists.patch
@@ -0,0 +1,38 @@
+From: Jan-Philipp Litza <janphilipp@litza.de>
+Date: Sun, 30 Aug 2015 15:45:49 +0200
+Subject: luci-lib-jsonc: allow encoding empty lists
+
+To be consistent with the behavior of luci-lib-json, an empty Lua table
+should be encoded to an empty JSON list, not an empty JSON object.
+
+To still allow encoding empty JSON objects, the usage of anything other
+than a number or a string as a key (for example an empty table or a
+function) can be used to force encoding as an object:
+
+    json.stringify({})                  -- "[]"
+    json.stringify({[{}] = true})       -- "{}"
+
+Signed-off-by: Jan-Philipp Litza <janphilipp@litza.de>
+
+diff --git a/libs/luci-lib-jsonc/src/jsonc.c b/libs/luci-lib-jsonc/src/jsonc.c
+index 827fde8..971fb12 100644
+--- a/libs/luci-lib-jsonc/src/jsonc.c
++++ b/libs/luci-lib-jsonc/src/jsonc.c
+@@ -222,7 +222,7 @@ static int _lua_test_array(lua_State *L, int index)
+ 
+ out:
+ 		lua_pop(L, 2);
+-		return 0;
++		return -1;
+ 	}
+ 
+ 	/* check for holes */
+@@ -254,7 +254,7 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
+ 	case LUA_TTABLE:
+ 		max = _lua_test_array(L, index);
+ 
+-		if (max > 0)
++		if (max >= 0)
+ 		{
+ 			obj = json_object_new_array();
+ 
-- 
GitLab