Merge pull request #462 from jplitza/jsonc-sink
authorJo-Philipp Wich <jow@openwrt.org>
Thu, 17 Dec 2015 01:36:45 +0000 (02:36 +0100)
committerJo-Philipp Wich <jow@openwrt.org>
Thu, 17 Dec 2015 01:36:45 +0000 (02:36 +0100)
luci-lib-jsonc: Add ltn12-compatible sink factory

documentation/api/modules/luci.jsonc.parser.html
libs/luci-lib-jsonc/src/jsonc.c
libs/luci-lib-jsonc/src/jsonc.luadoc

index 4c19cf0..e8e145f 100644 (file)
@@ -234,6 +234,13 @@ Put Lua data into the parser.</td>
        </tr>
 
        <tr>
+       <td class="name" nowrap><a href="#parser.sink">parser:sink</a>&nbsp;()</td>
+       <td class="summary">
+Generate an ltn12-compatible sink.</td>
+       </tr>
+
+       <tr>
        <td class="name" nowrap><a href="#parser.stringify">parser:stringify</a>&nbsp;(pretty)</td>
        <td class="summary">
  
@@ -406,6 +413,34 @@ Nothing is returned.
 
 
 
+<dt><a name="parser.sink"></a><strong>parser:sink</strong>&nbsp;()</dt>
+<dd>
+
+Generate an ltn12-compatible sink. 
+
+
+
+
+
+
+<h3>Usage:</h3>
+<pre>parser = luci.jsonc.new() 
+ltn12.pump.all(ltn12.source.file(io.input()), parser:sink()) 
+print(parser:get())</pre>
+
+
+
+<h3>Return value:</h3>
+Returns a function that can be used as an ltn12 sink.
+
+
+
+</dd>
+
+
+
+
 <dt><a name="parser.stringify"></a><strong>parser:stringify</strong>&nbsp;(pretty)</dt>
 <dd>
 
index b857c97..ef11101 100644 (file)
@@ -328,6 +328,76 @@ static int json_parse_set(lua_State *L)
        return 0;
 }
 
+static int json_parse_sink_closure(lua_State *L)
+{
+       bool finished = lua_toboolean(L, lua_upvalueindex(2));
+       if (lua_isnil(L, 1))
+       {
+               // no more data available
+               if (finished)
+               {
+                       // we were finished parsing
+                       lua_pushboolean(L, true);
+                       return 1;
+               }
+               else
+               {
+                       lua_pushnil(L);
+                       lua_pushstring(L, "Incomplete JSON data");
+                       return 2;
+               }
+       }
+       else
+       {
+               if (finished)
+               {
+                       lua_pushnil(L);
+                       lua_pushstring(L, "Unexpected data after complete JSON object");
+                       return 2;
+               }
+               else
+               {
+                       // luci.jsonc.parser.chunk()
+                       lua_pushcfunction(L, json_parse_chunk);
+                       // parser object from closure
+                       lua_pushvalue(L, lua_upvalueindex(1));
+                       // chunk
+                       lua_pushvalue(L, 1);
+                       lua_call(L, 2, 2);
+
+                       if (lua_isnil(L, -2))
+                       {
+                               // an error occurred, leave (nil, errmsg) on the stack and return it
+                               return 2;
+                       }
+                       else if (lua_toboolean(L, -2))
+                       {
+                               // finished reading, set finished=true and return nil to prevent further input
+                               lua_pop(L, 2);
+                               lua_pushboolean(L, true);
+                               lua_replace(L, lua_upvalueindex(2));
+                               lua_pushnil(L);
+                               return 1;
+                       }
+                       else
+                       {
+                               // not finished reading, return true
+                               lua_pop(L, 2);
+                               lua_pushboolean(L, true);
+                               return 1;
+                       }
+               }
+       }
+}
+
+static int json_parse_sink(lua_State *L)
+{
+       luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
+       lua_pushboolean(L, false);
+       lua_pushcclosure(L, json_parse_sink_closure, 2);
+       return 1;
+}
+
 static int json_tostring(lua_State *L)
 {
        struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
@@ -367,6 +437,7 @@ static const luaL_reg jsonc_parser_methods[] = {
        { "parse",                      json_parse_chunk  },
        { "get",                        json_parse_get    },
        { "set",                        json_parse_set    },
+       { "sink",                       json_parse_sink   },
        { "stringify",          json_tostring     },
 
        { "__gc",                       json_gc           },
index 2ee9ceb..720b17d 100644 (file)
@@ -121,10 +121,22 @@ parser:set({ "some", "data" })`
 ]]
 
 ---[[
-Serialize current parser state as JSON.
+Generate an ltn12-compatible sink.
 
 @class function
 @sort 4
+@name parser.sink
+@return Returns a function that can be used as an ltn12 sink.
+@usage `parser = luci.jsonc.new()
+ltn12.pump.all(ltn12.source.file(io.input()), parser:sink())
+print(parser:get())`
+]]
+
+---[[
+Serialize current parser state as JSON.
+
+@class function
+@sort 5
 @name parser.stringify
 @param pretty A boolean value indicating whether the resulting JSON should be pretty printed.
 @return Returns the serialized JSON data of this parser instance.