luci-0.11: merge outstanding trunk changes
This commit is contained in:
parent
31d76dbb64
commit
839dcdc012
387 changed files with 8383 additions and 4520 deletions
2
Makefile
2
Makefile
|
@ -14,7 +14,7 @@ all: build
|
|||
build: gccbuild luabuild
|
||||
|
||||
gccbuild:
|
||||
make -C libs/lmo CC="cc" CFLAGS="" LDFLAGS="" SDK="$(shell test -f .running-sdk && echo 1)" host-install
|
||||
make -C libs/web CC="cc" CFLAGS="" LDFLAGS="" SDK="$(shell test -f .running-sdk && echo 1)" host-install
|
||||
for i in $(MODULES); do \
|
||||
make -C$$i SDK="$(shell test -f .running-sdk && echo 1)" compile || { \
|
||||
echo "*** Compilation of $$i failed!"; \
|
||||
|
|
|
@ -19,7 +19,7 @@ function index()
|
|||
return
|
||||
end
|
||||
|
||||
entry({"admin", "network", "ahcpd"}, cbi("ahcp"), _("AHCP Server"), 90).i18n = "ahcp"
|
||||
entry({"admin", "network", "ahcpd"}, cbi("ahcp"), _("AHCP Server"), 90)
|
||||
entry({"admin", "network", "ahcpd", "status"}, call("ahcp_status"))
|
||||
end
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ module("luci.controller.asterisk", package.seeall)
|
|||
|
||||
function index()
|
||||
|
||||
entry({"admin", "services", "asterisk"}, cbi("asterisk"), "Asterisk", 80).i18n = "asterisk"
|
||||
entry({"admin", "services", "asterisk"}, cbi("asterisk"), "Asterisk", 80)
|
||||
|
||||
entry({"admin", "services", "asterisk", "voice"}, cbi("asterisk-voice"), "Voice Functions", 1)
|
||||
entry({"admin", "services", "asterisk", "meetme"}, cbi("asterisk-meetme"), "Meetme Conferences", 2)
|
||||
|
|
4
applications/luci-commands/Makefile
Normal file
4
applications/luci-commands/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
PO = commands
|
||||
|
||||
include ../../build/config.mk
|
||||
include ../../build/module.mk
|
237
applications/luci-commands/luasrc/controller/commands.lua
Normal file
237
applications/luci-commands/luasrc/controller/commands.lua
Normal file
|
@ -0,0 +1,237 @@
|
|||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
|
||||
Copyright 2012 Jo-Philipp Wich <jow@openwrt.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
]]--
|
||||
|
||||
module("luci.controller.commands", package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "system", "commands"}, firstchild(), _("Custom Commands"), 80)
|
||||
entry({"admin", "system", "commands", "dashboard"}, template("commands"), _("Dashboard"), 1)
|
||||
entry({"admin", "system", "commands", "config"}, cbi("commands"), _("Configure"), 2)
|
||||
entry({"admin", "system", "commands", "run"}, call("action_run"), nil, 3).leaf = true
|
||||
entry({"admin", "system", "commands", "download"}, call("action_download"), nil, 3).leaf = true
|
||||
|
||||
entry({"command"}, call("action_public"), nil, 1).leaf = true
|
||||
end
|
||||
|
||||
--- Decode a given string into arguments following shell quoting rules
|
||||
--- [[abc \def "foo\"bar" abc'def']] -> [[abc def]] [[foo"bar]] [[abcdef]]
|
||||
local function parse_args(str)
|
||||
local args = { }
|
||||
|
||||
local function isspace(c)
|
||||
if c == 9 or c == 10 or c == 11 or c == 12 or c == 13 or c == 32 then
|
||||
return c
|
||||
end
|
||||
end
|
||||
|
||||
local function isquote(c)
|
||||
if c == 34 or c == 39 or c == 96 then
|
||||
return c
|
||||
end
|
||||
end
|
||||
|
||||
local function isescape(c)
|
||||
if c == 92 then
|
||||
return c
|
||||
end
|
||||
end
|
||||
|
||||
local function ismeta(c)
|
||||
if c == 36 or c == 92 or c == 96 then
|
||||
return c
|
||||
end
|
||||
end
|
||||
|
||||
--- Convert given table of byte values into a Lua string and append it to
|
||||
--- the "args" table. Segment byte value sequence into chunks of 256 values
|
||||
--- to not trip over the parameter limit for string.char()
|
||||
local function putstr(bytes)
|
||||
local chunks = { }
|
||||
local csz = 256
|
||||
local upk = unpack
|
||||
local chr = string.char
|
||||
local min = math.min
|
||||
local len = #bytes
|
||||
local off
|
||||
|
||||
for off = 1, len, csz do
|
||||
chunks[#chunks+1] = chr(upk(bytes, off, min(off + csz - 1, len)))
|
||||
end
|
||||
|
||||
args[#args+1] = table.concat(chunks)
|
||||
end
|
||||
|
||||
--- Scan substring defined by the indexes [s, e] of the string "str",
|
||||
--- perform unquoting and de-escaping on the fly and store the result in
|
||||
--- a table of byte values which is passed to putstr()
|
||||
local function unquote(s, e)
|
||||
local off, esc, quote
|
||||
local res = { }
|
||||
|
||||
for off = s, e do
|
||||
local byte = str:byte(off)
|
||||
local q = isquote(byte)
|
||||
local e = isescape(byte)
|
||||
local m = ismeta(byte)
|
||||
|
||||
if e then
|
||||
esc = true
|
||||
elseif esc then
|
||||
if m then res[#res+1] = 92 end
|
||||
res[#res+1] = byte
|
||||
esc = false
|
||||
elseif q and quote and q == quote then
|
||||
quote = nil
|
||||
elseif q and not quote then
|
||||
quote = q
|
||||
else
|
||||
if m then res[#res+1] = 92 end
|
||||
res[#res+1] = byte
|
||||
end
|
||||
end
|
||||
|
||||
putstr(res)
|
||||
end
|
||||
|
||||
--- Find substring boundaries in "str". Ignore escaped or quoted
|
||||
--- whitespace, pass found start- and end-index for each substring
|
||||
--- to unquote()
|
||||
local off, esc, start, quote
|
||||
for off = 1, #str + 1 do
|
||||
local byte = str:byte(off)
|
||||
local q = isquote(byte)
|
||||
local s = isspace(byte) or (off > #str)
|
||||
local e = isescape(byte)
|
||||
|
||||
if esc then
|
||||
esc = false
|
||||
elseif e then
|
||||
esc = true
|
||||
elseif q and quote and q == quote then
|
||||
quote = nil
|
||||
elseif q and not quote then
|
||||
start = start or off
|
||||
quote = q
|
||||
elseif s and not quote then
|
||||
if start then
|
||||
unquote(start, off - 1)
|
||||
start = nil
|
||||
end
|
||||
else
|
||||
start = start or off
|
||||
end
|
||||
end
|
||||
|
||||
--- If the "quote" is still set we encountered an unfinished string
|
||||
if quote then
|
||||
unquote(start, #str)
|
||||
end
|
||||
|
||||
return args
|
||||
end
|
||||
|
||||
local function parse_cmdline(cmdid, args)
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
if uci:get("luci", cmdid) == "command" then
|
||||
local cmd = uci:get_all("luci", cmdid)
|
||||
local argv = parse_args(cmd.command)
|
||||
local i, v
|
||||
|
||||
if cmd.param == "1" and args then
|
||||
for i, v in ipairs(parse_args(luci.http.urldecode(args))) do
|
||||
argv[#argv+1] = v
|
||||
end
|
||||
end
|
||||
|
||||
for i, v in ipairs(argv) do
|
||||
if v:match("[^%w%.%-i/]") then
|
||||
argv[i] = '"%s"' % v:gsub('"', '\\"')
|
||||
end
|
||||
end
|
||||
|
||||
return argv
|
||||
end
|
||||
end
|
||||
|
||||
function action_run(...)
|
||||
local fs = require "nixio.fs"
|
||||
local argv = parse_cmdline(...)
|
||||
if argv then
|
||||
local outfile = os.tmpname()
|
||||
local errfile = os.tmpname()
|
||||
|
||||
local rv = os.execute(table.concat(argv, " ") .. " >%s 2>%s" %{ outfile, errfile })
|
||||
local stdout = fs.readfile(outfile, 1024 * 512) or ""
|
||||
local stderr = fs.readfile(errfile, 1024 * 512) or ""
|
||||
|
||||
fs.unlink(outfile)
|
||||
fs.unlink(errfile)
|
||||
|
||||
local binary = not not (stdout:match("[%z\1-\8\14-\31]"))
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({
|
||||
command = table.concat(argv, " "),
|
||||
stdout = not binary and stdout,
|
||||
stderr = stderr,
|
||||
exitcode = rv,
|
||||
binary = binary
|
||||
})
|
||||
else
|
||||
luci.http.status(404, "No such command")
|
||||
end
|
||||
end
|
||||
|
||||
function action_download(...)
|
||||
local fs = require "nixio.fs"
|
||||
local argv = parse_cmdline(...)
|
||||
if argv then
|
||||
local fd = io.popen(table.concat(argv, " ") .. " 2>/dev/null")
|
||||
if fd then
|
||||
local chunk = fd:read(4096) or ""
|
||||
local name
|
||||
if chunk:match("[%z\1-\8\14-\31]") then
|
||||
luci.http.header("Content-Disposition", "attachment; filename=%s"
|
||||
% fs.basename(argv[1]):gsub("%W+", ".") .. ".bin")
|
||||
luci.http.prepare_content("application/octet-stream")
|
||||
else
|
||||
luci.http.header("Content-Disposition", "attachment; filename=%s"
|
||||
% fs.basename(argv[1]):gsub("%W+", ".") .. ".txt")
|
||||
luci.http.prepare_content("text/plain")
|
||||
end
|
||||
|
||||
while chunk do
|
||||
luci.http.write(chunk)
|
||||
chunk = fd:read(4096)
|
||||
end
|
||||
|
||||
fd:close()
|
||||
else
|
||||
luci.http.status(500, "Failed to execute command")
|
||||
end
|
||||
else
|
||||
luci.http.status(404, "No such command")
|
||||
end
|
||||
end
|
||||
|
||||
function action_public(cmdid, args)
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
if cmdid and
|
||||
uci:get("luci", cmdid) == "command" and
|
||||
uci:get("luci", cmdid, "public") == "1"
|
||||
then
|
||||
action_download(cmdid, args)
|
||||
else
|
||||
luci.http.status(403, "Access to command denied")
|
||||
end
|
||||
end
|
37
applications/luci-commands/luasrc/model/cbi/commands.lua
Normal file
37
applications/luci-commands/luasrc/model/cbi/commands.lua
Normal file
|
@ -0,0 +1,37 @@
|
|||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
|
||||
Copyright 2012 Jo-Philipp Wich <jow@openwrt.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
]]--
|
||||
|
||||
local m, s
|
||||
|
||||
m = Map("luci", translate("Custom Commands"),
|
||||
translate("This page allows you to configure custom shell commands which can be easily invoked from the web interface."))
|
||||
|
||||
s = m:section(TypedSection, "command", "")
|
||||
s.template = "cbi/tblsection"
|
||||
s.anonymous = true
|
||||
s.addremove = true
|
||||
|
||||
|
||||
s:option(Value, "name", translate("Description"),
|
||||
translate("A short textual description of the configured command"))
|
||||
|
||||
s:option(Value, "command", translate("Command"),
|
||||
translate("Command line to execute"))
|
||||
|
||||
s:option(Flag, "param", translate("Custom arguments"),
|
||||
translate("Allow the user to provide additional command line arguments"))
|
||||
|
||||
s:option(Flag, "public", translate("Public access"),
|
||||
translate("Allow executing the command and downloading its output without prior authentication"))
|
||||
|
||||
return m
|
176
applications/luci-commands/luasrc/view/commands.htm
Normal file
176
applications/luci-commands/luasrc/view/commands.htm
Normal file
|
@ -0,0 +1,176 @@
|
|||
<%#
|
||||
LuCI - Lua Configuration Interface
|
||||
Copyright 2012 Jo-Philipp Wich <jow@openwrt.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
-%>
|
||||
|
||||
<% css = [[
|
||||
|
||||
.commandbox {
|
||||
height: 12em;
|
||||
width: 30%;
|
||||
float: left;
|
||||
height: 12em;
|
||||
margin: 5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.commandbox h3 {
|
||||
font-size: 1.5em !important;
|
||||
line-height: 2em !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.commandbox input[type="text"] {
|
||||
width: 50% !important;
|
||||
}
|
||||
|
||||
.commandbox div {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 1.5em;
|
||||
}
|
||||
|
||||
]] -%>
|
||||
|
||||
<%+header%>
|
||||
|
||||
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
var stxhr = new XHR();
|
||||
|
||||
function command_run(id)
|
||||
{
|
||||
var args;
|
||||
var field = document.getElementById(id);
|
||||
if (field)
|
||||
args = encodeURIComponent(field.value);
|
||||
|
||||
var legend = document.getElementById('command-rc-legend');
|
||||
var output = document.getElementById('command-rc-output');
|
||||
|
||||
if (legend && output)
|
||||
{
|
||||
output.innerHTML =
|
||||
'<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /> ' +
|
||||
'<%:Waiting for command to complete...%>'
|
||||
;
|
||||
|
||||
legend.parentNode.style.display = 'block';
|
||||
legend.style.display = 'inline';
|
||||
|
||||
stxhr.get('<%=luci.dispatcher.build_url("admin", "system", "commands", "run")%>/' + id + (args ? '/' + args : ''), null,
|
||||
function(x, st)
|
||||
{
|
||||
if (st)
|
||||
{
|
||||
if (st.binary)
|
||||
st.stdout = '[<%:Binary data not displayed, download instead.%>]';
|
||||
|
||||
legend.style.display = 'none';
|
||||
output.innerHTML = String.format(
|
||||
'<pre><strong># %h\n</strong>%h<span style="color:red">%h</span></pre>' +
|
||||
'<div class="alert-message warning">%s (<%:Code:%> %d)</div>',
|
||||
st.command, st.stdout, st.stderr,
|
||||
(st.exitcode == 0) ? '<%:Command successful%>' : '<%:Command failed%>',
|
||||
st.exitcode);
|
||||
}
|
||||
else
|
||||
{
|
||||
legend.style.display = 'none';
|
||||
output.innerHTML = '<span class="error"><%:Failed to execute command!%></span>';
|
||||
}
|
||||
|
||||
location.hash = '#output';
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function command_download(id)
|
||||
{
|
||||
var args;
|
||||
var field = document.getElementById(id);
|
||||
if (field)
|
||||
args = encodeURIComponent(field.value);
|
||||
|
||||
location.href = '<%=luci.dispatcher.build_url("admin", "system", "commands", "download")%>/' + id + (args ? '/' + args : '');
|
||||
}
|
||||
|
||||
function command_link(id)
|
||||
{
|
||||
var legend = document.getElementById('command-rc-legend');
|
||||
var output = document.getElementById('command-rc-output');
|
||||
|
||||
var args;
|
||||
var field = document.getElementById(id);
|
||||
if (field)
|
||||
args = encodeURIComponent(field.value);
|
||||
|
||||
if (legend && output)
|
||||
{
|
||||
var link = location.protocol + '//' + location.hostname +
|
||||
(location.port ? ':' + location.port : '') +
|
||||
location.pathname.split(';')[0] + 'command/' +
|
||||
id + (args ? '/' + args : '');
|
||||
|
||||
legend.style.display = 'none';
|
||||
output.parentNode.style.display = 'block';
|
||||
output.innerHTML = String.format(
|
||||
'<div class="alert-message"><%:Access command with%> <a href="%s">%s</a></div>',
|
||||
link, link
|
||||
);
|
||||
|
||||
location.hash = '#output';
|
||||
}
|
||||
}
|
||||
|
||||
//]]></script>
|
||||
|
||||
<%
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local commands = { }
|
||||
|
||||
uci:foreach("luci", "command", function(s) commands[#commands+1] = s end)
|
||||
%>
|
||||
|
||||
<form method="get" action="<%=pcdata(luci.http.getenv("REQUEST_URI"))%>">
|
||||
<div class="cbi-map">
|
||||
<h2><a id="content" name="content"><%:Custom Commands%></a></h2>
|
||||
|
||||
<fieldset class="cbi-section">
|
||||
<% local _, command; for _, command in ipairs(commands) do %>
|
||||
<div class="commandbox">
|
||||
<h3><%=pcdata(command.name)%></h3>
|
||||
<p><%:Command:%> <code><%=pcdata(command.command)%></code></p>
|
||||
<% if command.param == "1" then %>
|
||||
<p><%:Arguments:%> <input type="text" id="<%=command['.name']%>" /></p>
|
||||
<% end %>
|
||||
<div>
|
||||
<input type="button" value="<%:Run%>" class="cbi-button cbi-button-apply" onclick="command_run('<%=command['.name']%>')" />
|
||||
<input type="button" value="<%:Download%>" class="cbi-button cbi-button-download" onclick="command_download('<%=command['.name']%>')" />
|
||||
<% if command.public == "1" then %>
|
||||
<input type="button" value="<%:Link%>" class="cbi-button cbi-button-link" onclick="command_link('<%=command['.name']%>')" />
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<br style="clear:both" /><br />
|
||||
<a name="output"></a>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<fieldset class="cbi-section" style="display:none">
|
||||
<legend id="command-rc-legend"><%:Collecting data...%></legend>
|
||||
<span id="command-rc-output"></span>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<%+footer%>
|
|
@ -18,7 +18,6 @@ function index()
|
|||
local cc
|
||||
|
||||
cc = entry( { "admin", "services", "coovachilli" }, cbi("coovachilli"), _("CoovaChilli"), 90)
|
||||
cc.i18n = "coovachilli"
|
||||
cc.subindex = true
|
||||
|
||||
entry( { "admin", "services", "coovachilli", "network" }, cbi("coovachilli_network"), _("Network Configuration"), 10)
|
||||
|
|
|
@ -23,10 +23,8 @@ function index()
|
|||
local page
|
||||
|
||||
page = entry({"admin", "services", "ddns"}, cbi("ddns/ddns"), _("Dynamic DNS"), 60)
|
||||
page.i18n = "ddns"
|
||||
page.dependent = true
|
||||
|
||||
page = entry({"mini", "network", "ddns"}, cbi("ddns/ddns", {autoapply=true}), _("Dynamic DNS"), 60)
|
||||
page.i18n = "ddns"
|
||||
page.dependent = true
|
||||
end
|
||||
|
|
|
@ -112,14 +112,19 @@ else
|
|||
end
|
||||
|
||||
|
||||
s:option(Value, "check_interval",
|
||||
translate("Check for changed IP every")).default = 10
|
||||
ci = s:option(Value, "check_interval", translate("Check for changed IP every"))
|
||||
ci.datatype = "and(uinteger,min(1))"
|
||||
ci.default = 10
|
||||
|
||||
unit = s:option(ListValue, "check_unit", translate("Check-time unit"))
|
||||
unit.default = "minutes"
|
||||
unit:value("minutes", translate("min"))
|
||||
unit:value("hours", translate("h"))
|
||||
|
||||
s:option(Value, "force_interval", translate("Force update every")).default = 72
|
||||
fi = s:option(Value, "force_interval", translate("Force update every"))
|
||||
fi.datatype = "and(uinteger,min(1))"
|
||||
fi.default = 72
|
||||
|
||||
unit = s:option(ListValue, "force_unit", translate("Force-time unit"))
|
||||
unit.default = "hours"
|
||||
unit:value("minutes", translate("min"))
|
||||
|
|
|
@ -11,8 +11,6 @@ You may obtain a copy of the License at
|
|||
|
||||
]]--
|
||||
|
||||
require("luci.i18n")
|
||||
|
||||
module("luci.controller.luci_diag", package.seeall)
|
||||
|
||||
function index()
|
||||
|
@ -20,11 +18,9 @@ function index()
|
|||
|
||||
e = entry({"admin", "network", "diag_config"}, template("diag/network_config_index") , _("Configure Diagnostics"), 120)
|
||||
e.index = true
|
||||
e.i18n = "diag_core"
|
||||
e.dependent = true
|
||||
|
||||
e = entry({"mini", "diag"}, template("diag/index"), _("Diagnostics"), 120)
|
||||
e.index = true
|
||||
e.i18n = "diag_core"
|
||||
e.dependent = true
|
||||
end
|
||||
|
|
|
@ -38,8 +38,6 @@ end
|
|||
function parse_output(devmap, outnets, haslink, type, mini, debug)
|
||||
local curnet = next(outnets, nil)
|
||||
|
||||
luci.i18n.loadc("diag_devinfo")
|
||||
|
||||
while (curnet) do
|
||||
local output = outnets[curnet]["output"]
|
||||
local subnet = outnets[curnet]["subnet"]
|
||||
|
|
|
@ -19,49 +19,38 @@ function index()
|
|||
e = entry({"admin", "voice", "diag", "phones"}, arcombine(cbi("luci_diag/smap_devinfo"), cbi("luci_diag/smap_devinfo_config")), _("Phones"), 10)
|
||||
e.leaf = true
|
||||
e.subindex = true
|
||||
e.i18n = "diag_devinfo"
|
||||
e.dependent = true
|
||||
|
||||
e = entry({"admin", "voice", "diag", "phones", "config"}, cbi("luci_diag/smap_devinfo_config"), _("Configure"), 10)
|
||||
e.i18n = "diag_devinfo"
|
||||
|
||||
e = entry({"admin", "status", "smap_devinfo"}, cbi("luci_diag/smap_devinfo"), _("SIP Devices on Network"), 120)
|
||||
e.leaf = true
|
||||
e.i18n = "diag_devinfo"
|
||||
e.dependent = true
|
||||
|
||||
e = entry({"admin", "network", "diag_config", "netdiscover_devinfo_config"}, cbi("luci_diag/netdiscover_devinfo_config"), _("Network Device Scan"), 100)
|
||||
e.leaf = true
|
||||
e.i18n = "diag_devinfo"
|
||||
e.dependent = true
|
||||
|
||||
e = entry({"admin", "network", "diag_config", "smap_devinfo_config"}, cbi("luci_diag/smap_devinfo_config"), _("SIP Device Scan"))
|
||||
e.leaf = true
|
||||
e.i18n = "diag_devinfo"
|
||||
e.dependent = true
|
||||
|
||||
e = entry({"admin", "status", "netdiscover_devinfo"}, cbi("luci_diag/netdiscover_devinfo"), _("Devices on Network"), 90)
|
||||
e.i18n = "diag_devinfo"
|
||||
e.dependent = true
|
||||
|
||||
e = entry({"admin", "network", "mactodevinfo"}, cbi("luci_diag/mactodevinfo"), _("MAC Device Info Overrides"), 190)
|
||||
e.i18n = "diag_devinfo"
|
||||
e.dependent = true
|
||||
|
||||
e = entry({"mini", "diag", "phone_scan"}, cbi("luci_diag/smap_devinfo_mini"), _("Phone Scan"), 100)
|
||||
e.i18n = "diag_devinfo"
|
||||
e.dependent = true
|
||||
|
||||
e = entry({"mini", "voice", "phones", "phone_scan_config"}, cbi("luci_diag/smap_devinfo_config_mini"), _("Config Phone Scan"), 90)
|
||||
e.i18n = "diag_devinfo"
|
||||
e.dependent = true
|
||||
|
||||
e = entry({"mini", "diag", "netdiscover_devinfo"}, cbi("luci_diag/netdiscover_devinfo_mini"), _("Network Device Scan"), 10)
|
||||
e.i18n = "diag_devinfo"
|
||||
e.dependent = true
|
||||
|
||||
e = entry({"mini", "network", "netdiscover_devinfo_config"}, cbi("luci_diag/netdiscover_devinfo_config_mini"), _("Device Scan Config"))
|
||||
e.i18n = "diag_devinfo"
|
||||
e.dependent = true
|
||||
|
||||
end
|
||||
|
|
|
@ -83,7 +83,6 @@ function command_function(outnets, i)
|
|||
end
|
||||
|
||||
function action_links(netdiscovermap, mini)
|
||||
luci.i18n.loadc("diag_devinfo")
|
||||
s = netdiscovermap:section(SimpleSection, "", translate("Actions"))
|
||||
b = s:option(DummyValue, "_config", translate("Configure Scans"))
|
||||
b.value = ""
|
||||
|
|
|
@ -94,7 +94,6 @@ function command_function(outnets, i)
|
|||
end
|
||||
|
||||
function action_links(smapmap, mini)
|
||||
luci.i18n.loadc("diag_devinfo")
|
||||
s = smapmap:section(SimpleSection, "", translate("Actions"))
|
||||
b = s:option(DummyValue, "_config", translate("Configure Scans"))
|
||||
b.value = ""
|
||||
|
|
|
@ -3,7 +3,7 @@ module("luci.controller.firewall", package.seeall)
|
|||
function index()
|
||||
entry({"admin", "network", "firewall"},
|
||||
alias("admin", "network", "firewall", "zones"),
|
||||
_("Firewall"), 60).i18n = "firewall"
|
||||
_("Firewall"), 60)
|
||||
|
||||
entry({"admin", "network", "firewall", "zones"},
|
||||
arcombine(cbi("firewall/zones"), cbi("firewall/zone-details")),
|
||||
|
|
|
@ -14,5 +14,5 @@ module "luci.controller.freifunk.policy-routing"
|
|||
|
||||
function index()
|
||||
entry({"admin", "freifunk", "policyrouting"}, cbi("freifunk/policyrouting"),
|
||||
_("Policy Routing"), 60).i18n = "freifunk-policyrouting"
|
||||
_("Policy Routing"), 60)
|
||||
end
|
||||
|
|
|
@ -10,7 +10,6 @@ You may obtain a copy of the License at
|
|||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
]]--
|
||||
|
||||
luci.i18n.loadc("freifunk")
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
|
||||
m = Map("freifunk-policyrouting", translate("Policy Routing"), translate("These pages can be used to setup policy routing for certain firewall zones. "..
|
||||
|
|
|
@ -23,6 +23,5 @@ function index()
|
|||
local page
|
||||
|
||||
page = entry({"admin", "services", "hd_idle"}, cbi("hd_idle"), _("hd-idle"), 60)
|
||||
page.i18n = "hd_idle"
|
||||
page.dependent = true
|
||||
end
|
||||
|
|
|
@ -22,7 +22,6 @@ function index()
|
|||
page.target = firstchild()
|
||||
page.title = _("VoIP")
|
||||
page.order = 90
|
||||
page.i18n = "telephony"
|
||||
|
||||
entry({"admin", "telephony", "account"}, cbi("luci_ltqtapi/account") , _("Account"), 10)
|
||||
entry({"admin", "telephony", "contact"}, cbi("luci_ltqtapi/contact") , _("Contacts"), 20)
|
||||
|
|
|
@ -22,7 +22,6 @@ function index()
|
|||
local page
|
||||
|
||||
page = entry({"admin", "services", "minidlna"}, cbi("minidlna"), _("miniDLNA"))
|
||||
page.i18n = "minidlna"
|
||||
page.dependent = true
|
||||
|
||||
entry({"admin", "services", "minidlna_status"}, call("minidlna_status"))
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
<%- luci.i18n.loadc("minidlna") -%>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
XHR.poll(5, '<%=luci.dispatcher.build_url("admin/services/minidlna_status")%>', null,
|
||||
function(x, st)
|
||||
|
|
|
@ -23,6 +23,5 @@ function index()
|
|||
local page
|
||||
|
||||
page = entry({"admin", "system", "mmc_over_gpio"}, cbi("mmc_over_gpio"), _("MMC/SD driver configuration"), 60)
|
||||
page.i18n = "mmc_over_gpio"
|
||||
page.dependent = true
|
||||
end
|
||||
|
|
|
@ -9,13 +9,11 @@ function index()
|
|||
local page
|
||||
|
||||
page = entry({"admin", "network", "multiwan"}, cbi("multiwan/multiwan"), _("Multi-WAN"))
|
||||
page.i18n = "multiwan"
|
||||
page.dependent = true
|
||||
|
||||
entry({"admin", "network", "multiwan", "status"}, call("multiwan_status"))
|
||||
|
||||
page = entry({"mini", "network", "multiwan"}, cbi("multiwan/multiwanmini", {autoapply=true}), _("Multi-WAN"))
|
||||
page.i18n = "multiwan"
|
||||
page.dependent = true
|
||||
end
|
||||
function multiwan_status()
|
||||
|
|
|
@ -23,10 +23,8 @@ function index()
|
|||
local page
|
||||
|
||||
page = entry({"admin", "system", "ntpc"}, cbi("ntpc/ntpc"), _("Time Synchronisation"), 50)
|
||||
page.i18n = "ntpc"
|
||||
page.dependent = true
|
||||
|
||||
page = entry({"mini", "system", "ntpc"}, cbi("ntpc/ntpcmini", {autoapply=true}), _("Time Synchronisation"), 50)
|
||||
page.i18n = "ntpc"
|
||||
page.dependent = true
|
||||
end
|
||||
|
|
|
@ -20,14 +20,21 @@ s.addremove = false
|
|||
|
||||
s:option(DummyValue, "_time", translate("Current system time")).value = os.date("%c")
|
||||
|
||||
s:option(Value, "interval", translate("Update interval (in seconds)")).rmempty = true
|
||||
s:option(Value, "count", translate("Count of time measurements"), translate("empty = infinite")).rmempty = true
|
||||
interval = s:option(Value, "interval", translate("Update interval (in seconds)"))
|
||||
interval.datatype = "and(uinteger,min(1))"
|
||||
interval.rmempty = true
|
||||
|
||||
count = s:option(Value, "count", translate("Count of time measurements"), translate("empty = infinite"))
|
||||
count.datatype = "and(uinteger,min(1))"
|
||||
count.rmempty = true
|
||||
|
||||
s2 = m:section(TypedSection, "ntpdrift", translate("Clock Adjustment"))
|
||||
s2.anonymous = true
|
||||
s2.addremove = false
|
||||
s2:option(Value, "freq", translate("Offset frequency")).rmempty = true
|
||||
|
||||
freq = s2:option(Value, "freq", translate("Offset frequency"))
|
||||
freq.datatype = "integer"
|
||||
freq.rmempty = true
|
||||
|
||||
s3 = m:section(TypedSection, "ntpserver", translate("Time Servers"))
|
||||
s3.anonymous = true
|
||||
|
@ -35,6 +42,8 @@ s3.addremove = true
|
|||
s3.template = "cbi/tblsection"
|
||||
|
||||
s3:option(Value, "hostname", translate("Hostname"))
|
||||
s3:option(Value, "port", translate("Port")).rmempty = true
|
||||
port = s3:option(Value, "port", translate("Port"))
|
||||
port.datatype = "port"
|
||||
port.rmempty = true
|
||||
|
||||
return m
|
||||
|
|
|
@ -21,8 +21,9 @@ s.addremove = false
|
|||
|
||||
s:option(DummyValue, "_time", translate("Current system time")).value = os.date("%c")
|
||||
|
||||
s:option(Value, "interval", translate("Update interval (in seconds)")).rmempty = true
|
||||
|
||||
interval = s:option(Value, "interval", translate("Update interval (in seconds)"))
|
||||
interval.datatype = "and(uinteger,min(1))"
|
||||
interval.rmempty = true
|
||||
|
||||
s3 = m:section(TypedSection, "ntpserver", translate("Time Server"))
|
||||
s3.anonymous = true
|
||||
|
@ -30,6 +31,8 @@ s3.addremove = true
|
|||
s3.template = "cbi/tblsection"
|
||||
|
||||
s3:option(Value, "hostname", translate("Hostname"))
|
||||
s3:option(Value, "port", translate("Port")).rmempty = true
|
||||
port = s3:option(Value, "port", translate("Port"))
|
||||
port.datatype = "port"
|
||||
port.rmempty = true
|
||||
|
||||
return m
|
||||
|
|
|
@ -8,7 +8,6 @@ function index()
|
|||
local page = node("admin", "status", "olsr")
|
||||
page.target = template("status-olsr/overview")
|
||||
page.title = _("OLSR")
|
||||
page.i18n = "olsr"
|
||||
page.subindex = true
|
||||
|
||||
local page = node("admin", "status", "olsr", "neighbors")
|
||||
|
@ -51,7 +50,6 @@ function index()
|
|||
{"admin", "services", "olsrd"},
|
||||
cbi("olsr/olsrd"), "OLSR"
|
||||
)
|
||||
ol.i18n = "olsr"
|
||||
ol.subindex = true
|
||||
|
||||
entry(
|
||||
|
@ -74,7 +72,6 @@ function index()
|
|||
cbi("olsr/olsrddisplay"), _("Display")
|
||||
)
|
||||
|
||||
oplg.i18n = "olsr"
|
||||
oplg.leaf = true
|
||||
oplg.subindex = true
|
||||
|
||||
|
|
|
@ -16,11 +16,11 @@ function etx_color(etx)
|
|||
local color = "#bb3333"
|
||||
if etx == 0 then
|
||||
color = "#bb3333"
|
||||
elseif etx < 4 then
|
||||
elseif etx < 2 then
|
||||
color = "#00cc00"
|
||||
elseif etx < 10 then
|
||||
elseif etx < 4 then
|
||||
color = "#ffcb05"
|
||||
elseif etx < 100 then
|
||||
elseif etx < 10 then
|
||||
color = "#ff6600"
|
||||
end
|
||||
return color
|
||||
|
|
|
@ -147,6 +147,10 @@ end
|
|||
<li><strong>LQ: </strong><%:Success rate of packages received from the neighbour%></li>
|
||||
<li><strong>NLQ: </strong><%:Success rate of packages sent to the neighbour%></li>
|
||||
<li><strong>ETX: </strong><%:Expected retransmission count%></li>
|
||||
<li><strong><span style="color:#00cc00"><%:Green%></span></strong>:<%:Very good (ETX < 2)%></li>
|
||||
<li><strong><span style="color:#ffcb05"><%:Yellow%></span></strong>:<%:Good (2 < ETX < 4)%></li>
|
||||
<li><strong><span style="color:#ff6600"><%:Orange%></span></strong>:<%:Still usable (4 < ETX < 10)%></li>
|
||||
<li><strong><span style="color:#bb3333"><%:Red%></span></strong>:<%:Bad (ETX > 10)%></li>
|
||||
</ul>
|
||||
</fieldset>
|
||||
<%+footer%>
|
||||
|
|
|
@ -16,7 +16,7 @@ $Id$
|
|||
module("luci.controller.openvpn", package.seeall)
|
||||
|
||||
function index()
|
||||
entry( {"admin", "services", "openvpn"}, cbi("openvpn"), _("OpenVPN") ).i18n = "openvpn"
|
||||
entry( {"admin", "services", "openvpn"}, cbi("openvpn"), _("OpenVPN") )
|
||||
entry( {"admin", "services", "openvpn", "basic"}, cbi("openvpn-basic"), nil ).leaf = true
|
||||
entry( {"admin", "services", "openvpn", "advanced"}, cbi("openvpn-advanced"), nil ).leaf = true
|
||||
end
|
||||
|
|
|
@ -16,5 +16,5 @@ module("luci.controller.ff_p2pblock", package.seeall)
|
|||
|
||||
function index()
|
||||
entry({"admin", "network", "firewall", "p2pblock"}, cbi("luci_fw/p2pblock"),
|
||||
_("P2P-Block"), 40).i18n = "p2pblock"
|
||||
_("P2P-Block"), 40)
|
||||
end
|
||||
|
|
|
@ -23,6 +23,5 @@ function index()
|
|||
local page
|
||||
|
||||
page = entry({"admin", "services", "p910nd"}, cbi("p910nd"), _("p910nd - Printer server"), 60)
|
||||
page.i18n = "p910nd"
|
||||
page.dependent = true
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
LuCI p910nd
|
||||
(c) 2008 Yanira <forum-2008@email.de>
|
||||
(c) 2012 Jo-Philipp Wich <jow@openwrt.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -9,15 +10,17 @@ You may obtain a copy of the License at
|
|||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
$Id$
|
||||
|
||||
]]--
|
||||
|
||||
local uci = luci.model.uci.cursor_state()
|
||||
local net = require "luci.model.network"
|
||||
local m, s, p, b
|
||||
|
||||
m = Map("p910nd", translate("p910nd - Printer server"),
|
||||
translatef("First you have to install the packages to get support for USB (kmod-usb-printer) or parallel port (kmod-lp)."))
|
||||
|
||||
net = net.init(m.uci)
|
||||
|
||||
s = m:section(TypedSection, "p910nd", translate("Settings"))
|
||||
s.addremove = true
|
||||
s.anonymous = true
|
||||
|
@ -26,6 +29,25 @@ s:option(Flag, "enabled", translate("enable"))
|
|||
|
||||
s:option(Value, "device", translate("Device")).rmempty = true
|
||||
|
||||
b = s:option(Value, "bind", translate("Interface"), translate("Specifies the interface to listen on."))
|
||||
b.template = "cbi/network_netlist"
|
||||
b.nocreate = true
|
||||
b.unspecified = true
|
||||
|
||||
function b.cfgvalue(...)
|
||||
local v = Value.cfgvalue(...)
|
||||
if v then
|
||||
return (net:get_status_by_address(v))
|
||||
end
|
||||
end
|
||||
|
||||
function b.write(self, section, value)
|
||||
local n = net:get_network(value)
|
||||
if n and n:ipaddr() then
|
||||
Value.write(self, section, n:ipaddr())
|
||||
end
|
||||
end
|
||||
|
||||
p = s:option(ListValue, "port", translate("Port"), translate("TCP listener port."))
|
||||
p.rmempty = true
|
||||
for i=0,9 do
|
||||
|
|
|
@ -19,7 +19,7 @@ function index()
|
|||
return
|
||||
end
|
||||
|
||||
entry({"admin", "services", "polipo"}, alias("admin", "services", "polipo", "config"), _("Polipo")).i18n = "polipo"
|
||||
entry({"admin", "services", "polipo"}, alias("admin", "services", "polipo", "config"), _("Polipo"))
|
||||
entry({"admin", "services", "polipo", "status"}, template("polipo_status"), _("Status"))
|
||||
entry({"admin", "services", "polipo", "config"}, cbi("polipo"), _("Configuration"))
|
||||
end
|
||||
|
|
|
@ -22,10 +22,8 @@ function index()
|
|||
local page
|
||||
|
||||
page = entry({"admin", "network", "qos"}, cbi("qos/qos"), _("QoS"))
|
||||
page.i18n = "qos"
|
||||
page.dependent = true
|
||||
|
||||
page = entry({"mini", "network", "qos"}, cbi("qos/qosmini", {autoapply=true}), _("QoS"))
|
||||
page.i18n = "qos"
|
||||
page.dependent = true
|
||||
end
|
||||
|
|
|
@ -35,9 +35,11 @@ s:option(Flag, "overhead", translate("Calculate overhead"))
|
|||
|
||||
s:option(Flag, "halfduplex", translate("Half-duplex"))
|
||||
|
||||
s:option(Value, "download", translate("Download speed (kbit/s)"))
|
||||
dl = s:option(Value, "download", translate("Download speed (kbit/s)"))
|
||||
dl.datatype = "and(uinteger,min(1))"
|
||||
|
||||
s:option(Value, "upload", translate("Upload speed (kbit/s)"))
|
||||
ul = s:option(Value, "upload", translate("Upload speed (kbit/s)"))
|
||||
ul.datatype = "and(uinteger,min(1))"
|
||||
|
||||
s = m:section(TypedSection, "classify", translate("Classification Rules"))
|
||||
s.template = "cbi/tblsection"
|
||||
|
|
|
@ -21,8 +21,12 @@ m = Map("qos")
|
|||
s = m:section(NamedSection, "wan", "interface", translate("Internet Connection"))
|
||||
|
||||
s:option(Flag, "enabled", translate("Quality of Service"))
|
||||
s:option(Value, "download", translate("Downlink"), "kbit/s")
|
||||
s:option(Value, "upload", translate("Uplink"), "kbit/s")
|
||||
|
||||
dl = s:option(Value, "download", translate("Downlink"), "kbit/s")
|
||||
dl.datatype = "and(uinteger,min(1))"
|
||||
|
||||
ul = s:option(Value, "upload", translate("Uplink"), "kbit/s")
|
||||
ul.datatype = "and(uinteger,min(1))"
|
||||
|
||||
s = m:section(TypedSection, "classify")
|
||||
s.template = "cbi/tblsection"
|
||||
|
|
|
@ -19,7 +19,7 @@ function index()
|
|||
return
|
||||
end
|
||||
|
||||
entry({"admin", "network", "radvd"}, cbi("radvd"), _("Radvd"), 61).i18n = "radvd"
|
||||
entry({"admin", "network", "radvd"}, cbi("radvd"), _("Radvd"), 61)
|
||||
entry({"admin", "network", "radvd", "interface"}, cbi("radvd/interface"), nil).leaf = true
|
||||
entry({"admin", "network", "radvd", "prefix"}, cbi("radvd/prefix"), nil).leaf = true
|
||||
entry({"admin", "network", "radvd", "route"}, cbi("radvd/route"), nil).leaf = true
|
||||
|
|
|
@ -23,6 +23,5 @@ function index()
|
|||
local page
|
||||
|
||||
page = entry({"admin", "services", "samba"}, cbi("samba"), _("Network Shares"))
|
||||
page.i18n = "samba"
|
||||
page.dependent = true
|
||||
end
|
||||
|
|
|
@ -1,28 +1,25 @@
|
|||
module("luci.controller.splash.splash", package.seeall)
|
||||
luci.i18n.loadc("splash")
|
||||
|
||||
local uci = luci.model.uci.cursor()
|
||||
local util = require "luci.util"
|
||||
|
||||
function index()
|
||||
entry({"admin", "services", "splash"}, cbi("splash/splash"), _("Client-Splash"), 90).i18n = "freifunk"
|
||||
entry({"admin", "services", "splash"}, cbi("splash/splash"), _("Client-Splash"), 90)
|
||||
entry({"admin", "services", "splash", "splashtext" }, form("splash/splashtext"), _("Splashtext"), 10)
|
||||
|
||||
local e
|
||||
|
||||
e = node("splash")
|
||||
e.target = call("action_dispatch")
|
||||
e.i18n = "freifunk"
|
||||
|
||||
node("splash", "activate").target = call("action_activate")
|
||||
node("splash", "splash").target = template("splash_splash/splash")
|
||||
node("splash", "blocked").target = template("splash/blocked")
|
||||
|
||||
entry({"admin", "status", "splash"}, call("action_status_admin"), _("Client-Splash")).i18n = "freifunk"
|
||||
entry({"admin", "status", "splash"}, call("action_status_admin"), _("Client-Splash"))
|
||||
|
||||
local page = node("splash", "publicstatus")
|
||||
page.target = call("action_status_public")
|
||||
page.i18n = "freifunk"
|
||||
page.leaf = true
|
||||
end
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ You may obtain a copy of the License at
|
|||
]]--
|
||||
|
||||
require("luci.model.uci")
|
||||
luci.i18n.loadc("splash")
|
||||
|
||||
m = Map("luci_splash", translate("Client-Splash"), translate("Client-Splash is a hotspot authentification system for wireless mesh networks."))
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ You may obtain a copy of the License at
|
|||
]]--
|
||||
|
||||
local fs = require "nixio.fs"
|
||||
luci.i18n.loadc("splash")
|
||||
|
||||
local splashtextfile = "/usr/lib/luci-splash/splashtext.html"
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ local ipt = require "luci.sys.iptparser".IptParser()
|
|||
local uci = require "luci.model.uci".cursor_state()
|
||||
local wat = require "luci.tools.webadmin"
|
||||
local fs = require "nixio.fs"
|
||||
luci.i18n.loadc("splash")
|
||||
|
||||
local clients = { }
|
||||
local leasetime = tonumber(uci:get("luci_splash", "general", "leasetime") or 1) * 60 * 60
|
||||
|
|
|
@ -50,6 +50,7 @@ function index()
|
|||
memory = _("Memory"),
|
||||
netlink = _("Netlink"),
|
||||
network = _("Network"),
|
||||
nut = _("UPS"),
|
||||
olsrd = _("OLSRd"),
|
||||
ping = _("Ping"),
|
||||
processes = _("Processes"),
|
||||
|
@ -61,13 +62,12 @@ function index()
|
|||
-- our collectd menu
|
||||
local collectd_menu = {
|
||||
output = { "csv", "network", "rrdtool", "unixsock" },
|
||||
system = { "cpu", "df", "disk", "email", "exec", "irq", "load", "memory", "processes" },
|
||||
system = { "cpu", "df", "disk", "email", "exec", "irq", "load", "memory", "nut", "processes" },
|
||||
network = { "conntrack", "dns", "interface", "iptables", "netlink", "olsrd", "ping", "tcpconns", "iwinfo" }
|
||||
}
|
||||
|
||||
-- create toplevel menu nodes
|
||||
local st = entry({"admin", "statistics"}, template("admin_statistics/index"), _("Statistics"), 80)
|
||||
st.i18n = "statistics"
|
||||
st.index = true
|
||||
|
||||
entry({"admin", "statistics", "collectd"}, cbi("luci_statistics/collectd"), _("Collectd"), 10).subindex = true
|
||||
|
@ -82,7 +82,6 @@ function index()
|
|||
)
|
||||
|
||||
e.index = true
|
||||
e.i18n = "rrdtool"
|
||||
|
||||
for j, plugin in luci.util.vspairs( plugins ) do
|
||||
_entry(
|
||||
|
@ -97,7 +96,6 @@ function index()
|
|||
|
||||
-- output views
|
||||
local page = entry( { "admin", "statistics", "graph" }, template("admin_statistics/index"), _("Graphs"), 80)
|
||||
page.i18n = "statistics"
|
||||
page.setuser = "nobody"
|
||||
page.setgroup = "nogroup"
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ require("luci.sys")
|
|||
m = Map("luci_statistics",
|
||||
translate("Collectd Settings"),
|
||||
translate(
|
||||
"Collectd is a small daeomon for collecting data from " ..
|
||||
"Collectd is a small daemon for collecting data from " ..
|
||||
"various sources through different plugins. On this page " ..
|
||||
"you can change general settings for the collectd daemon."
|
||||
))
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
|
||||
Copyright © 2011 Manuel Munz <freifunk at somakoma dot de>
|
||||
Copyright © 2012 David Woodhouse <dwmw2@infradead.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
]]--
|
||||
|
||||
m = Map("luci_statistics",
|
||||
translate("UPS Plugin Configuration"),
|
||||
translate("The NUT plugin reads information about Uninterruptible Power Supplies."))
|
||||
|
||||
s = m:section(NamedSection, "collectd_nut", "luci_statistics" )
|
||||
|
||||
enable = s:option(Flag, "enable", translate("Enable this plugin"))
|
||||
enable.default = 0
|
||||
|
||||
host = s:option(Value, "UPS", translate("UPS"), translate("UPS name in NUT ups@host format"))
|
||||
host.placeholder = "myupsname"
|
||||
host.datatype = "string"
|
||||
host.rmempty = true
|
||||
|
||||
return m
|
|
@ -25,9 +25,6 @@ Instance = luci.util.class()
|
|||
function Instance.__init__( self, graph )
|
||||
self.i18n = luci.i18n
|
||||
self.graph = graph
|
||||
|
||||
self.i18n.loadc("rrdtool")
|
||||
self.i18n.loadc("statistics")
|
||||
end
|
||||
|
||||
function Instance._subst( self, str, val )
|
||||
|
|
|
@ -156,11 +156,14 @@ function Graph._generic( self, opts, plugin, plugin_instance, dtype, index )
|
|||
|
||||
if not ds or ds:len() == 0 then ds = "value" end
|
||||
|
||||
_tif( _args, "DEF:%s_avg=%s:%s:AVERAGE", inst, rrd, ds )
|
||||
_tif( _args, "DEF:%s_avg_raw=%s:%s:AVERAGE", inst, rrd, ds )
|
||||
_tif( _args, "CDEF:%s_avg=%s_avg_raw,%s", inst, inst, source.transform_rpn )
|
||||
|
||||
if not self.opts.rrasingle then
|
||||
_tif( _args, "DEF:%s_min=%s:%s:MIN", inst, rrd, ds )
|
||||
_tif( _args, "DEF:%s_max=%s:%s:MAX", inst, rrd, ds )
|
||||
_tif( _args, "DEF:%s_min_raw=%s:%s:MIN", inst, rrd, ds )
|
||||
_tif( _args, "CDEF:%s_min=%s_min_raw,%s", inst, inst, source.transform_rpn )
|
||||
_tif( _args, "DEF:%s_max_raw=%s:%s:MAX", inst, rrd, ds )
|
||||
_tif( _args, "CDEF:%s_max=%s_max_raw,%s", inst, inst, source.transform_rpn )
|
||||
end
|
||||
|
||||
_tif( _args, "CDEF:%s_nnl=%s_avg,UN,0,%s_avg,IF", inst, inst, inst )
|
||||
|
@ -180,20 +183,23 @@ function Graph._generic( self, opts, plugin, plugin_instance, dtype, index )
|
|||
|
||||
-- is first source in stack or overlay source: source_stk = source_nnl
|
||||
if not prev or source.overlay then
|
||||
-- create cdef statement
|
||||
-- create cdef statement for cumulative stack (no NaNs) and also
|
||||
-- for display (preserving NaN where no points should be displayed)
|
||||
_tif( _args, "CDEF:%s_stk=%s_nnl", source.sname, source.sname )
|
||||
_tif( _args, "CDEF:%s_plot=%s_avg", source.sname, source.sname )
|
||||
|
||||
-- is subsequent source without overlay: source_stk = source_nnl + previous_stk
|
||||
else
|
||||
-- create cdef statement
|
||||
_tif( _args, "CDEF:%s_stk=%s_nnl,%s_stk,+", source.sname, source.sname, prev )
|
||||
_tif( _args, "CDEF:%s_plot=%s_avg,%s_stk,+", source.sname, source.sname, prev )
|
||||
end
|
||||
|
||||
-- create multiply by minus one cdef if flip is enabled
|
||||
if source.flip then
|
||||
|
||||
-- create cdef statement: source_stk = source_stk * -1
|
||||
_tif( _args, "CDEF:%s_neg=%s_stk,-1,*", source.sname, source.sname )
|
||||
_tif( _args, "CDEF:%s_neg=%s_plot,-1,*", source.sname, source.sname )
|
||||
|
||||
-- push to negative stack if overlay is disabled
|
||||
if not source.overlay then
|
||||
|
@ -253,11 +259,11 @@ function Graph._generic( self, opts, plugin, plugin_instance, dtype, index )
|
|||
-- derive area background color from line color
|
||||
area_color = self.colors:to_string( self.colors:faded( area_color ) )
|
||||
|
||||
-- choose source_stk or source_neg variable depending on flip state
|
||||
-- choose source_plot or source_neg variable depending on flip state
|
||||
if source.flip then
|
||||
var = "neg"
|
||||
else
|
||||
var = "stk"
|
||||
var = "plot"
|
||||
end
|
||||
|
||||
-- create legend
|
||||
|
@ -400,6 +406,7 @@ function Graph._generic( self, opts, plugin, plugin_instance, dtype, index )
|
|||
flip = dopts.flip or false,
|
||||
total = dopts.total or false,
|
||||
overlay = dopts.overlay or false,
|
||||
transform_rpn = dopts.transform_rpn or "0,+",
|
||||
noarea = dopts.noarea or false,
|
||||
title = dopts.title or nil,
|
||||
ds = dsource,
|
||||
|
@ -450,6 +457,18 @@ function Graph._generic( self, opts, plugin, plugin_instance, dtype, index )
|
|||
_ti( _args, self.i18n:title( plugin, plugin_instance, _sources[1].type, instance, opts.title ) )
|
||||
_ti( _args, "-v" )
|
||||
_ti( _args, self.i18n:label( plugin, plugin_instance, _sources[1].type, instance, opts.vlabel ) )
|
||||
if opts.y_max then
|
||||
_ti ( _args, "-u" )
|
||||
_ti ( _args, opts.y_max )
|
||||
end
|
||||
if opts.y_min then
|
||||
_ti ( _args, "-l" )
|
||||
_ti ( _args, opts.y_min )
|
||||
end
|
||||
if opts.units_exponent then
|
||||
_ti ( _args, "-X" )
|
||||
_ti ( _args, opts.units_exponent )
|
||||
end
|
||||
|
||||
-- store additional rrd options
|
||||
if opts.rrdopts then
|
||||
|
|
|
@ -19,6 +19,7 @@ function rrdargs( graph, plugin, plugin_instance, dtype )
|
|||
|
||||
return {
|
||||
title = "%H: Processor usage on core #%pi",
|
||||
y_min = "0",
|
||||
vlabel = "Percent",
|
||||
number_format = "%5.1lf%%",
|
||||
data = {
|
||||
|
|
|
@ -19,6 +19,8 @@ function rrdargs( graph, plugin, plugin_instance, dtype )
|
|||
|
||||
return {
|
||||
title = "%H: Load", vlabel = "Load",
|
||||
y_min = "0",
|
||||
units_exponent = "0",
|
||||
number_format = "%5.2lf", data = {
|
||||
sources = {
|
||||
load = { "shortterm", "midterm", "longterm" }
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
--[[
|
||||
|
||||
Luci statistics - ups plugin diagram definition
|
||||
Copyright © 2008 Freifunk Leipzig / Jo-Philipp Wich <xm@leipzig.freifunk.net>
|
||||
Copyright © 2012 David Woodhouse <dwmw2@infradead.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
]]--
|
||||
|
||||
|
||||
module("luci.statistics.rrdtool.definitions.nut",package.seeall)
|
||||
|
||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
||||
|
||||
local voltages = {
|
||||
title = "%H: Voltages on UPS \"%pi\"",
|
||||
vlabel = "V",
|
||||
number_format = "%5.1lfV",
|
||||
data = {
|
||||
instances = {
|
||||
voltage = { "battery", "input", "output" }
|
||||
},
|
||||
|
||||
options = {
|
||||
voltage_output = { color = "00e000", title = "Output voltage", noarea=true, overlay=true },
|
||||
voltage_battery = { color = "0000ff", title = "Battery voltage", noarea=true, overlay=true },
|
||||
voltage_input = { color = "ffb000", title = "Input voltage", noarea=true, overlay=true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local currents = {
|
||||
title = "%H: Current on UPS \"%pi\"",
|
||||
vlabel = "A",
|
||||
number_format = "%5.3lfA",
|
||||
data = {
|
||||
instances = {
|
||||
current = { "battery", "output" }
|
||||
},
|
||||
|
||||
options = {
|
||||
current_output = { color = "00e000", title = "Output current", noarea=true, overlay=true },
|
||||
current_battery = { color = "0000ff", title = "Battery current", noarea=true, overlay=true },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local percentage = {
|
||||
title = "%H: Battery charge on UPS \"%pi\"",
|
||||
vlabel = "Percent",
|
||||
y_min = "0",
|
||||
y_max = "100",
|
||||
number_format = "%5.1lf%%",
|
||||
data = {
|
||||
sources = {
|
||||
percent = { "percent" }
|
||||
},
|
||||
instances = {
|
||||
percent = "charge"
|
||||
},
|
||||
options = {
|
||||
percent_charge = { color = "00ff00", title = "Charge level" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-- Note: This is in ISO8859-1 for rrdtool. Welcome to the 20th century.
|
||||
local temperature = {
|
||||
title = "%H: Battery temperature on UPS \"%pi\"",
|
||||
vlabel = "\176C",
|
||||
number_format = "%5.1lf\176C",
|
||||
data = {
|
||||
instances = {
|
||||
temperature = "battery"
|
||||
},
|
||||
|
||||
options = {
|
||||
temperature_battery = { color = "ffb000", title = "Battery temperature" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local timeleft = {
|
||||
title = "%H: Time left on UPS \"%pi\"",
|
||||
vlabel = "Minutes",
|
||||
number_format = "%.1lfm",
|
||||
data = {
|
||||
sources = {
|
||||
timeleft = { "timeleft" }
|
||||
},
|
||||
instances = {
|
||||
timeleft = { "battery" }
|
||||
},
|
||||
options = {
|
||||
timeleft_battery = { color = "0000ff", title = "Time left", transform_rpn = "60,/" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { voltages, currents, percentage, temperature, timeleft }
|
||||
end
|
|
@ -131,3 +131,7 @@ config 'statistics' 'collectd_olsrd'
|
|||
|
||||
config 'statistics' 'collectd_iwinfo'
|
||||
option 'enable' '1'
|
||||
|
||||
config 'statistics' 'collectd_nut'
|
||||
option 'enable' '0'
|
||||
option 'UPS' 'myupsname'
|
||||
|
|
|
@ -357,6 +357,12 @@ plugins = {
|
|||
|
||||
network = config_network,
|
||||
|
||||
nut = {
|
||||
{ "UPS" },
|
||||
{ },
|
||||
{ }
|
||||
},
|
||||
|
||||
olsrd = {
|
||||
{ "Host", "Port", "CollectLinks","CollectRoutes","CollectTopology"},
|
||||
{ },
|
||||
|
|
|
@ -20,7 +20,7 @@ function index()
|
|||
return
|
||||
end
|
||||
|
||||
entry({"admin", "services", "tinyproxy"}, alias("admin", "services", "tinyproxy", "config"), _("Tinyproxy")).i18n = "tinyproxy"
|
||||
entry({"admin", "services", "tinyproxy"}, alias("admin", "services", "tinyproxy", "config"), _("Tinyproxy"))
|
||||
entry({"admin", "services", "tinyproxy", "status"}, template("tinyproxy_status"), _("Status"))
|
||||
entry({"admin", "services", "tinyproxy", "config"}, cbi("tinyproxy"), _("Configuration"))
|
||||
end
|
||||
|
|
|
@ -15,14 +15,11 @@ $Id$
|
|||
module("luci.controller.transmission", package.seeall)
|
||||
|
||||
function index()
|
||||
require("luci.i18n")
|
||||
luci.i18n.loadc("transmission")
|
||||
if not nixio.fs.access("/etc/config/transmission") then
|
||||
return
|
||||
end
|
||||
|
||||
local page = entry({"admin", "services", "transmission"}, cbi("transmission"), _("Transmission"))
|
||||
page.i18n = "transmission"
|
||||
page.dependent = true
|
||||
|
||||
end
|
||||
|
|
|
@ -23,11 +23,9 @@ function index()
|
|||
local page
|
||||
|
||||
page = entry({"admin", "services", "upnp"}, cbi("upnp/upnp"), _("UPNP"))
|
||||
page.i18n = "upnp"
|
||||
page.dependent = true
|
||||
|
||||
page = entry({"mini", "network", "upnp"}, cbi("upnp/upnpmini", {autoapply=true}), _("UPNP"))
|
||||
page.i18n = "upnp"
|
||||
page.dependent = true
|
||||
|
||||
entry({"admin", "services", "upnp", "status"}, call("act_status")).leaf = true
|
||||
|
@ -69,10 +67,8 @@ function act_status()
|
|||
end
|
||||
end
|
||||
|
||||
function act_delete()
|
||||
local path = luci.dispatcher.context.requestpath
|
||||
local idx = tonumber(path[#path])
|
||||
|
||||
function act_delete(idx)
|
||||
idx = tonumber(idx)
|
||||
if idx and idx > 0 then
|
||||
luci.sys.call("iptables -t filter -D MINIUPNPD %d 2>/dev/null" % idx)
|
||||
luci.sys.call("iptables -t nat -D MINIUPNPD %d 2>/dev/null" % idx)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
<%- luci.i18n.loadc("upnp") -%>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
function upnp_delete_fwd(idx) {
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "upnp", "delete")%>/' + idx, null,
|
||||
|
|
|
@ -23,6 +23,5 @@ function index()
|
|||
local page
|
||||
|
||||
page = entry({"admin", "services", "ushare"}, cbi("ushare"), _("uShare"), 60)
|
||||
page.i18n = "ushare"
|
||||
page.dependent = true
|
||||
end
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
module("luci.controller.vnstat", package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "status", "vnstat"}, alias("admin", "status", "vnstat", "graphs"), _("VnStat Traffic Monitor"), 90).i18n = "vnstat"
|
||||
entry({"admin", "status", "vnstat"}, alias("admin", "status", "vnstat", "graphs"), _("VnStat Traffic Monitor"), 90)
|
||||
entry({"admin", "status", "vnstat", "graphs"}, template("vnstat"), _("Graphs"), 1)
|
||||
entry({"admin", "status", "vnstat", "config"}, cbi("vnstat"), _("Configuration"), 2)
|
||||
|
||||
entry({"mini", "network", "vnstat"}, alias("mini", "network", "vnstat", "graphs"), _("VnStat Traffic Monitor"), 90).i18n = "vnstat"
|
||||
entry({"mini", "network", "vnstat"}, alias("mini", "network", "vnstat", "graphs"), _("VnStat Traffic Monitor"), 90)
|
||||
entry({"mini", "network", "vnstat", "graphs"}, template("vnstat"), _("Graphs"), 1)
|
||||
entry({"mini", "network", "vnstat", "config"}, cbi("vnstat"), _("Configuration"), 2)
|
||||
end
|
||||
|
|
|
@ -18,18 +18,14 @@ function index()
|
|||
|
||||
e = entry({"admin", "voice"}, template("luci_voice/index") , _("Voice"), 90)
|
||||
e.index = true
|
||||
e.i18n = "voice_core"
|
||||
|
||||
e = entry({"mini", "voice"}, template("luci_voice/index"), _("Voice"), 90)
|
||||
e.index = true
|
||||
e.i18n = "voice_core"
|
||||
|
||||
e = entry({"mini", "voice", "phones"}, template("luci_voice/phone_index"), _("Phones"), 90)
|
||||
e.index = true
|
||||
e.i18n = "voice_core"
|
||||
|
||||
e = entry({"admin", "voice", "phones"}, template("luci_voice/phone_index"), _("Phones"), 90)
|
||||
e.index = true
|
||||
e.i18n = "voice_core"
|
||||
|
||||
end
|
||||
|
|
|
@ -18,6 +18,5 @@ function index()
|
|||
|
||||
e = entry({"admin", "voice", "diag"}, template("luci_voice/diag_index"), _("Diagnostics"), 90)
|
||||
e.index = true
|
||||
e.i18n = "voice_diag"
|
||||
e.dependent = true
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module("luci.controller.wol", package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "network", "wol"}, cbi("wol"), _("Wake on LAN"), 90).i18n = "wol"
|
||||
entry({"mini", "network", "wol"}, cbi("wol"), _("Wake on LAN"), 90).i18n = "wol"
|
||||
entry({"admin", "network", "wol"}, cbi("wol"), _("Wake on LAN"), 90)
|
||||
entry({"mini", "network", "wol"}, cbi("wol"), _("Wake on LAN"), 90)
|
||||
end
|
||||
|
|
|
@ -4,7 +4,8 @@ PATTERN=$1
|
|||
SCM=
|
||||
|
||||
[ -d .svn ] && SCM="svn"
|
||||
[ -d .git ] && SCM="git"
|
||||
git=$( which git 2>/dev/null )
|
||||
[ "$git" ] && "$git" status >/dev/null && SCM="git"
|
||||
|
||||
[ -z "$SCM" ] && {
|
||||
echo "Unsupported SCM tool" >&2
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
config 'community' 'profile'
|
||||
option 'name' 'Freifunk Hamburg'
|
||||
option 'homepage' 'http://hamburg.piratenpartei.de'
|
||||
option 'ssid' 'hamburg.freifunk.net'
|
||||
option 'mesh_network' '10.112.0.0/12'
|
||||
option 'splash_network' '10.104.0.0/16'
|
||||
option 'splash_prefix' '27'
|
||||
option 'latitude' '53.56262'
|
||||
option 'longitude' '10.01069'
|
||||
|
||||
config 'defaults' 'interface'
|
||||
option 'netmask' '255.240.0.0'
|
||||
|
||||
config 'defaults' 'wifi_device'
|
||||
option 'channel' '1'
|
|
@ -1,5 +1,6 @@
|
|||
#
|
||||
# Copyright (C) 2009 Andreas Seidler <tetzlav@subsignal.org>
|
||||
# Copyright (C) 2012 Jo-Philipp Wich <xm@subsignal.org>
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
|
@ -8,7 +9,7 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=freifunk-p2pblock
|
||||
PKG_RELEASE:=2
|
||||
PKG_RELEASE:=3
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ start() {
|
|||
config_get ipp2p p2pblock ipp2p
|
||||
config_get portrange p2pblock portrange
|
||||
config_get blocktime p2pblock blocktime
|
||||
config_get whitelist p2pblock whitelist
|
||||
|
||||
# load modules
|
||||
insmod ipt_ipp2p 2>&-
|
||||
|
|
|
@ -177,14 +177,13 @@ $(eval $(call library,fastindex,Fastindex indexing module,+PACKAGE_luci-lib-fast
|
|||
$(eval $(call library,httpclient,HTTP(S) client library,+luci-lib-web +luci-lib-nixio))
|
||||
$(eval $(call library,ipkg,LuCI IPKG/OPKG call abstraction library))
|
||||
$(eval $(call library,json,LuCI JSON library))
|
||||
$(eval $(call library,lmo,LuCI LMO I18N library))
|
||||
$(eval $(call library,lucid,LuCId Full-Stack Webserver,+luci-lib-nixio +luci-lib-web +luci-lib-px5g))
|
||||
$(eval $(call library,lucid-http,LuCId HTTP Backend,+luci-lib-lucid))
|
||||
$(eval $(call library,lucid-rpc,LuCId RPC Backend,+luci-lib-lucid))
|
||||
$(eval $(call library,nixio,NIXIO POSIX library,+PACKAGE_luci-lib-nixio_openssl:libopenssl +PACKAGE_luci-lib-nixio_cyassl:libcyassl))
|
||||
$(eval $(call library,px5g,RSA/X.509 Key Generator (required for LuCId SSL support),+luci-lib-nixio))
|
||||
$(eval $(call library,sys,LuCI Linux/POSIX system library))
|
||||
$(eval $(call library,web,MVC Webframework,+luci-lib-sys +luci-lib-nixio +luci-lib-core +luci-sgi-cgi +luci-lib-lmo))
|
||||
$(eval $(call library,web,MVC Webframework,+luci-lib-sys +luci-lib-nixio +luci-lib-core +luci-sgi-cgi))
|
||||
|
||||
|
||||
### Protocols ###
|
||||
|
@ -327,7 +326,7 @@ endef
|
|||
$(eval $(call application,siitwizard,SIIT IPv4-over-IPv6 configuration wizard,\
|
||||
+PACKAGE_luci-app-siitwizard:kmod-siit))
|
||||
|
||||
$(eval $(call application,firewall,Firmware and Portforwarding application,\
|
||||
$(eval $(call application,firewall,Firewall and Portforwarding application,\
|
||||
+PACKAGE_luci-app-firewall:firewall))
|
||||
|
||||
$(eval $(call application,freifunk-policyrouting,Policy routing for mesh traffic,\
|
||||
|
@ -380,6 +379,8 @@ $(eval $(call application,voice-core,LuCI Voice Software (Core)))
|
|||
$(eval $(call application,voice-diag,LuCI Voice Software (Diagnostics),\
|
||||
luci-app-diag-devinfo))
|
||||
|
||||
$(eval $(call application,commands,LuCI Shell Command Module))
|
||||
|
||||
$(eval $(call application,upnp,Universal Plug & Play configuration module,\
|
||||
+PACKAGE_luci-app-upnp:miniupnpd))
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/sh
|
||||
uci batch <<-EOF
|
||||
set luci.languages.pl='Język polski'
|
||||
set luci.languages.pl='Polski'
|
||||
commit luci
|
||||
EOF
|
||||
|
|
|
@ -20,7 +20,7 @@ limitations under the License.
|
|||
local type, pairs, ipairs, table, luci, math
|
||||
= type, pairs, ipairs, table, luci, math
|
||||
|
||||
local lmo = require "lmo"
|
||||
local tpl = require "luci.template.parser"
|
||||
local utl = require "luci.util"
|
||||
local uci = require "luci.model.uci"
|
||||
|
||||
|
@ -478,7 +478,7 @@ function zone.get_color(self)
|
|||
elseif self and self:name() == "wan" then
|
||||
return "#f09090"
|
||||
elseif self then
|
||||
math.randomseed(lmo.hash(self:name()))
|
||||
math.randomseed(tpl.hash(self:name()))
|
||||
|
||||
local r = math.random(128)
|
||||
local g = math.random(128)
|
||||
|
|
|
@ -623,6 +623,32 @@ function get_status_by_route(self, addr, mask)
|
|||
end
|
||||
end
|
||||
|
||||
function get_status_by_address(self, addr)
|
||||
local _, object
|
||||
for _, object in ipairs(_ubus:objects()) do
|
||||
local net = object:match("^network%.interface%.(.+)")
|
||||
if net then
|
||||
local s = _ubus:call(object, "status", {})
|
||||
if s and s['ipv4-address'] then
|
||||
local a
|
||||
for _, a in ipairs(s['ipv4-address']) do
|
||||
if a.address == addr then
|
||||
return net, s
|
||||
end
|
||||
end
|
||||
end
|
||||
if s and s['ipv6-address'] then
|
||||
local a
|
||||
for _, a in ipairs(s['ipv6-address']) do
|
||||
if a.address == addr then
|
||||
return net, s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function get_wannet(self)
|
||||
local net = self:get_status_by_route("0.0.0.0", 0)
|
||||
return net and network(net)
|
||||
|
|
|
@ -182,27 +182,18 @@ end
|
|||
-- String and data manipulation routines
|
||||
--
|
||||
|
||||
--- Escapes all occurrences of the given character in given string.
|
||||
-- @param s String value containing unescaped characters
|
||||
-- @param c String value with character to escape (optional, defaults to "\")
|
||||
-- @return String value with each occurrence of character escaped with "\"
|
||||
function escape(s, c)
|
||||
c = c or "\\"
|
||||
return s:gsub(c, "\\" .. c)
|
||||
end
|
||||
|
||||
--- Create valid XML PCDATA from given string.
|
||||
-- @param value String value containing the data to escape
|
||||
-- @return String value containing the escaped data
|
||||
function pcdata(value)
|
||||
return value and tparser.sanitize_pcdata(tostring(value))
|
||||
return value and tparser.pcdata(tostring(value))
|
||||
end
|
||||
|
||||
--- Strip HTML tags from given string.
|
||||
-- @param value String containing the HTML text
|
||||
-- @return String with HTML tags stripped of
|
||||
function striptags(s)
|
||||
return pcdata(tostring(s):gsub("</?[A-Za-z][A-Za-z0-9:_%-]*[^>]*>", " "):gsub("%s+", " "))
|
||||
function striptags(value)
|
||||
return value and tparser.striptags(tostring(value))
|
||||
end
|
||||
|
||||
--- Splits given string on a defined separator sequence and return a table
|
||||
|
@ -356,7 +347,6 @@ function parse_units(ustr)
|
|||
end
|
||||
|
||||
-- also register functions above in the central string class for convenience
|
||||
string.escape = escape
|
||||
string.pcdata = pcdata
|
||||
string.striptags = striptags
|
||||
string.split = split
|
||||
|
|
|
@ -10,7 +10,6 @@ You may obtain a copy of the License at
|
|||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
$Id$
|
||||
]]--
|
||||
|
||||
local os = require "os"
|
||||
|
@ -23,7 +22,7 @@ local pairs = pairs
|
|||
local error = error
|
||||
local table = table
|
||||
|
||||
local ipkg = "opkg --force-removal-of-dependent-packages --force-overwrite"
|
||||
local ipkg = "opkg --force-removal-of-dependent-packages --force-overwrite --nocase"
|
||||
local icfg = "/etc/opkg.conf"
|
||||
|
||||
--- LuCI OPKG call abstraction library
|
||||
|
@ -159,7 +158,7 @@ end
|
|||
-- List helper
|
||||
function _list(action, pat, cb)
|
||||
local fd = io.popen(ipkg .. " " .. action ..
|
||||
(pat and (" '%s'" % pat:gsub("'", "")) or "")) -- .. " | grep -vE '^ '")
|
||||
(pat and (" '%s'" % pat:gsub("'", "")) or ""))
|
||||
|
||||
if fd then
|
||||
local name, version, desc
|
||||
|
@ -167,20 +166,18 @@ function _list(action, pat, cb)
|
|||
local line = fd:read("*l")
|
||||
if not line then break end
|
||||
|
||||
if line:sub(1,1) ~= " " then
|
||||
name, version, desc = line:match("^(.-) %- (.-) %- (.+)")
|
||||
name, version, desc = line:match("^(.-) %- (.-) %- (.+)")
|
||||
|
||||
if not name then
|
||||
name, version = line:match("^(.-) %- (.+)")
|
||||
desc = ""
|
||||
end
|
||||
|
||||
cb(name, version, desc)
|
||||
|
||||
name = nil
|
||||
version = nil
|
||||
desc = nil
|
||||
if not name then
|
||||
name, version = line:match("^(.-) %- (.+)")
|
||||
desc = ""
|
||||
end
|
||||
|
||||
cb(name, version, desc)
|
||||
|
||||
name = nil
|
||||
version = nil
|
||||
desc = nil
|
||||
end
|
||||
|
||||
fd:close()
|
||||
|
@ -203,6 +200,15 @@ function list_installed(pat, cb)
|
|||
_list("list_installed", pat, cb)
|
||||
end
|
||||
|
||||
--- Find packages that match the given pattern.
|
||||
-- @param pat Find packages whose names or descriptions match this pattern, nil results in zero results
|
||||
-- @param cb Callback function invoked for each patckage, receives name, version and description as arguments
|
||||
-- @return nothing
|
||||
function find(pat, cb)
|
||||
_list("find", pat, cb)
|
||||
end
|
||||
|
||||
|
||||
--- Determines the overlay root used by opkg.
|
||||
-- @return String containing the directory path of the overlay root.
|
||||
function overlay_root()
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
ifneq (,$(wildcard ../../build/config.mk))
|
||||
include ../../build/config.mk
|
||||
include ../../build/module.mk
|
||||
include ../../build/gccconfig.mk
|
||||
else
|
||||
include standalone.mk
|
||||
endif
|
||||
|
||||
LMO_LDFLAGS =
|
||||
LMO_CFLAGS =
|
||||
LMO_SO = lmo.so
|
||||
LMO_PO2LMO = po2lmo
|
||||
LMO_LOOKUP = lookup
|
||||
LMO_COMMON_OBJ = src/lmo_core.o src/lmo_hash.o
|
||||
LMO_PO2LMO_OBJ = src/lmo_po2lmo.o
|
||||
LMO_LOOKUP_OBJ = src/lmo_lookup.o
|
||||
LMO_LUALIB_OBJ = src/lmo_lualib.o
|
||||
|
||||
%.o: %.c
|
||||
$(COMPILE) $(LMO_CFLAGS) $(LUA_CFLAGS) $(FPIC) -c -o $@ $<
|
||||
|
||||
compile: build-clean $(LMO_COMMON_OBJ) $(LMO_PO2LMO_OBJ) $(LMO_LOOKUP_OBJ) $(LMO_LUALIB_OBJ)
|
||||
$(LINK) $(SHLIB_FLAGS) $(LMO_LDFLAGS) -o src/$(LMO_SO) \
|
||||
$(LMO_COMMON_OBJ) $(LMO_LUALIB_OBJ)
|
||||
$(LINK) $(LMO_LDFLAGS) -o src/$(LMO_PO2LMO) $(LMO_COMMON_OBJ) $(LMO_PO2LMO_OBJ)
|
||||
$(LINK) $(LMO_LDFLAGS) -o src/$(LMO_LOOKUP) $(LMO_COMMON_OBJ) $(LMO_LOOKUP_OBJ)
|
||||
mkdir -p dist$(LUA_LIBRARYDIR)
|
||||
cp src/$(LMO_SO) dist$(LUA_LIBRARYDIR)/$(LMO_SO)
|
||||
|
||||
install: build
|
||||
cp -pR dist$(LUA_LIBRARYDIR)/* $(LUA_LIBRARYDIR)
|
||||
|
||||
clean: build-clean
|
||||
|
||||
build-clean:
|
||||
rm -f src/*.o src/lookup src/po2lmo src/lmo.so
|
||||
|
||||
host-compile: build-clean host-clean $(LMO_COMMON_OBJ) $(LMO_PO2LMO_OBJ)
|
||||
$(LINK) $(LMO_LDFLAGS) -o src/$(LMO_PO2LMO) $(LMO_COMMON_OBJ) $(LMO_PO2LMO_OBJ)
|
||||
|
||||
host-install: host-compile
|
||||
cp src/$(LMO_PO2LMO) ../../build/$(LMO_PO2LMO)
|
||||
|
||||
host-clean:
|
||||
rm -f ../../build/$(LMO_PO2LMO)
|
||||
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
* lmo - Lua Machine Objects - Base functions
|
||||
*
|
||||
* Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "lmo.h"
|
||||
|
||||
extern char _lmo_error[1024];
|
||||
|
||||
static int lmo_read32( int fd, uint32_t *val )
|
||||
{
|
||||
if( read(fd, val, 4) < 4 )
|
||||
return -1;
|
||||
|
||||
*val = ntohl(*val);
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
static char * error(const char *message, int add_errno)
|
||||
{
|
||||
memset(_lmo_error, 0, sizeof(_lmo_error));
|
||||
|
||||
if( add_errno )
|
||||
snprintf(_lmo_error, sizeof(_lmo_error),
|
||||
"%s: %s", message, strerror(errno));
|
||||
else
|
||||
snprintf(_lmo_error, sizeof(_lmo_error), "%s", message);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * lmo_error(void)
|
||||
{
|
||||
return _lmo_error;
|
||||
}
|
||||
|
||||
lmo_archive_t * lmo_open(const char *file)
|
||||
{
|
||||
int in = -1;
|
||||
uint32_t idx_offset = 0;
|
||||
uint32_t i;
|
||||
struct stat s;
|
||||
|
||||
lmo_archive_t *ar = NULL;
|
||||
lmo_entry_t *head = NULL;
|
||||
lmo_entry_t *entry = NULL;
|
||||
|
||||
if( stat(file, &s) == -1 )
|
||||
{
|
||||
error("Can not stat file", 1);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if( (in = open(file, O_RDONLY)) == -1 )
|
||||
{
|
||||
error("Can not open file", 1);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if( lseek(in, -sizeof(uint32_t), SEEK_END) == -1 )
|
||||
{
|
||||
error("Can not seek to eof", 1);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if( lmo_read32(in, &idx_offset) != 4 )
|
||||
{
|
||||
error("Unexpected EOF while reading index offset", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if( lseek(in, (off_t)idx_offset, SEEK_SET) == -1 )
|
||||
{
|
||||
error("Can not seek to index offset", 1);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if( (ar = (lmo_archive_t *) malloc(sizeof(lmo_archive_t))) != NULL )
|
||||
{
|
||||
ar->fd = in;
|
||||
ar->length = idx_offset;
|
||||
|
||||
fcntl(ar->fd, F_SETFD, fcntl(ar->fd, F_GETFD) | FD_CLOEXEC);
|
||||
|
||||
for( i = idx_offset;
|
||||
i < (s.st_size - sizeof(uint32_t));
|
||||
i += (4 * sizeof(uint32_t))
|
||||
) {
|
||||
if( (entry = (lmo_entry_t *) malloc(sizeof(lmo_entry_t))) != NULL )
|
||||
{
|
||||
if( (lmo_read32(ar->fd, &entry->key_id) == 4) &&
|
||||
(lmo_read32(ar->fd, &entry->val_id) == 4) &&
|
||||
(lmo_read32(ar->fd, &entry->offset) == 4) &&
|
||||
(lmo_read32(ar->fd, &entry->length) == 4)
|
||||
) {
|
||||
entry->next = head;
|
||||
head = entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Unexpected EOF while reading index entry", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Out of memory", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ar->index = head;
|
||||
|
||||
if( lseek(ar->fd, 0, SEEK_SET) == -1 )
|
||||
{
|
||||
error("Can not seek to start", 1);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if( (ar->mmap = mmap(NULL, ar->length, PROT_READ, MAP_PRIVATE, ar->fd, 0)) == MAP_FAILED )
|
||||
{
|
||||
error("Failed to memory map archive contents", 1);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return ar;
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Out of memory", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
cleanup:
|
||||
|
||||
if( in > -1 )
|
||||
close(in);
|
||||
|
||||
if( head != NULL )
|
||||
{
|
||||
entry = head;
|
||||
|
||||
while( entry != NULL )
|
||||
{
|
||||
head = entry->next;
|
||||
free(entry);
|
||||
entry = head;
|
||||
}
|
||||
|
||||
head = entry = NULL;
|
||||
}
|
||||
|
||||
if( ar != NULL )
|
||||
{
|
||||
if( (ar->mmap != NULL) && (ar->mmap != MAP_FAILED) )
|
||||
munmap(ar->mmap, ar->length);
|
||||
|
||||
free(ar);
|
||||
ar = NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void lmo_close(lmo_archive_t *ar)
|
||||
{
|
||||
lmo_entry_t *head = NULL;
|
||||
lmo_entry_t *entry = NULL;
|
||||
|
||||
if( ar != NULL )
|
||||
{
|
||||
entry = ar->index;
|
||||
|
||||
while( entry != NULL )
|
||||
{
|
||||
head = entry->next;
|
||||
free(entry);
|
||||
entry = head;
|
||||
}
|
||||
|
||||
head = entry = NULL;
|
||||
|
||||
if( (ar->mmap != NULL) && (ar->mmap != MAP_FAILED) )
|
||||
munmap(ar->mmap, ar->length);
|
||||
|
||||
close(ar->fd);
|
||||
free(ar);
|
||||
|
||||
ar = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int lmo_lookup(lmo_archive_t *ar, const char *key, char *dest, int len)
|
||||
{
|
||||
uint32_t look_key = sfh_hash(key, strlen(key));
|
||||
int copy_len = -1;
|
||||
lmo_entry_t *entry;
|
||||
|
||||
if( !ar )
|
||||
return copy_len;
|
||||
|
||||
entry = ar->index;
|
||||
|
||||
while( entry != NULL )
|
||||
{
|
||||
if( entry->key_id == look_key )
|
||||
{
|
||||
copy_len = ((len - 1) > entry->length) ? entry->length : (len - 1);
|
||||
memcpy(dest, &ar->mmap[entry->offset], copy_len);
|
||||
dest[copy_len] = '\0';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
return copy_len;
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Hash function from http://www.azillionmonkeys.com/qed/hash.html
|
||||
* Copyright (C) 2004-2008 by Paul Hsieh
|
||||
*/
|
||||
|
||||
#include "lmo.h"
|
||||
|
||||
uint32_t sfh_hash(const char * data, int len)
|
||||
{
|
||||
uint32_t hash = len, tmp;
|
||||
int rem;
|
||||
|
||||
if (len <= 0 || data == NULL) return 0;
|
||||
|
||||
rem = len & 3;
|
||||
len >>= 2;
|
||||
|
||||
/* Main loop */
|
||||
for (;len > 0; len--) {
|
||||
hash += sfh_get16(data);
|
||||
tmp = (sfh_get16(data+2) << 11) ^ hash;
|
||||
hash = (hash << 16) ^ tmp;
|
||||
data += 2*sizeof(uint16_t);
|
||||
hash += hash >> 11;
|
||||
}
|
||||
|
||||
/* Handle end cases */
|
||||
switch (rem) {
|
||||
case 3: hash += sfh_get16(data);
|
||||
hash ^= hash << 16;
|
||||
hash ^= data[sizeof(uint16_t)] << 18;
|
||||
hash += hash >> 11;
|
||||
break;
|
||||
case 2: hash += sfh_get16(data);
|
||||
hash ^= hash << 11;
|
||||
hash += hash >> 17;
|
||||
break;
|
||||
case 1: hash += *data;
|
||||
hash ^= hash << 10;
|
||||
hash += hash >> 1;
|
||||
}
|
||||
|
||||
/* Force "avalanching" of final 127 bits */
|
||||
hash ^= hash << 3;
|
||||
hash += hash >> 5;
|
||||
hash ^= hash << 4;
|
||||
hash += hash >> 17;
|
||||
hash ^= hash << 25;
|
||||
hash += hash >> 6;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* lmo - Lua Machine Objects - Lookup utility
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "lmo.h"
|
||||
|
||||
extern char _lmo_error[1024];
|
||||
|
||||
static void die(const char *msg)
|
||||
{
|
||||
printf("Error: %s\n", msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void usage(const char *name)
|
||||
{
|
||||
printf("Usage: %s input.lmo key\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char val[4096];
|
||||
lmo_archive_t *ar = NULL;
|
||||
|
||||
if( argc != 3 )
|
||||
usage(argv[0]);
|
||||
|
||||
if( (ar = (lmo_archive_t *) lmo_open(argv[1])) != NULL )
|
||||
{
|
||||
if( lmo_lookup(ar, argv[2], val, sizeof(val)) > -1 )
|
||||
{
|
||||
printf("%s\n", val);
|
||||
}
|
||||
|
||||
lmo_close(ar);
|
||||
}
|
||||
else
|
||||
{
|
||||
die(lmo_error());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,237 +0,0 @@
|
|||
/*
|
||||
* lmo - Lua Machine Objects - Lua binding
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "lmo_lualib.h"
|
||||
|
||||
extern char _lmo_error[1024];
|
||||
|
||||
|
||||
static int lmo_L_open(lua_State *L) {
|
||||
const char *filename = luaL_checklstring(L, 1, NULL);
|
||||
lmo_archive_t *ar, **udata;
|
||||
|
||||
if( (ar = lmo_open(filename)) != NULL )
|
||||
{
|
||||
if( (udata = lua_newuserdata(L, sizeof(lmo_archive_t *))) != NULL )
|
||||
{
|
||||
*udata = ar;
|
||||
luaL_getmetatable(L, LMO_ARCHIVE_META);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lmo_close(ar);
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "out of memory");
|
||||
return 2;
|
||||
}
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, lmo_error());
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int lmo_L_hash(lua_State *L) {
|
||||
const char *data = luaL_checkstring(L, 1);
|
||||
uint32_t hash = sfh_hash(data, strlen(data));
|
||||
lua_pushinteger(L, (lua_Integer)hash);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static lmo_luaentry_t *_lmo_push_entry(lua_State *L) {
|
||||
lmo_luaentry_t *le;
|
||||
|
||||
if( (le = lua_newuserdata(L, sizeof(lmo_luaentry_t))) != NULL )
|
||||
{
|
||||
luaL_getmetatable(L, LMO_ENTRY_META);
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
return le;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _lmo_lookup(lua_State *L, lmo_archive_t *ar, uint32_t hash) {
|
||||
lmo_entry_t *e = ar->index;
|
||||
lmo_luaentry_t *le = NULL;
|
||||
|
||||
while( e != NULL )
|
||||
{
|
||||
if( e->key_id == hash )
|
||||
{
|
||||
if( (le = _lmo_push_entry(L)) != NULL )
|
||||
{
|
||||
le->archive = ar;
|
||||
le->entry = e;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "out of memory");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lmo_L_get(lua_State *L) {
|
||||
lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
|
||||
uint32_t hash = (uint32_t) luaL_checkinteger(L, 2);
|
||||
return _lmo_lookup(L, *ar, hash);
|
||||
}
|
||||
|
||||
static int lmo_L_lookup(lua_State *L) {
|
||||
lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
|
||||
const char *key = luaL_checkstring(L, 2);
|
||||
uint32_t hash = sfh_hash(key, strlen(key));
|
||||
return _lmo_lookup(L, *ar, hash);
|
||||
}
|
||||
|
||||
static int lmo_L_foreach(lua_State *L) {
|
||||
lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
|
||||
lmo_entry_t *e = (*ar)->index;
|
||||
|
||||
if( lua_isfunction(L, 2) )
|
||||
{
|
||||
while( e != NULL )
|
||||
{
|
||||
lua_pushvalue(L, 2);
|
||||
lua_pushinteger(L, e->key_id);
|
||||
lua_pushlstring(L, &(*ar)->mmap[e->offset], e->length);
|
||||
lua_pcall(L, 2, 0, 0);
|
||||
e = e->next;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lmo_L__gc(lua_State *L) {
|
||||
lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
|
||||
|
||||
if( (*ar) != NULL )
|
||||
lmo_close(*ar);
|
||||
|
||||
*ar = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lmo_L__tostring(lua_State *L) {
|
||||
lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
|
||||
lua_pushfstring(L, "LMO Archive (%d bytes)", (*ar)->length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int _lmo_convert_entry(lua_State *L, int idx) {
|
||||
lmo_luaentry_t *le = luaL_checkudata(L, idx, LMO_ENTRY_META);
|
||||
|
||||
lua_pushlstring(L,
|
||||
&le->archive->mmap[le->entry->offset],
|
||||
le->entry->length
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lmo_L_entry__tostring(lua_State *L) {
|
||||
return _lmo_convert_entry(L, 1);
|
||||
}
|
||||
|
||||
static int lmo_L_entry__concat(lua_State *L) {
|
||||
if( lua_isuserdata(L, 1) )
|
||||
_lmo_convert_entry(L, 1);
|
||||
else
|
||||
lua_pushstring(L, lua_tostring(L, 1));
|
||||
|
||||
if( lua_isuserdata(L, 2) )
|
||||
_lmo_convert_entry(L, 2);
|
||||
else
|
||||
lua_pushstring(L, lua_tostring(L, 2));
|
||||
|
||||
lua_concat(L, 2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lmo_L_entry__len(lua_State *L) {
|
||||
lmo_luaentry_t *le = luaL_checkudata(L, 1, LMO_ENTRY_META);
|
||||
lua_pushinteger(L, le->entry->length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lmo_L_entry__gc(lua_State *L) {
|
||||
lmo_luaentry_t *le = luaL_checkudata(L, 1, LMO_ENTRY_META);
|
||||
le->archive = NULL;
|
||||
le->entry = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* lmo method table */
|
||||
static const luaL_reg M[] = {
|
||||
{"close", lmo_L__gc},
|
||||
{"get", lmo_L_get},
|
||||
{"lookup", lmo_L_lookup},
|
||||
{"foreach", lmo_L_foreach},
|
||||
{"__tostring", lmo_L__tostring},
|
||||
{"__gc", lmo_L__gc},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* lmo.entry method table */
|
||||
static const luaL_reg E[] = {
|
||||
{"__tostring", lmo_L_entry__tostring},
|
||||
{"__concat", lmo_L_entry__concat},
|
||||
{"__len", lmo_L_entry__len},
|
||||
{"__gc", lmo_L_entry__gc},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* module table */
|
||||
static const luaL_reg R[] = {
|
||||
{"open", lmo_L_open},
|
||||
{"hash", lmo_L_hash},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
LUALIB_API int luaopen_lmo(lua_State *L) {
|
||||
luaL_newmetatable(L, LMO_ARCHIVE_META);
|
||||
luaL_register(L, NULL, M);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setglobal(L, LMO_ARCHIVE_META);
|
||||
|
||||
luaL_newmetatable(L, LMO_ENTRY_META);
|
||||
luaL_register(L, NULL, E);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setglobal(L, LMO_ENTRY_META);
|
||||
|
||||
luaL_register(L, LMO_LUALIB_META, R);
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* lmo - Lua Machine Objects - Lua library header
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _LMO_LUALIB_H_
|
||||
#define _LMO_LUALIB_H_
|
||||
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
#include "lmo.h"
|
||||
|
||||
#define LMO_LUALIB_META "lmo"
|
||||
#define LMO_ARCHIVE_META "lmo.archive"
|
||||
#define LMO_ENTRY_META "lmo.entry"
|
||||
|
||||
struct lmo_luaentry {
|
||||
lmo_archive_t *archive;
|
||||
lmo_entry_t *entry;
|
||||
};
|
||||
|
||||
typedef struct lmo_luaentry lmo_luaentry_t;
|
||||
|
||||
|
||||
LUALIB_API int luaopen_lmo(lua_State *L);
|
||||
|
||||
#endif
|
|
@ -1,19 +1,28 @@
|
|||
ifneq (,$(wildcard ../../build/config.mk))
|
||||
include ../../build/config.mk
|
||||
include ../../build/module.mk
|
||||
include ../../build/gccconfig.mk
|
||||
else
|
||||
include standalone.mk
|
||||
endif
|
||||
|
||||
TPL_LDFLAGS =
|
||||
TPL_CFLAGS =
|
||||
TPL_SO = parser.so
|
||||
TPL_PO2LMO = po2lmo
|
||||
TPL_PO2LMO_OBJ = src/po2lmo.o
|
||||
TPL_LMO_OBJ = src/template_lmo.o
|
||||
TPL_COMMON_OBJ = src/template_parser.o src/template_utils.o
|
||||
TPL_LUALIB_OBJ = src/template_lualib.o
|
||||
|
||||
%.o: %.c
|
||||
$(COMPILE) $(TPL_CFLAGS) $(LUA_CFLAGS) $(FPIC) -c -o $@ $<
|
||||
|
||||
compile: build-clean $(TPL_COMMON_OBJ) $(TPL_LUALIB_OBJ)
|
||||
compile: build-clean $(TPL_COMMON_OBJ) $(TPL_LUALIB_OBJ) $(TPL_LMO_OBJ) $(TPL_PO2LMO_OBJ)
|
||||
$(LINK) $(SHLIB_FLAGS) $(TPL_LDFLAGS) -o src/$(TPL_SO) \
|
||||
$(TPL_COMMON_OBJ) $(TPL_LUALIB_OBJ)
|
||||
$(TPL_COMMON_OBJ) $(TPL_LMO_OBJ) $(TPL_LUALIB_OBJ)
|
||||
$(LINK) -o src/$(TPL_PO2LMO) \
|
||||
$(TPL_LMO_OBJ) $(TPL_PO2LMO_OBJ)
|
||||
mkdir -p dist$(LUCI_LIBRARYDIR)/template
|
||||
cp src/$(TPL_SO) dist$(LUCI_LIBRARYDIR)/template/$(TPL_SO)
|
||||
|
||||
|
@ -24,3 +33,12 @@ clean: build-clean
|
|||
|
||||
build-clean:
|
||||
rm -f src/*.o src/$(TPL_SO)
|
||||
|
||||
host-compile: build-clean host-clean $(TPL_LMO_OBJ) $(TPL_PO2LMO_OBJ)
|
||||
$(LINK) -o src/$(TPL_PO2LMO) $(TPL_LMO_OBJ) $(TPL_PO2LMO_OBJ)
|
||||
|
||||
host-install: host-compile
|
||||
cp src/$(TPL_PO2LMO) ../../build/$(TPL_PO2LMO)
|
||||
|
||||
host-clean:
|
||||
rm -f ../../build/$(TPL_PO2LMO)
|
||||
|
|
|
@ -1097,216 +1097,243 @@ function cbi_tag_last(container)
|
|||
}
|
||||
}
|
||||
|
||||
if( ! String.serialize )
|
||||
String.serialize = function(o)
|
||||
String.prototype.serialize = function()
|
||||
{
|
||||
var o = this;
|
||||
switch(typeof(o))
|
||||
{
|
||||
switch(typeof(o))
|
||||
{
|
||||
case 'object':
|
||||
// null
|
||||
if( o == null )
|
||||
{
|
||||
return 'null';
|
||||
}
|
||||
|
||||
// array
|
||||
else if( o.length )
|
||||
{
|
||||
var i, s = '';
|
||||
|
||||
for( var i = 0; i < o.length; i++ )
|
||||
s += (s ? ', ' : '') + String.serialize(o[i]);
|
||||
|
||||
return '[ ' + s + ' ]';
|
||||
}
|
||||
|
||||
// object
|
||||
else
|
||||
{
|
||||
var k, s = '';
|
||||
|
||||
for( k in o )
|
||||
s += (s ? ', ' : '') + k + ': ' + String.serialize(o[k]);
|
||||
|
||||
return '{ ' + s + ' }';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
// complex string
|
||||
if( o.match(/[^a-zA-Z0-9_,.: -]/) )
|
||||
return 'decodeURIComponent("' + encodeURIComponent(o) + '")';
|
||||
|
||||
// simple string
|
||||
else
|
||||
return '"' + o + '"';
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( ! String.format )
|
||||
String.format = function()
|
||||
{
|
||||
if (!arguments || arguments.length < 1 || !RegExp)
|
||||
return;
|
||||
|
||||
var html_esc = [/&/g, '&', /"/g, '"', /'/g, ''', /</g, '<', />/g, '>'];
|
||||
var quot_esc = [/"/g, '"', /'/g, '''];
|
||||
|
||||
function esc(s, r) {
|
||||
for( var i = 0; i < r.length; i += 2 )
|
||||
s = s.replace(r[i], r[i+1]);
|
||||
return s;
|
||||
}
|
||||
|
||||
var str = arguments[0];
|
||||
var out = '';
|
||||
var re = /^(([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X|q|h|j|t|m))/;
|
||||
var a = b = [], numSubstitutions = 0, numMatches = 0;
|
||||
|
||||
while( a = re.exec(str) )
|
||||
{
|
||||
var m = a[1];
|
||||
var leftpart = a[2], pPad = a[3], pJustify = a[4], pMinLength = a[5];
|
||||
var pPrecision = a[6], pType = a[7];
|
||||
|
||||
numMatches++;
|
||||
|
||||
if (pType == '%')
|
||||
case 'object':
|
||||
// null
|
||||
if( o == null )
|
||||
{
|
||||
subst = '%';
|
||||
return 'null';
|
||||
}
|
||||
|
||||
// array
|
||||
else if( o.length )
|
||||
{
|
||||
var i, s = '';
|
||||
|
||||
for( var i = 0; i < o.length; i++ )
|
||||
s += (s ? ', ' : '') + String.serialize(o[i]);
|
||||
|
||||
return '[ ' + s + ' ]';
|
||||
}
|
||||
|
||||
// object
|
||||
else
|
||||
{
|
||||
if (numSubstitutions++ < arguments.length)
|
||||
{
|
||||
var param = arguments[numSubstitutions];
|
||||
var k, s = '';
|
||||
|
||||
var pad = '';
|
||||
if (pPad && pPad.substr(0,1) == "'")
|
||||
pad = leftpart.substr(1,1);
|
||||
else if (pPad)
|
||||
pad = pPad;
|
||||
for( k in o )
|
||||
s += (s ? ', ' : '') + k + ': ' + String.serialize(o[k]);
|
||||
|
||||
var justifyRight = true;
|
||||
if (pJustify && pJustify === "-")
|
||||
justifyRight = false;
|
||||
|
||||
var minLength = -1;
|
||||
if (pMinLength)
|
||||
minLength = parseInt(pMinLength);
|
||||
|
||||
var precision = -1;
|
||||
if (pPrecision && pType == 'f')
|
||||
precision = parseInt(pPrecision.substring(1));
|
||||
|
||||
var subst = param;
|
||||
|
||||
switch(pType)
|
||||
{
|
||||
case 'b':
|
||||
subst = (parseInt(param) || 0).toString(2);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
subst = String.fromCharCode(parseInt(param) || 0);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
subst = (parseInt(param) || 0);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
subst = Math.abs(parseInt(param) || 0);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
subst = (precision > -1)
|
||||
? ((parseFloat(param) || 0.0)).toFixed(precision)
|
||||
: (parseFloat(param) || 0.0);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
subst = (parseInt(param) || 0).toString(8);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
subst = param;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
subst = ('' + (parseInt(param) || 0).toString(16)).toLowerCase();
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
subst = ('' + (parseInt(param) || 0).toString(16)).toUpperCase();
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
subst = esc(param, html_esc);
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
subst = esc(param, quot_esc);
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
subst = String.serialize(param);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
var td = 0;
|
||||
var th = 0;
|
||||
var tm = 0;
|
||||
var ts = (param || 0);
|
||||
|
||||
if (ts > 60) {
|
||||
tm = Math.floor(ts / 60);
|
||||
ts = (ts % 60);
|
||||
}
|
||||
|
||||
if (tm > 60) {
|
||||
th = Math.floor(tm / 60);
|
||||
tm = (tm % 60);
|
||||
}
|
||||
|
||||
if (th > 24) {
|
||||
td = Math.floor(th / 24);
|
||||
th = (th % 24);
|
||||
}
|
||||
|
||||
subst = (td > 0)
|
||||
? String.format('%dd %dh %dm %ds', td, th, tm, ts)
|
||||
: String.format('%dh %dm %ds', th, tm, ts);
|
||||
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
var mf = pMinLength ? parseInt(pMinLength) : 1000;
|
||||
var pr = pPrecision ? Math.floor(10*parseFloat('0'+pPrecision)) : 2;
|
||||
|
||||
var i = 0;
|
||||
var val = parseFloat(param || 0);
|
||||
var units = [ '', 'K', 'M', 'G', 'T', 'P', 'E' ];
|
||||
|
||||
for (i = 0; (i < units.length) && (val > mf); i++)
|
||||
val /= mf;
|
||||
|
||||
subst = val.toFixed(pr) + ' ' + units[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return '{ ' + s + ' }';
|
||||
}
|
||||
|
||||
out += leftpart + subst;
|
||||
str = str.substr(m.length);
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
// complex string
|
||||
if( o.match(/[^a-zA-Z0-9_,.: -]/) )
|
||||
return 'decodeURIComponent("' + encodeURIComponent(o) + '")';
|
||||
|
||||
// simple string
|
||||
else
|
||||
return '"' + o + '"';
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
|
||||
String.prototype.format = function()
|
||||
{
|
||||
if (!RegExp)
|
||||
return;
|
||||
|
||||
var html_esc = [/&/g, '&', /"/g, '"', /'/g, ''', /</g, '<', />/g, '>'];
|
||||
var quot_esc = [/"/g, '"', /'/g, '''];
|
||||
|
||||
function esc(s, r) {
|
||||
for( var i = 0; i < r.length; i += 2 )
|
||||
s = s.replace(r[i], r[i+1]);
|
||||
return s;
|
||||
}
|
||||
|
||||
var str = this;
|
||||
var out = '';
|
||||
var re = /^(([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X|q|h|j|t|m))/;
|
||||
var a = b = [], numSubstitutions = 0, numMatches = 0;
|
||||
|
||||
while( a = re.exec(str) )
|
||||
{
|
||||
var m = a[1];
|
||||
var leftpart = a[2], pPad = a[3], pJustify = a[4], pMinLength = a[5];
|
||||
var pPrecision = a[6], pType = a[7];
|
||||
|
||||
numMatches++;
|
||||
|
||||
if (pType == '%')
|
||||
{
|
||||
subst = '%';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numSubstitutions < arguments.length)
|
||||
{
|
||||
var param = arguments[numSubstitutions++];
|
||||
|
||||
var pad = '';
|
||||
if (pPad && pPad.substr(0,1) == "'")
|
||||
pad = leftpart.substr(1,1);
|
||||
else if (pPad)
|
||||
pad = pPad;
|
||||
|
||||
var justifyRight = true;
|
||||
if (pJustify && pJustify === "-")
|
||||
justifyRight = false;
|
||||
|
||||
var minLength = -1;
|
||||
if (pMinLength)
|
||||
minLength = parseInt(pMinLength);
|
||||
|
||||
var precision = -1;
|
||||
if (pPrecision && pType == 'f')
|
||||
precision = parseInt(pPrecision.substring(1));
|
||||
|
||||
var subst = param;
|
||||
|
||||
switch(pType)
|
||||
{
|
||||
case 'b':
|
||||
subst = (parseInt(param) || 0).toString(2);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
subst = String.fromCharCode(parseInt(param) || 0);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
subst = (parseInt(param) || 0);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
subst = Math.abs(parseInt(param) || 0);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
subst = (precision > -1)
|
||||
? ((parseFloat(param) || 0.0)).toFixed(precision)
|
||||
: (parseFloat(param) || 0.0);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
subst = (parseInt(param) || 0).toString(8);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
subst = param;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
subst = ('' + (parseInt(param) || 0).toString(16)).toLowerCase();
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
subst = ('' + (parseInt(param) || 0).toString(16)).toUpperCase();
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
subst = esc(param, html_esc);
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
subst = esc(param, quot_esc);
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
subst = String.serialize(param);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
var td = 0;
|
||||
var th = 0;
|
||||
var tm = 0;
|
||||
var ts = (param || 0);
|
||||
|
||||
if (ts > 60) {
|
||||
tm = Math.floor(ts / 60);
|
||||
ts = (ts % 60);
|
||||
}
|
||||
|
||||
if (tm > 60) {
|
||||
th = Math.floor(tm / 60);
|
||||
tm = (tm % 60);
|
||||
}
|
||||
|
||||
if (th > 24) {
|
||||
td = Math.floor(th / 24);
|
||||
th = (th % 24);
|
||||
}
|
||||
|
||||
subst = (td > 0)
|
||||
? String.format('%dd %dh %dm %ds', td, th, tm, ts)
|
||||
: String.format('%dh %dm %ds', th, tm, ts);
|
||||
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
var mf = pMinLength ? parseInt(pMinLength) : 1000;
|
||||
var pr = pPrecision ? Math.floor(10*parseFloat('0'+pPrecision)) : 2;
|
||||
|
||||
var i = 0;
|
||||
var val = parseFloat(param || 0);
|
||||
var units = [ '', 'K', 'M', 'G', 'T', 'P', 'E' ];
|
||||
|
||||
for (i = 0; (i < units.length) && (val > mf); i++)
|
||||
val /= mf;
|
||||
|
||||
subst = val.toFixed(pr) + ' ' + units[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out + str;
|
||||
out += leftpart + subst;
|
||||
str = str.substr(m.length);
|
||||
}
|
||||
|
||||
return out + str;
|
||||
}
|
||||
|
||||
String.prototype.nobr = function()
|
||||
{
|
||||
return this.replace(/[\s\n]+/g, ' ');
|
||||
}
|
||||
|
||||
String.serialize = function()
|
||||
{
|
||||
var a = [ ];
|
||||
for (var i = 1; i < arguments.length; i++)
|
||||
a.push(arguments[i]);
|
||||
return ''.serialize.apply(arguments[0], a);
|
||||
}
|
||||
|
||||
String.format = function()
|
||||
{
|
||||
var a = [ ];
|
||||
for (var i = 1; i < arguments.length; i++)
|
||||
a.push(arguments[i]);
|
||||
return ''.format.apply(arguments[0], a);
|
||||
}
|
||||
|
||||
String.nobr = function()
|
||||
{
|
||||
var a = [ ];
|
||||
for (var i = 1; i < arguments.length; i++)
|
||||
a.push(arguments[i]);
|
||||
return ''.nobr.apply(arguments[0], a);
|
||||
}
|
||||
|
|
|
@ -74,8 +74,6 @@ function load(cbimap, ...)
|
|||
|
||||
assert(func, err)
|
||||
|
||||
luci.i18n.loadc("base")
|
||||
|
||||
local env = {
|
||||
translate=i18n.translate,
|
||||
translatef=i18n.translatef,
|
||||
|
|
|
@ -4,9 +4,6 @@ LuCI - HTTP-Interaction
|
|||
Description:
|
||||
HTTP-Header manipulator and form variable preprocessor
|
||||
|
||||
FileId:
|
||||
$Id$
|
||||
|
||||
License:
|
||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
|
||||
|
@ -334,12 +331,14 @@ function write_json(x)
|
|||
end
|
||||
elseif type(x) == "number" or type(x) == "boolean" then
|
||||
if (x ~= x) then
|
||||
-- NaN is the only value that doesn't equal to itself.
|
||||
-- NaN is the only value that doesn't equal to itself.
|
||||
write("Number.NaN")
|
||||
else
|
||||
write(tostring(x))
|
||||
end
|
||||
else
|
||||
write("%q" % tostring(x))
|
||||
write('"%s"' % tostring(x):gsub('["%z\1-\31]', function(c)
|
||||
return '\\u%04x' % c:byte(1)
|
||||
end))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,7 +27,8 @@ limitations under the License.
|
|||
--- LuCI translation library.
|
||||
module("luci.i18n", package.seeall)
|
||||
require("luci.util")
|
||||
require("lmo")
|
||||
|
||||
local tparser = require "luci.template.parser"
|
||||
|
||||
table = {}
|
||||
i18ndir = luci.util.libpath() .. "/i18n/"
|
||||
|
@ -37,7 +38,6 @@ default = "en"
|
|||
|
||||
--- Clear the translation table.
|
||||
function clear()
|
||||
table = {}
|
||||
end
|
||||
|
||||
--- Load a translation and copy its data into the translation table.
|
||||
|
@ -46,33 +46,6 @@ end
|
|||
-- @param force Force reload even if already loaded (optional)
|
||||
-- @return Success status
|
||||
function load(file, lang, force)
|
||||
lang = lang and lang:gsub("_", "-") or ""
|
||||
if force or not loaded[lang] or not loaded[lang][file] then
|
||||
local f = lmo.open(i18ndir .. file .. "." .. lang .. ".lmo")
|
||||
if f then
|
||||
if not table[lang] then
|
||||
table[lang] = { f }
|
||||
setmetatable(table[lang], {
|
||||
__index = function(tbl, key)
|
||||
for i = 1, #tbl do
|
||||
local s = rawget(tbl, i):lookup(key)
|
||||
if s then return s end
|
||||
end
|
||||
end
|
||||
})
|
||||
else
|
||||
table[lang][#table[lang]+1] = f
|
||||
end
|
||||
|
||||
loaded[lang] = loaded[lang] or {}
|
||||
loaded[lang][file] = true
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--- Load a translation file using the default translation language.
|
||||
|
@ -80,9 +53,6 @@ end
|
|||
-- @param file Language file
|
||||
-- @param force Force reload even if already loaded (optional)
|
||||
function loadc(file, force)
|
||||
load(file, default, force)
|
||||
if context.parent then load(file, context.parent, force) end
|
||||
return load(file, context.lang, force)
|
||||
end
|
||||
|
||||
--- Set the context default translation language.
|
||||
|
@ -90,16 +60,20 @@ end
|
|||
function setlanguage(lang)
|
||||
context.lang = lang:gsub("_", "-")
|
||||
context.parent = (context.lang:match("^([a-z][a-z])_"))
|
||||
if not tparser.load_catalog(context.lang, i18ndir) then
|
||||
if context.parent then
|
||||
tparser.load_catalog(context.parent, i18ndir)
|
||||
return context.parent
|
||||
end
|
||||
end
|
||||
return context.lang
|
||||
end
|
||||
|
||||
--- Return the translated value for a specific translation key.
|
||||
-- @param key Default translation text
|
||||
-- @return Translated string
|
||||
function translate(key)
|
||||
return (table[context.lang] and table[context.lang][key])
|
||||
or (table[context.parent] and table[context.parent][key])
|
||||
or (table[default] and table[default][key])
|
||||
or key
|
||||
return tparser.translate(key) or key
|
||||
end
|
||||
|
||||
--- Return the translated value for a specific translation key and use it as sprintf pattern.
|
||||
|
|
|
@ -79,9 +79,8 @@ function Template.__init__(self, name)
|
|||
-- If we have no valid template throw error, otherwise cache the template
|
||||
if not self.template then
|
||||
error("Failed to load template '" .. name .. "'.\n" ..
|
||||
"Error while parsing template '" .. sourcefile .. "'.\n" ..
|
||||
"A syntax error occured near '" ..
|
||||
(err or "(nil)"):gsub("\t", "\\t"):gsub("\n", "\\n") .. "'.")
|
||||
"Error while parsing template '" .. sourcefile .. "':\n" ..
|
||||
(err or "Unknown syntax error"))
|
||||
else
|
||||
self.cache[name] = self.template
|
||||
end
|
||||
|
|
|
@ -38,6 +38,6 @@
|
|||
//]]></script>
|
||||
|
||||
<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" />
|
||||
<span id="cbi-apply-<%=id%>-status"><%:Waiting for router...%></span>
|
||||
<span id="cbi-apply-<%=id%>-status"><%:Waiting for changes to be applied...%></span>
|
||||
</fieldset>
|
||||
<%- end) %>
|
||||
|
|
|
@ -9,11 +9,15 @@
|
|||
<% if flow.skip then %>
|
||||
<input class="cbi-button cbi-button-skip" type="submit" name="cbi.skip" value="<%:Skip%>" />
|
||||
<% end %>
|
||||
<% if not autoapply then %>
|
||||
<% if not autoapply and not flow.hideapplybtn then %>
|
||||
<input class="cbi-button cbi-button-apply" type="submit" name="cbi.apply" value="<%:Save & Apply%>" />
|
||||
<% end %>
|
||||
<input class="cbi-button cbi-button-save" type="submit" value="<%:Save%>" />
|
||||
<input class="cbi-button cbi-button-reset" type="reset" value="<%:Reset%>" />
|
||||
<% if not flow.hidesavebtn then %>
|
||||
<input class="cbi-button cbi-button-save" type="submit" value="<%:Save%>" />
|
||||
<% end %>
|
||||
<% if not flow.hideresetbtn then %>
|
||||
<input class="cbi-button cbi-button-reset" type="reset" value="<%:Reset%>" />
|
||||
<% end %>
|
||||
|
||||
<script type="text/javascript">cbi_d_update();</script>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* lmo - Lua Machine Objects - PO to LMO conversion tool
|
||||
*
|
||||
* Copyright (C) 2009-2011 Jo-Philipp Wich <xm@subsignal.org>
|
||||
* Copyright (C) 2009-2012 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,7 +16,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "lmo.h"
|
||||
#include "template_lmo.h"
|
||||
|
||||
static void die(const char *msg)
|
||||
{
|
||||
|
@ -52,12 +52,19 @@ static int extract_string(const char *src, char *dest, int len)
|
|||
{
|
||||
if( esc == 1 )
|
||||
{
|
||||
switch (src[pos])
|
||||
{
|
||||
case '"':
|
||||
case '\\':
|
||||
off++;
|
||||
break;
|
||||
}
|
||||
dest[pos-off] = src[pos];
|
||||
esc = 0;
|
||||
}
|
||||
else if( src[pos] == '\\' )
|
||||
{
|
||||
off++;
|
||||
dest[pos-off] = src[pos];
|
||||
esc = 1;
|
||||
}
|
||||
else if( src[pos] != '"' )
|
||||
|
@ -75,6 +82,34 @@ static int extract_string(const char *src, char *dest, int len)
|
|||
return (off > -1) ? strlen(dest) : -1;
|
||||
}
|
||||
|
||||
static int cmp_index(const void *a, const void *b)
|
||||
{
|
||||
uint32_t x = ntohl(((const lmo_entry_t *)a)->key_id);
|
||||
uint32_t y = ntohl(((const lmo_entry_t *)b)->key_id);
|
||||
|
||||
if (x < y)
|
||||
return -1;
|
||||
else if (x > y)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_index(void *array, int n, FILE *out)
|
||||
{
|
||||
lmo_entry_t *e;
|
||||
|
||||
qsort(array, n, sizeof(*e), cmp_index);
|
||||
|
||||
for (e = array; n > 0; n--, e++)
|
||||
{
|
||||
print(&e->key_id, sizeof(uint32_t), 1, out);
|
||||
print(&e->val_id, sizeof(uint32_t), 1, out);
|
||||
print(&e->offset, sizeof(uint32_t), 1, out);
|
||||
print(&e->length, sizeof(uint32_t), 1, out);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char line[4096];
|
||||
|
@ -84,14 +119,14 @@ int main(int argc, char *argv[])
|
|||
int state = 0;
|
||||
int offset = 0;
|
||||
int length = 0;
|
||||
int n_entries = 0;
|
||||
void *array = NULL;
|
||||
lmo_entry_t *entry = NULL;
|
||||
uint32_t key_id, val_id;
|
||||
|
||||
FILE *in;
|
||||
FILE *out;
|
||||
|
||||
lmo_entry_t *head = NULL;
|
||||
lmo_entry_t *entry = NULL;
|
||||
|
||||
if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) )
|
||||
usage(argv[0]);
|
||||
|
||||
|
@ -160,26 +195,22 @@ int main(int argc, char *argv[])
|
|||
|
||||
if( key_id != val_id )
|
||||
{
|
||||
if( (entry = (lmo_entry_t *) malloc(sizeof(lmo_entry_t))) != NULL )
|
||||
{
|
||||
memset(entry, 0, sizeof(entry));
|
||||
length = strlen(val) + ((4 - (strlen(val) % 4)) % 4);
|
||||
n_entries++;
|
||||
array = realloc(array, n_entries * sizeof(lmo_entry_t));
|
||||
entry = (lmo_entry_t *)array + n_entries - 1;
|
||||
|
||||
entry->key_id = htonl(key_id);
|
||||
entry->val_id = htonl(val_id);
|
||||
entry->offset = htonl(offset);
|
||||
entry->length = htonl(strlen(val));
|
||||
|
||||
print(val, length, 1, out);
|
||||
offset += length;
|
||||
|
||||
entry->next = head;
|
||||
head = entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!array)
|
||||
die("Out of memory");
|
||||
}
|
||||
|
||||
entry->key_id = htonl(key_id);
|
||||
entry->val_id = htonl(val_id);
|
||||
entry->offset = htonl(offset);
|
||||
entry->length = htonl(strlen(val));
|
||||
|
||||
length = strlen(val) + ((4 - (strlen(val) % 4)) % 4);
|
||||
|
||||
print(val, length, 1, out);
|
||||
offset += length;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,15 +222,7 @@ int main(int argc, char *argv[])
|
|||
memset(line, 0, sizeof(line));
|
||||
}
|
||||
|
||||
entry = head;
|
||||
while( entry != NULL )
|
||||
{
|
||||
print(&entry->key_id, sizeof(uint32_t), 1, out);
|
||||
print(&entry->val_id, sizeof(uint32_t), 1, out);
|
||||
print(&entry->offset, sizeof(uint32_t), 1, out);
|
||||
print(&entry->length, sizeof(uint32_t), 1, out);
|
||||
entry = entry->next;
|
||||
}
|
||||
print_index(array, n_entries, out);
|
||||
|
||||
if( offset > 0 )
|
||||
{
|
325
libs/web/src/template_lmo.c
Normal file
325
libs/web/src/template_lmo.c
Normal file
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* lmo - Lua Machine Objects - Base functions
|
||||
*
|
||||
* Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "template_lmo.h"
|
||||
|
||||
/*
|
||||
* Hash function from http://www.azillionmonkeys.com/qed/hash.html
|
||||
* Copyright (C) 2004-2008 by Paul Hsieh
|
||||
*/
|
||||
|
||||
uint32_t sfh_hash(const char *data, int len)
|
||||
{
|
||||
uint32_t hash = len, tmp;
|
||||
int rem;
|
||||
|
||||
if (len <= 0 || data == NULL) return 0;
|
||||
|
||||
rem = len & 3;
|
||||
len >>= 2;
|
||||
|
||||
/* Main loop */
|
||||
for (;len > 0; len--) {
|
||||
hash += sfh_get16(data);
|
||||
tmp = (sfh_get16(data+2) << 11) ^ hash;
|
||||
hash = (hash << 16) ^ tmp;
|
||||
data += 2*sizeof(uint16_t);
|
||||
hash += hash >> 11;
|
||||
}
|
||||
|
||||
/* Handle end cases */
|
||||
switch (rem) {
|
||||
case 3: hash += sfh_get16(data);
|
||||
hash ^= hash << 16;
|
||||
hash ^= data[sizeof(uint16_t)] << 18;
|
||||
hash += hash >> 11;
|
||||
break;
|
||||
case 2: hash += sfh_get16(data);
|
||||
hash ^= hash << 11;
|
||||
hash += hash >> 17;
|
||||
break;
|
||||
case 1: hash += *data;
|
||||
hash ^= hash << 10;
|
||||
hash += hash >> 1;
|
||||
}
|
||||
|
||||
/* Force "avalanching" of final 127 bits */
|
||||
hash ^= hash << 3;
|
||||
hash += hash >> 5;
|
||||
hash ^= hash << 4;
|
||||
hash += hash >> 17;
|
||||
hash ^= hash << 25;
|
||||
hash += hash >> 6;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint32_t lmo_canon_hash(const char *str, int len)
|
||||
{
|
||||
char res[4096];
|
||||
char *ptr, prev;
|
||||
int off;
|
||||
|
||||
if (!str || len >= sizeof(res))
|
||||
return 0;
|
||||
|
||||
for (prev = ' ', ptr = res, off = 0; off < len; prev = *str, off++, str++)
|
||||
{
|
||||
if (isspace(*str))
|
||||
{
|
||||
if (!isspace(prev))
|
||||
*ptr++ = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr++ = *str;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ptr > res) && isspace(*(ptr-1)))
|
||||
ptr--;
|
||||
|
||||
return sfh_hash(res, ptr - res);
|
||||
}
|
||||
|
||||
lmo_archive_t * lmo_open(const char *file)
|
||||
{
|
||||
int in = -1;
|
||||
uint32_t idx_offset = 0;
|
||||
struct stat s;
|
||||
|
||||
lmo_archive_t *ar = NULL;
|
||||
|
||||
if (stat(file, &s) == -1)
|
||||
goto err;
|
||||
|
||||
if ((in = open(file, O_RDONLY)) == -1)
|
||||
goto err;
|
||||
|
||||
if ((ar = (lmo_archive_t *)malloc(sizeof(*ar))) != NULL)
|
||||
{
|
||||
memset(ar, 0, sizeof(*ar));
|
||||
|
||||
ar->fd = in;
|
||||
ar->size = s.st_size;
|
||||
|
||||
fcntl(ar->fd, F_SETFD, fcntl(ar->fd, F_GETFD) | FD_CLOEXEC);
|
||||
|
||||
if ((ar->mmap = mmap(NULL, ar->size, PROT_READ, MAP_SHARED, ar->fd, 0)) == MAP_FAILED)
|
||||
goto err;
|
||||
|
||||
idx_offset = *((const uint32_t *)
|
||||
(ar->mmap + ar->size - sizeof(uint32_t)));
|
||||
|
||||
if (idx_offset >= ar->size)
|
||||
goto err;
|
||||
|
||||
ar->index = (lmo_entry_t *)(ar->mmap + idx_offset);
|
||||
ar->length = (ar->size - idx_offset - sizeof(uint32_t)) / sizeof(lmo_entry_t);
|
||||
ar->end = ar->mmap + ar->size;
|
||||
|
||||
return ar;
|
||||
}
|
||||
|
||||
err:
|
||||
if (in > -1)
|
||||
close(in);
|
||||
|
||||
if (ar != NULL)
|
||||
{
|
||||
if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED))
|
||||
munmap(ar->mmap, ar->size);
|
||||
|
||||
free(ar);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void lmo_close(lmo_archive_t *ar)
|
||||
{
|
||||
if (ar != NULL)
|
||||
{
|
||||
if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED))
|
||||
munmap(ar->mmap, ar->size);
|
||||
|
||||
close(ar->fd);
|
||||
free(ar);
|
||||
|
||||
ar = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lmo_catalog_t *_lmo_catalogs = NULL;
|
||||
lmo_catalog_t *_lmo_active_catalog = NULL;
|
||||
|
||||
int lmo_load_catalog(const char *lang, const char *dir)
|
||||
{
|
||||
DIR *dh = NULL;
|
||||
char pattern[16];
|
||||
char path[PATH_MAX];
|
||||
struct dirent *de = NULL;
|
||||
|
||||
lmo_archive_t *ar = NULL;
|
||||
lmo_catalog_t *cat = NULL;
|
||||
|
||||
if (!lmo_change_catalog(lang))
|
||||
return 0;
|
||||
|
||||
if (!dir || !(dh = opendir(dir)))
|
||||
goto err;
|
||||
|
||||
if (!(cat = malloc(sizeof(*cat))))
|
||||
goto err;
|
||||
|
||||
memset(cat, 0, sizeof(*cat));
|
||||
|
||||
snprintf(cat->lang, sizeof(cat->lang), "%s", lang);
|
||||
snprintf(pattern, sizeof(pattern), "*.%s.lmo", lang);
|
||||
|
||||
while ((de = readdir(dh)) != NULL)
|
||||
{
|
||||
if (!fnmatch(pattern, de->d_name, 0))
|
||||
{
|
||||
snprintf(path, sizeof(path), "%s/%s", dir, de->d_name);
|
||||
ar = lmo_open(path);
|
||||
|
||||
if (ar)
|
||||
{
|
||||
ar->next = cat->archives;
|
||||
cat->archives = ar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dh);
|
||||
|
||||
cat->next = _lmo_catalogs;
|
||||
_lmo_catalogs = cat;
|
||||
|
||||
if (!_lmo_active_catalog)
|
||||
_lmo_active_catalog = cat;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (dh) closedir(dh);
|
||||
if (cat) free(cat);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lmo_change_catalog(const char *lang)
|
||||
{
|
||||
lmo_catalog_t *cat;
|
||||
|
||||
for (cat = _lmo_catalogs; cat; cat = cat->next)
|
||||
{
|
||||
if (!strncmp(cat->lang, lang, sizeof(cat->lang)))
|
||||
{
|
||||
_lmo_active_catalog = cat;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static lmo_entry_t * lmo_find_entry(lmo_archive_t *ar, uint32_t hash)
|
||||
{
|
||||
unsigned int m, l, r;
|
||||
|
||||
l = 0;
|
||||
r = ar->length - 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
m = l + ((r - l) / 2);
|
||||
|
||||
if (r < l)
|
||||
break;
|
||||
|
||||
if (ar->index[m].key_id == hash)
|
||||
return &ar->index[m];
|
||||
|
||||
if (ar->index[m].key_id > hash)
|
||||
{
|
||||
if (!m)
|
||||
break;
|
||||
|
||||
r = m - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = m + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int lmo_translate(const char *key, int keylen, char **out, int *outlen)
|
||||
{
|
||||
uint32_t hash;
|
||||
lmo_entry_t *e;
|
||||
lmo_archive_t *ar;
|
||||
|
||||
if (!key || !_lmo_active_catalog)
|
||||
return -2;
|
||||
|
||||
hash = htonl(lmo_canon_hash(key, keylen));
|
||||
|
||||
for (ar = _lmo_active_catalog->archives; ar; ar = ar->next)
|
||||
{
|
||||
if ((e = lmo_find_entry(ar, hash)) != NULL)
|
||||
{
|
||||
*out = ar->mmap + e->offset;
|
||||
*outlen = e->length;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void lmo_close_catalog(const char *lang)
|
||||
{
|
||||
lmo_archive_t *ar, *next;
|
||||
lmo_catalog_t *cat, *prev;
|
||||
|
||||
for (prev = NULL, cat = _lmo_catalogs; cat; prev = cat, cat = cat->next)
|
||||
{
|
||||
if (!strncmp(cat->lang, lang, sizeof(cat->lang)))
|
||||
{
|
||||
if (prev)
|
||||
prev->next = cat->next;
|
||||
else
|
||||
_lmo_catalogs = cat->next;
|
||||
|
||||
for (ar = cat->archives; ar; ar = next)
|
||||
{
|
||||
next = ar->next;
|
||||
lmo_close(ar);
|
||||
}
|
||||
|
||||
free(cat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* lmo - Lua Machine Objects - General header
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
* Copyright (C) 2009-2012 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,8 +16,8 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _LMO_H_
|
||||
#define _LMO_H_
|
||||
#ifndef _TEMPLATE_LMO_H_
|
||||
#define _TEMPLATE_LMO_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
@ -29,7 +29,9 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <fnmatch.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if (defined(__GNUC__) && defined(__i386__))
|
||||
#define sfh_get16(d) (*((const uint16_t *) (d)))
|
||||
|
@ -44,7 +46,6 @@ struct lmo_entry {
|
|||
uint32_t val_id;
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
struct lmo_entry *next;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct lmo_entry lmo_entry_t;
|
||||
|
@ -52,21 +53,39 @@ typedef struct lmo_entry lmo_entry_t;
|
|||
|
||||
struct lmo_archive {
|
||||
int fd;
|
||||
uint32_t length;
|
||||
int length;
|
||||
uint32_t size;
|
||||
lmo_entry_t *index;
|
||||
char *mmap;
|
||||
char *end;
|
||||
struct lmo_archive *next;
|
||||
};
|
||||
|
||||
typedef struct lmo_archive lmo_archive_t;
|
||||
|
||||
|
||||
uint32_t sfh_hash(const char * data, int len);
|
||||
struct lmo_catalog {
|
||||
char lang[6];
|
||||
struct lmo_archive *archives;
|
||||
struct lmo_catalog *next;
|
||||
};
|
||||
|
||||
char _lmo_error[1024];
|
||||
const char * lmo_error(void);
|
||||
typedef struct lmo_catalog lmo_catalog_t;
|
||||
|
||||
|
||||
uint32_t sfh_hash(const char *data, int len);
|
||||
uint32_t lmo_canon_hash(const char *data, int len);
|
||||
|
||||
lmo_archive_t * lmo_open(const char *file);
|
||||
int lmo_lookup(lmo_archive_t *ar, const char *key, char *dest, int len);
|
||||
void lmo_close(lmo_archive_t *ar);
|
||||
|
||||
|
||||
extern lmo_catalog_t *_lmo_catalogs;
|
||||
extern lmo_catalog_t *_lmo_active_catalog;
|
||||
|
||||
int lmo_load_catalog(const char *lang, const char *dir);
|
||||
int lmo_change_catalog(const char *lang);
|
||||
int lmo_translate(const char *key, int keylen, char **out, int *outlen);
|
||||
void lmo_close_catalog(const char *lang);
|
||||
|
||||
#endif
|
|
@ -21,79 +21,139 @@
|
|||
int template_L_parse(lua_State *L)
|
||||
{
|
||||
const char *file = luaL_checkstring(L, 1);
|
||||
struct template_parser parser;
|
||||
int lua_status;
|
||||
struct template_parser *parser = template_open(file);
|
||||
int lua_status, rv;
|
||||
|
||||
if( (parser.fd = open(file, O_RDONLY)) > 0 )
|
||||
if (!parser)
|
||||
{
|
||||
parser.flags = 0;
|
||||
parser.bufsize = 0;
|
||||
parser.state = T_STATE_TEXT_NEXT;
|
||||
lua_pushnil(L);
|
||||
lua_pushinteger(L, errno);
|
||||
lua_pushstring(L, strerror(errno));
|
||||
return 3;
|
||||
}
|
||||
|
||||
lua_status = lua_load(L, template_reader, &parser, file);
|
||||
lua_status = lua_load(L, template_reader, parser, file);
|
||||
|
||||
(void) close(parser.fd);
|
||||
if (lua_status == 0)
|
||||
rv = 1;
|
||||
else
|
||||
rv = template_error(L, parser);
|
||||
|
||||
template_close(parser);
|
||||
|
||||
if( lua_status == 0 )
|
||||
{
|
||||
return rv;
|
||||
}
|
||||
|
||||
int template_L_utf8(lua_State *L)
|
||||
{
|
||||
size_t len = 0;
|
||||
const char *str = luaL_checklstring(L, 1, &len);
|
||||
char *res = utf8(str, len);
|
||||
|
||||
if (res != NULL)
|
||||
{
|
||||
lua_pushstring(L, res);
|
||||
free(res);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int template_L_pcdata(lua_State *L)
|
||||
{
|
||||
size_t len = 0;
|
||||
const char *str = luaL_checklstring(L, 1, &len);
|
||||
char *res = pcdata(str, len);
|
||||
|
||||
if (res != NULL)
|
||||
{
|
||||
lua_pushstring(L, res);
|
||||
free(res);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int template_L_striptags(lua_State *L)
|
||||
{
|
||||
size_t len = 0;
|
||||
const char *str = luaL_checklstring(L, 1, &len);
|
||||
char *res = striptags(str, len);
|
||||
|
||||
if (res != NULL)
|
||||
{
|
||||
lua_pushstring(L, res);
|
||||
free(res);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int template_L_load_catalog(lua_State *L) {
|
||||
const char *lang = luaL_optstring(L, 1, "en");
|
||||
const char *dir = luaL_optstring(L, 2, NULL);
|
||||
lua_pushboolean(L, !lmo_load_catalog(lang, dir));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int template_L_close_catalog(lua_State *L) {
|
||||
const char *lang = luaL_optstring(L, 1, "en");
|
||||
lmo_close_catalog(lang);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int template_L_change_catalog(lua_State *L) {
|
||||
const char *lang = luaL_optstring(L, 1, "en");
|
||||
lua_pushboolean(L, !lmo_change_catalog(lang));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int template_L_translate(lua_State *L) {
|
||||
size_t len;
|
||||
char *tr;
|
||||
int trlen;
|
||||
const char *key = luaL_checklstring(L, 1, &len);
|
||||
|
||||
switch (lmo_translate(key, len, &tr, &trlen))
|
||||
{
|
||||
case 0:
|
||||
lua_pushlstring(L, tr, trlen);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushinteger(L, lua_status);
|
||||
lua_pushlstring(L, parser.out, parser.outsize);
|
||||
return 3;
|
||||
}
|
||||
|
||||
case -1:
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushinteger(L, 255);
|
||||
lua_pushstring(L, "No such file or directory");
|
||||
return 3;
|
||||
lua_pushstring(L, "no catalog loaded");
|
||||
return 2;
|
||||
}
|
||||
|
||||
int template_L_sanitize_utf8(lua_State *L)
|
||||
{
|
||||
size_t len = 0;
|
||||
const char *str = luaL_checklstring(L, 1, &len);
|
||||
char *res = sanitize_utf8(str, len);
|
||||
|
||||
if (res != NULL)
|
||||
{
|
||||
lua_pushstring(L, res);
|
||||
free(res);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int template_L_sanitize_pcdata(lua_State *L)
|
||||
{
|
||||
size_t len = 0;
|
||||
const char *str = luaL_checklstring(L, 1, &len);
|
||||
char *res = sanitize_pcdata(str, len);
|
||||
|
||||
if (res != NULL)
|
||||
{
|
||||
lua_pushstring(L, res);
|
||||
free(res);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
static int template_L_hash(lua_State *L) {
|
||||
size_t len;
|
||||
const char *key = luaL_checklstring(L, 1, &len);
|
||||
lua_pushinteger(L, sfh_hash(key, len));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* module table */
|
||||
static const luaL_reg R[] = {
|
||||
{ "parse", template_L_parse },
|
||||
{ "sanitize_utf8", template_L_sanitize_utf8 },
|
||||
{ "sanitize_pcdata", template_L_sanitize_pcdata },
|
||||
{ "utf8", template_L_utf8 },
|
||||
{ "pcdata", template_L_pcdata },
|
||||
{ "striptags", template_L_striptags },
|
||||
{ "load_catalog", template_L_load_catalog },
|
||||
{ "close_catalog", template_L_close_catalog },
|
||||
{ "change_catalog", template_L_change_catalog },
|
||||
{ "translate", template_L_translate },
|
||||
{ "hash", template_L_hash },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "template_parser.h"
|
||||
#include "template_utils.h"
|
||||
#include "template_lmo.h"
|
||||
|
||||
#define TEMPLATE_LUALIB_META "template.parser"
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* LuCI Template - Parser implementation
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
* Copyright (C) 2009-2012 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,17 +17,21 @@
|
|||
*/
|
||||
|
||||
#include "template_parser.h"
|
||||
#include "template_utils.h"
|
||||
#include "template_lmo.h"
|
||||
|
||||
|
||||
/* leading and trailing code for different types */
|
||||
const char * gen_code[7][2] = {
|
||||
const char *gen_code[9][2] = {
|
||||
{ NULL, NULL },
|
||||
{ "write(\"", "\")" },
|
||||
{ NULL, NULL },
|
||||
{ "write(tostring(", " or \"\"))" },
|
||||
{ "include(\"", "\")" },
|
||||
{ "write(pcdata(translate(\"", "\")))" },
|
||||
{ "write(translate(\"", "\"))" },
|
||||
{ NULL, " " }
|
||||
{ "write(\"", "\")" },
|
||||
{ "write(\"", "\")" },
|
||||
{ NULL, " " },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
/* Simple strstr() like function that takes len arguments for both haystack and needle. */
|
||||
|
@ -59,407 +63,324 @@ static char *strfind(char *haystack, int hslen, const char *needle, int ndlen)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inspect current read buffer and find the number of "vague" characters at the end
|
||||
* which could indicate an opening token. Returns the number of "vague" chars.
|
||||
* The last continuous sequence of whitespace, optionally followed by a "<" is
|
||||
* treated as "vague" because whitespace may be discarded if the upcoming opening
|
||||
* token indicates pre-whitespace-removal ("<%-"). A single remaining "<" char
|
||||
* can't be differentiated from an opening token ("<%"), so it's kept to be processed
|
||||
* in the next cycle.
|
||||
*/
|
||||
static int stokscan(struct template_parser *data, int off, int no_whitespace)
|
||||
struct template_parser * template_open(const char *file)
|
||||
{
|
||||
int i;
|
||||
int skip = 0;
|
||||
int tokoff = data->bufsize - 1;
|
||||
struct stat s;
|
||||
static struct template_parser *parser;
|
||||
|
||||
for( i = tokoff; i >= off; i-- )
|
||||
if (!(parser = malloc(sizeof(*parser))))
|
||||
goto err;
|
||||
|
||||
memset(parser, 0, sizeof(*parser));
|
||||
parser->fd = -1;
|
||||
parser->file = file;
|
||||
|
||||
if (stat(file, &s))
|
||||
goto err;
|
||||
|
||||
if ((parser->fd = open(file, O_RDONLY)) < 0)
|
||||
goto err;
|
||||
|
||||
parser->size = s.st_size;
|
||||
parser->mmap = mmap(NULL, parser->size, PROT_READ, MAP_PRIVATE,
|
||||
parser->fd, 0);
|
||||
|
||||
if (parser->mmap != MAP_FAILED)
|
||||
{
|
||||
if( data->buf[i] == T_TOK_START[0] )
|
||||
{
|
||||
skip = tokoff - i + 1;
|
||||
tokoff = i - 1;
|
||||
break;
|
||||
}
|
||||
parser->off = parser->mmap;
|
||||
parser->cur_chunk.type = T_TYPE_INIT;
|
||||
parser->cur_chunk.s = parser->mmap;
|
||||
parser->cur_chunk.e = parser->mmap;
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
if( !no_whitespace )
|
||||
{
|
||||
for( i = tokoff; i >= off; i-- )
|
||||
{
|
||||
if( isspace(data->buf[i]) )
|
||||
skip++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return skip;
|
||||
}
|
||||
|
||||
/*
|
||||
* Similar to stokscan() but looking for closing token indicators.
|
||||
* Matches "-", optionally followed by a "%" char.
|
||||
*/
|
||||
static int etokscan(struct template_parser *data)
|
||||
{
|
||||
int skip = 0;
|
||||
|
||||
if( (data->bufsize > 0) && (data->buf[data->bufsize-1] == T_TOK_END[0]) )
|
||||
skip++;
|
||||
|
||||
if( (data->bufsize > skip) && (data->buf[data->bufsize-skip-1] == T_TOK_SKIPWS[0]) )
|
||||
skip++;
|
||||
|
||||
return skip;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate Lua expressions from the given raw code, write it into the
|
||||
* output buffer and set the lua_Reader specific size pointer.
|
||||
* Takes parser-state, lua_Reader's size pointer and generator flags
|
||||
* as parameter. The given flags indicate whether leading or trailing
|
||||
* code should be added. Returns a pointer to the output buffer.
|
||||
*/
|
||||
static const char * generate_expression(struct template_parser *data, size_t *sz, int what)
|
||||
{
|
||||
char tmp[T_OUTBUFSZ];
|
||||
int i;
|
||||
int size = 0;
|
||||
int start = 0;
|
||||
int whitespace = 0;
|
||||
|
||||
memset(tmp, 0, T_OUTBUFSZ);
|
||||
|
||||
/* Inject leading expression code (if any) */
|
||||
if( (what & T_GEN_START) && (gen_code[data->type][0] != NULL) )
|
||||
{
|
||||
memcpy(tmp, gen_code[data->type][0], strlen(gen_code[data->type][0]));
|
||||
size += strlen(gen_code[data->type][0]);
|
||||
}
|
||||
|
||||
/* Parse source buffer */
|
||||
for( i = 0; i < data->outsize; i++ )
|
||||
{
|
||||
/* Skip leading whitespace for non-raw and non-expr chunks */
|
||||
if( !start && isspace(data->out[i]) && (data->type == T_TYPE_I18N ||
|
||||
data->type == T_TYPE_I18N_RAW || data->type == T_TYPE_INCLUDE) )
|
||||
continue;
|
||||
else if( !start )
|
||||
start = 1;
|
||||
|
||||
/* Found whitespace after i18n key */
|
||||
if( data->type == T_TYPE_I18N || data->type == T_TYPE_I18N_RAW )
|
||||
{
|
||||
/* Is initial whitespace, insert space */
|
||||
if( !whitespace && isspace(data->out[i]) )
|
||||
{
|
||||
tmp[size++] = ' ';
|
||||
whitespace = 1;
|
||||
}
|
||||
|
||||
/* Suppress subsequent whitespace, escape special chars */
|
||||
else if( !isspace(data->out[i]) )
|
||||
{
|
||||
if( data->out[i] == '\\' || data->out[i] == '"' )
|
||||
tmp[size++] = '\\';
|
||||
|
||||
tmp[size++] = data->out[i];
|
||||
whitespace = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Escape quotes, backslashes and newlines for plain and include expressions */
|
||||
else if( (data->type == T_TYPE_TEXT || data->type == T_TYPE_INCLUDE) &&
|
||||
(data->out[i] == '\\' || data->out[i] == '"' || data->out[i] == '\n' || data->out[i] == '\t') )
|
||||
{
|
||||
tmp[size++] = '\\';
|
||||
|
||||
switch(data->out[i])
|
||||
{
|
||||
case '\n':
|
||||
tmp[size++] = 'n';
|
||||
break;
|
||||
|
||||
case '\t':
|
||||
tmp[size++] = 't';
|
||||
break;
|
||||
|
||||
default:
|
||||
tmp[size++] = data->out[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Normal char */
|
||||
else
|
||||
{
|
||||
tmp[size++] = data->out[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Inject trailing expression code (if any) */
|
||||
if( (what & T_GEN_END) && (gen_code[data->type][1] != NULL) )
|
||||
{
|
||||
/* Strip trailing space for i18n expressions */
|
||||
if( data->type == T_TYPE_I18N || data->type == T_TYPE_I18N_RAW )
|
||||
if( (size > 0) && (tmp[size-1] == ' ') )
|
||||
size--;
|
||||
|
||||
memcpy(&tmp[size], gen_code[data->type][1], strlen(gen_code[data->type][1]));
|
||||
size += strlen(gen_code[data->type][1]);
|
||||
}
|
||||
|
||||
*sz = data->outsize = size;
|
||||
memset(data->out, 0, T_OUTBUFSZ);
|
||||
memcpy(data->out, tmp, size);
|
||||
|
||||
//printf("<<<%i|%i|%i|%s>>>\n", what, data->type, *sz, data->out);
|
||||
|
||||
return data->out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the number of bytes specified in data->bufsize from the
|
||||
* given source pointer to the beginning of the read buffer.
|
||||
*/
|
||||
static void bufmove(struct template_parser *data, const char *src)
|
||||
{
|
||||
if( data->bufsize > 0 )
|
||||
memmove(data->buf, src, data->bufsize);
|
||||
else if( data->bufsize < 0 )
|
||||
data->bufsize = 0;
|
||||
|
||||
data->buf[data->bufsize] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the given amount of bytes from the given source pointer
|
||||
* to the output buffer and set data->outputsize.
|
||||
*/
|
||||
static void bufout(struct template_parser *data, const char *src, int len)
|
||||
{
|
||||
if( len >= 0 )
|
||||
{
|
||||
memset(data->out, 0, T_OUTBUFSZ);
|
||||
memcpy(data->out, src, len);
|
||||
data->outsize = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
data->outsize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* lua_Reader compatible function that parses template code on demand from
|
||||
* the given file handle.
|
||||
*/
|
||||
const char *template_reader(lua_State *L, void *ud, size_t *sz)
|
||||
{
|
||||
struct template_parser *data = ud;
|
||||
char *match = NULL;
|
||||
int off = 0;
|
||||
int ignore = 0;
|
||||
int genflags = 0;
|
||||
int readlen = 0;
|
||||
int vague = 0;
|
||||
|
||||
while( !(data->flags & T_FLAG_EOF) || (data->bufsize > 0) )
|
||||
{
|
||||
/* Fill buffer */
|
||||
if( !(data->flags & T_FLAG_EOF) && (data->bufsize < T_READBUFSZ) )
|
||||
{
|
||||
if( (readlen = read(data->fd, &data->buf[data->bufsize], T_READBUFSZ - data->bufsize)) > 0 )
|
||||
data->bufsize += readlen;
|
||||
else if( readlen == 0 )
|
||||
data->flags |= T_FLAG_EOF;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Evaluate state */
|
||||
switch(data->state)
|
||||
{
|
||||
/* Plain text chunk (before "<%") */
|
||||
case T_STATE_TEXT_INIT:
|
||||
case T_STATE_TEXT_NEXT:
|
||||
off = 0; ignore = 0; *sz = 0;
|
||||
data->type = T_TYPE_TEXT;
|
||||
|
||||
/* Skip leading whitespace if requested */
|
||||
if( data->flags & T_FLAG_SKIPWS )
|
||||
{
|
||||
data->flags &= ~T_FLAG_SKIPWS;
|
||||
while( (off < data->bufsize) && isspace(data->buf[off]) )
|
||||
off++;
|
||||
}
|
||||
|
||||
/* Found "<%" */
|
||||
if( (match = strfind(&data->buf[off], data->bufsize - off - 1, T_TOK_START, strlen(T_TOK_START))) != NULL )
|
||||
{
|
||||
readlen = (int)(match - &data->buf[off]);
|
||||
data->bufsize -= (readlen + strlen(T_TOK_START) + off);
|
||||
match += strlen(T_TOK_START);
|
||||
|
||||
/* Check for leading '-' */
|
||||
if( match[0] == T_TOK_SKIPWS[0] )
|
||||
{
|
||||
data->bufsize--;
|
||||
match++;
|
||||
|
||||
while( (readlen > 1) && isspace(data->buf[off+readlen-1]) )
|
||||
{
|
||||
readlen--;
|
||||
}
|
||||
}
|
||||
|
||||
bufout(data, &data->buf[off], readlen);
|
||||
bufmove(data, match);
|
||||
data->state = T_STATE_CODE_INIT;
|
||||
}
|
||||
|
||||
/* Maybe plain chunk */
|
||||
else
|
||||
{
|
||||
/* Preserve trailing "<" or white space, maybe a start token */
|
||||
vague = stokscan(data, off, 0);
|
||||
|
||||
/* We can process some bytes ... */
|
||||
if( vague < data->bufsize )
|
||||
{
|
||||
readlen = data->bufsize - vague - off;
|
||||
}
|
||||
|
||||
/* No bytes to process, so try to remove at least whitespace ... */
|
||||
else
|
||||
{
|
||||
/* ... but try to preserve trailing "<" ... */
|
||||
vague = stokscan(data, off, 1);
|
||||
|
||||
if( vague < data->bufsize )
|
||||
{
|
||||
readlen = data->bufsize - vague - off;
|
||||
}
|
||||
|
||||
/* ... no chance, push out buffer */
|
||||
else
|
||||
{
|
||||
readlen = vague - off;
|
||||
vague = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bufout(data, &data->buf[off], readlen);
|
||||
|
||||
data->state = T_STATE_TEXT_NEXT;
|
||||
data->bufsize = vague;
|
||||
bufmove(data, &data->buf[off+readlen]);
|
||||
}
|
||||
|
||||
if( ignore || data->outsize == 0 )
|
||||
continue;
|
||||
else
|
||||
return generate_expression(data, sz, T_GEN_START | T_GEN_END);
|
||||
|
||||
break;
|
||||
|
||||
/* Ignored chunk (inside "<%# ... %>") */
|
||||
case T_STATE_SKIP:
|
||||
ignore = 1;
|
||||
|
||||
/* Initial code chunk ("<% ...") */
|
||||
case T_STATE_CODE_INIT:
|
||||
off = 0;
|
||||
|
||||
/* Check for leading '-' */
|
||||
if( data->buf[off] == T_TOK_SKIPWS[0] )
|
||||
off++;
|
||||
|
||||
/* Determine code type */
|
||||
switch(data->buf[off])
|
||||
{
|
||||
case '#':
|
||||
ignore = 1;
|
||||
off++;
|
||||
data->type = T_TYPE_COMMENT;
|
||||
break;
|
||||
|
||||
case '=':
|
||||
off++;
|
||||
data->type = T_TYPE_EXPR;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
off++;
|
||||
data->type = T_TYPE_INCLUDE;
|
||||
break;
|
||||
|
||||
case ':':
|
||||
off++;
|
||||
data->type = T_TYPE_I18N;
|
||||
break;
|
||||
|
||||
case '_':
|
||||
off++;
|
||||
data->type = T_TYPE_I18N_RAW;
|
||||
break;
|
||||
|
||||
default:
|
||||
data->type = T_TYPE_CODE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Subsequent code chunk ("..." or "... %>") */
|
||||
case T_STATE_CODE_NEXT:
|
||||
/* Found "%>" */
|
||||
if( (match = strfind(&data->buf[off], data->bufsize - off, T_TOK_END, strlen(T_TOK_END))) != NULL )
|
||||
{
|
||||
genflags = ( data->state == T_STATE_CODE_INIT )
|
||||
? (T_GEN_START | T_GEN_END) : T_GEN_END;
|
||||
|
||||
readlen = (int)(match - &data->buf[off]);
|
||||
|
||||
/* Check for trailing '-' */
|
||||
if( (match > data->buf) && (*(match-1) == T_TOK_SKIPWS[0]) )
|
||||
{
|
||||
readlen--;
|
||||
data->flags |= T_FLAG_SKIPWS;
|
||||
}
|
||||
|
||||
bufout(data, &data->buf[off], readlen);
|
||||
|
||||
data->state = T_STATE_TEXT_INIT;
|
||||
data->bufsize -= ((int)(match - &data->buf[off]) + strlen(T_TOK_END) + off);
|
||||
bufmove(data, &match[strlen(T_TOK_END)]);
|
||||
}
|
||||
|
||||
/* Code chunk */
|
||||
else
|
||||
{
|
||||
genflags = ( data->state == T_STATE_CODE_INIT ) ? T_GEN_START : 0;
|
||||
|
||||
/* Preserve trailing "%" and "-", maybe an end token */
|
||||
vague = etokscan(data);
|
||||
readlen = data->bufsize - off - vague;
|
||||
bufout(data, &data->buf[off], readlen);
|
||||
|
||||
data->state = T_STATE_CODE_NEXT;
|
||||
data->bufsize = vague;
|
||||
bufmove(data, &data->buf[readlen+off]);
|
||||
}
|
||||
|
||||
if( ignore || (data->outsize == 0 && !genflags) )
|
||||
continue;
|
||||
else
|
||||
return generate_expression(data, sz, genflags);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*sz = 0;
|
||||
err:
|
||||
template_close(parser);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void template_close(struct template_parser *parser)
|
||||
{
|
||||
if (!parser)
|
||||
return;
|
||||
|
||||
if (parser->gc != NULL)
|
||||
free(parser->gc);
|
||||
|
||||
if ((parser->mmap != NULL) && (parser->mmap != MAP_FAILED))
|
||||
munmap(parser->mmap, parser->size);
|
||||
|
||||
if (parser->fd >= 0)
|
||||
close(parser->fd);
|
||||
|
||||
free(parser);
|
||||
}
|
||||
|
||||
void template_text(struct template_parser *parser, const char *e)
|
||||
{
|
||||
const char *s = parser->off;
|
||||
|
||||
if (s < (parser->mmap + parser->size))
|
||||
{
|
||||
if (parser->strip_after)
|
||||
{
|
||||
while ((s <= e) && isspace(*s))
|
||||
s++;
|
||||
}
|
||||
|
||||
parser->cur_chunk.type = T_TYPE_TEXT;
|
||||
}
|
||||
else
|
||||
{
|
||||
parser->cur_chunk.type = T_TYPE_EOF;
|
||||
}
|
||||
|
||||
parser->cur_chunk.line = parser->line;
|
||||
parser->cur_chunk.s = s;
|
||||
parser->cur_chunk.e = e;
|
||||
}
|
||||
|
||||
void template_code(struct template_parser *parser, const char *e)
|
||||
{
|
||||
const char *s = parser->off;
|
||||
|
||||
parser->strip_before = 0;
|
||||
parser->strip_after = 0;
|
||||
|
||||
if (*s == '-')
|
||||
{
|
||||
parser->strip_before = 1;
|
||||
for (s++; (s <= e) && (*s == ' ' || *s == '\t'); s++);
|
||||
}
|
||||
|
||||
if (*(e-1) == '-')
|
||||
{
|
||||
parser->strip_after = 1;
|
||||
for (e--; (e >= s) && (*e == ' ' || *e == '\t'); e--);
|
||||
}
|
||||
|
||||
switch (*s)
|
||||
{
|
||||
/* comment */
|
||||
case '#':
|
||||
s++;
|
||||
parser->cur_chunk.type = T_TYPE_COMMENT;
|
||||
break;
|
||||
|
||||
/* include */
|
||||
case '+':
|
||||
s++;
|
||||
parser->cur_chunk.type = T_TYPE_INCLUDE;
|
||||
break;
|
||||
|
||||
/* translate */
|
||||
case ':':
|
||||
s++;
|
||||
parser->cur_chunk.type = T_TYPE_I18N;
|
||||
break;
|
||||
|
||||
/* translate raw */
|
||||
case '_':
|
||||
s++;
|
||||
parser->cur_chunk.type = T_TYPE_I18N_RAW;
|
||||
break;
|
||||
|
||||
/* expr */
|
||||
case '=':
|
||||
s++;
|
||||
parser->cur_chunk.type = T_TYPE_EXPR;
|
||||
break;
|
||||
|
||||
/* code */
|
||||
default:
|
||||
parser->cur_chunk.type = T_TYPE_CODE;
|
||||
break;
|
||||
}
|
||||
|
||||
parser->cur_chunk.line = parser->line;
|
||||
parser->cur_chunk.s = s;
|
||||
parser->cur_chunk.e = e;
|
||||
}
|
||||
|
||||
static const char *
|
||||
template_format_chunk(struct template_parser *parser, size_t *sz)
|
||||
{
|
||||
const char *s, *p;
|
||||
const char *head, *tail;
|
||||
struct template_chunk *c = &parser->prv_chunk;
|
||||
struct template_buffer *buf;
|
||||
|
||||
*sz = 0;
|
||||
s = parser->gc = NULL;
|
||||
|
||||
if (parser->strip_before && c->type == T_TYPE_TEXT)
|
||||
{
|
||||
while ((c->e > c->s) && isspace(*(c->e - 1)))
|
||||
c->e--;
|
||||
}
|
||||
|
||||
/* empty chunk */
|
||||
if (c->s == c->e)
|
||||
{
|
||||
if (c->type == T_TYPE_EOF)
|
||||
{
|
||||
*sz = 0;
|
||||
s = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*sz = 1;
|
||||
s = " ";
|
||||
}
|
||||
}
|
||||
|
||||
/* format chunk */
|
||||
else if ((buf = buf_init(c->e - c->s)) != NULL)
|
||||
{
|
||||
if ((head = gen_code[c->type][0]) != NULL)
|
||||
buf_append(buf, head, strlen(head));
|
||||
|
||||
switch (c->type)
|
||||
{
|
||||
case T_TYPE_TEXT:
|
||||
luastr_escape(buf, c->s, c->e - c->s, 0);
|
||||
break;
|
||||
|
||||
case T_TYPE_EXPR:
|
||||
buf_append(buf, c->s, c->e - c->s);
|
||||
for (p = c->s; p < c->e; p++)
|
||||
parser->line += (*p == '\n');
|
||||
break;
|
||||
|
||||
case T_TYPE_INCLUDE:
|
||||
luastr_escape(buf, c->s, c->e - c->s, 0);
|
||||
break;
|
||||
|
||||
case T_TYPE_I18N:
|
||||
luastr_translate(buf, c->s, c->e - c->s, 1);
|
||||
break;
|
||||
|
||||
case T_TYPE_I18N_RAW:
|
||||
luastr_translate(buf, c->s, c->e - c->s, 0);
|
||||
break;
|
||||
|
||||
case T_TYPE_CODE:
|
||||
buf_append(buf, c->s, c->e - c->s);
|
||||
for (p = c->s; p < c->e; p++)
|
||||
parser->line += (*p == '\n');
|
||||
break;
|
||||
}
|
||||
|
||||
if ((tail = gen_code[c->type][1]) != NULL)
|
||||
buf_append(buf, tail, strlen(tail));
|
||||
|
||||
*sz = buf_length(buf);
|
||||
s = parser->gc = buf_destroy(buf);
|
||||
|
||||
if (!*sz)
|
||||
{
|
||||
*sz = 1;
|
||||
s = " ";
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
const char *template_reader(lua_State *L, void *ud, size_t *sz)
|
||||
{
|
||||
struct template_parser *parser = ud;
|
||||
int rem = parser->size - (parser->off - parser->mmap);
|
||||
char *tag;
|
||||
|
||||
parser->prv_chunk = parser->cur_chunk;
|
||||
|
||||
/* free previous string */
|
||||
if (parser->gc)
|
||||
{
|
||||
free(parser->gc);
|
||||
parser->gc = NULL;
|
||||
}
|
||||
|
||||
/* before tag */
|
||||
if (!parser->in_expr)
|
||||
{
|
||||
if ((tag = strfind(parser->off, rem, "<%", 2)) != NULL)
|
||||
{
|
||||
template_text(parser, tag);
|
||||
parser->off = tag + 2;
|
||||
parser->in_expr = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
template_text(parser, parser->mmap + parser->size);
|
||||
parser->off = parser->mmap + parser->size;
|
||||
}
|
||||
}
|
||||
|
||||
/* inside tag */
|
||||
else
|
||||
{
|
||||
if ((tag = strfind(parser->off, rem, "%>", 2)) != NULL)
|
||||
{
|
||||
template_code(parser, tag);
|
||||
parser->off = tag + 2;
|
||||
parser->in_expr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unexpected EOF */
|
||||
template_code(parser, parser->mmap + parser->size);
|
||||
|
||||
*sz = 1;
|
||||
return "\033";
|
||||
}
|
||||
}
|
||||
|
||||
return template_format_chunk(parser, sz);
|
||||
}
|
||||
|
||||
int template_error(lua_State *L, struct template_parser *parser)
|
||||
{
|
||||
const char *err = luaL_checkstring(L, -1);
|
||||
const char *off = parser->prv_chunk.s;
|
||||
const char *ptr;
|
||||
char msg[1024];
|
||||
int line = 0;
|
||||
int chunkline = 0;
|
||||
|
||||
if ((ptr = strfind((char *)err, strlen(err), "]:", 2)) != NULL)
|
||||
{
|
||||
chunkline = atoi(ptr + 2) - parser->prv_chunk.line;
|
||||
|
||||
while (*ptr)
|
||||
{
|
||||
if (*ptr++ == ' ')
|
||||
{
|
||||
err = ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strfind((char *)err, strlen(err), "'char(27)'", 10) != NULL)
|
||||
{
|
||||
off = parser->mmap + parser->size;
|
||||
err = "'%>' expected before end of file";
|
||||
chunkline = 0;
|
||||
}
|
||||
|
||||
for (ptr = parser->mmap; ptr < off; ptr++)
|
||||
if (*ptr == '\n')
|
||||
line++;
|
||||
|
||||
snprintf(msg, sizeof(msg), "Syntax error in %s:%d: %s",
|
||||
parser->file, line + chunkline, err ? err : "(unknown error)");
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushinteger(L, line + chunkline);
|
||||
lua_pushstring(L, msg);
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
|
|
@ -21,61 +21,59 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
|
||||
#define T_READBUFSZ 1024
|
||||
#define T_OUTBUFSZ T_READBUFSZ * 3
|
||||
|
||||
/* parser states */
|
||||
#define T_STATE_TEXT_INIT 0
|
||||
#define T_STATE_TEXT_NEXT 1
|
||||
#define T_STATE_CODE_INIT 2
|
||||
#define T_STATE_CODE_NEXT 3
|
||||
#define T_STATE_SKIP 4
|
||||
|
||||
/* parser flags */
|
||||
#define T_FLAG_EOF 0x01
|
||||
#define T_FLAG_SKIPWS 0x02
|
||||
|
||||
/* tokens used in matching and expression generation */
|
||||
#define T_TOK_START "<%"
|
||||
#define T_TOK_END "%>"
|
||||
#define T_TOK_SKIPWS "-"
|
||||
|
||||
/* generator flags */
|
||||
#define T_GEN_START 0x01
|
||||
#define T_GEN_END 0x02
|
||||
|
||||
/* code types */
|
||||
#define T_TYPE_TEXT 0
|
||||
#define T_TYPE_COMMENT 1
|
||||
#define T_TYPE_EXPR 2
|
||||
#define T_TYPE_INCLUDE 3
|
||||
#define T_TYPE_I18N 4
|
||||
#define T_TYPE_I18N_RAW 5
|
||||
#define T_TYPE_CODE 6
|
||||
#define T_TYPE_INIT 0
|
||||
#define T_TYPE_TEXT 1
|
||||
#define T_TYPE_COMMENT 2
|
||||
#define T_TYPE_EXPR 3
|
||||
#define T_TYPE_INCLUDE 4
|
||||
#define T_TYPE_I18N 5
|
||||
#define T_TYPE_I18N_RAW 6
|
||||
#define T_TYPE_CODE 7
|
||||
#define T_TYPE_EOF 8
|
||||
|
||||
|
||||
struct template_chunk {
|
||||
const char *s;
|
||||
const char *e;
|
||||
int type;
|
||||
int line;
|
||||
};
|
||||
|
||||
/* parser state */
|
||||
struct template_parser {
|
||||
int fd;
|
||||
int bufsize;
|
||||
int outsize;
|
||||
int state;
|
||||
int flags;
|
||||
int type;
|
||||
char buf[T_READBUFSZ];
|
||||
char out[T_OUTBUFSZ];
|
||||
uint32_t size;
|
||||
char *mmap;
|
||||
char *off;
|
||||
char *gc;
|
||||
int line;
|
||||
int in_expr;
|
||||
int strip_before;
|
||||
int strip_after;
|
||||
struct template_chunk prv_chunk;
|
||||
struct template_chunk cur_chunk;
|
||||
const char *file;
|
||||
};
|
||||
|
||||
struct template_parser * template_open(const char *file);
|
||||
void template_close(struct template_parser *parser);
|
||||
|
||||
const char *template_reader(lua_State *L, void *ud, size_t *sz);
|
||||
int template_error(lua_State *L, struct template_parser *parser);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,19 +17,23 @@
|
|||
*/
|
||||
|
||||
#include "template_utils.h"
|
||||
#include "template_lmo.h"
|
||||
|
||||
/* initialize a buffer object */
|
||||
static struct template_buffer * buf_init(void)
|
||||
struct template_buffer * buf_init(int size)
|
||||
{
|
||||
struct template_buffer *buf;
|
||||
|
||||
if (size <= 0)
|
||||
size = 1024;
|
||||
|
||||
buf = (struct template_buffer *)malloc(sizeof(struct template_buffer));
|
||||
|
||||
if (buf != NULL)
|
||||
{
|
||||
buf->fill = 0;
|
||||
buf->size = 1024;
|
||||
buf->data = (unsigned char *)malloc(buf->size);
|
||||
buf->size = size;
|
||||
buf->data = malloc(buf->size);
|
||||
|
||||
if (buf->data != NULL)
|
||||
{
|
||||
|
@ -46,17 +50,21 @@ static struct template_buffer * buf_init(void)
|
|||
}
|
||||
|
||||
/* grow buffer */
|
||||
static int buf_grow(struct template_buffer *buf)
|
||||
int buf_grow(struct template_buffer *buf, int size)
|
||||
{
|
||||
unsigned int off = (buf->dptr - buf->data);
|
||||
unsigned char *data =
|
||||
(unsigned char *)realloc(buf->data, buf->size + 1024);
|
||||
char *data;
|
||||
|
||||
if (size <= 0)
|
||||
size = 1024;
|
||||
|
||||
data = realloc(buf->data, buf->size + size);
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
buf->data = data;
|
||||
buf->dptr = data + off;
|
||||
buf->size += 1024;
|
||||
buf->size += size;
|
||||
|
||||
return buf->size;
|
||||
}
|
||||
|
@ -65,9 +73,9 @@ static int buf_grow(struct template_buffer *buf)
|
|||
}
|
||||
|
||||
/* put one char into buffer object */
|
||||
static int buf_putchar(struct template_buffer *buf, unsigned char c)
|
||||
int buf_putchar(struct template_buffer *buf, char c)
|
||||
{
|
||||
if( ((buf->fill + 1) >= buf->size) && !buf_grow(buf) )
|
||||
if( ((buf->fill + 1) >= buf->size) && !buf_grow(buf, 0) )
|
||||
return 0;
|
||||
|
||||
*(buf->dptr++) = c;
|
||||
|
@ -78,11 +86,11 @@ static int buf_putchar(struct template_buffer *buf, unsigned char c)
|
|||
}
|
||||
|
||||
/* append data to buffer */
|
||||
static int buf_append(struct template_buffer *buf, unsigned char *s, int len)
|
||||
int buf_append(struct template_buffer *buf, const char *s, int len)
|
||||
{
|
||||
while ((buf->fill + len + 1) >= buf->size)
|
||||
if ((buf->fill + len + 1) >= buf->size)
|
||||
{
|
||||
if (!buf_grow(buf))
|
||||
if (!buf_grow(buf, len + 1))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -95,13 +103,19 @@ static int buf_append(struct template_buffer *buf, unsigned char *s, int len)
|
|||
return len;
|
||||
}
|
||||
|
||||
/* destroy buffer object and return pointer to data */
|
||||
static char * buf_destroy(struct template_buffer *buf)
|
||||
/* read buffer length */
|
||||
int buf_length(struct template_buffer *buf)
|
||||
{
|
||||
unsigned char *data = buf->data;
|
||||
return buf->fill;
|
||||
}
|
||||
|
||||
/* destroy buffer object and return pointer to data */
|
||||
char * buf_destroy(struct template_buffer *buf)
|
||||
{
|
||||
char *data = buf->data;
|
||||
|
||||
free(buf);
|
||||
return (char *)data;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
@ -229,7 +243,7 @@ static int _validate_utf8(unsigned char **s, int l, struct template_buffer *buf)
|
|||
!mb_is_surrogate(ptr, n) && !mb_is_illegal(ptr, n))
|
||||
{
|
||||
/* copy sequence */
|
||||
if (!buf_append(buf, ptr, n))
|
||||
if (!buf_append(buf, (char *)ptr, n))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -264,9 +278,9 @@ static int _validate_utf8(unsigned char **s, int l, struct template_buffer *buf)
|
|||
}
|
||||
|
||||
/* sanitize given string and replace all invalid UTF-8 sequences with "?" */
|
||||
char * sanitize_utf8(const char *s, unsigned int l)
|
||||
char * utf8(const char *s, unsigned int l)
|
||||
{
|
||||
struct template_buffer *buf = buf_init();
|
||||
struct template_buffer *buf = buf_init(l);
|
||||
unsigned char *ptr = (unsigned char *)s;
|
||||
unsigned int v, o;
|
||||
|
||||
|
@ -278,7 +292,7 @@ char * sanitize_utf8(const char *s, unsigned int l)
|
|||
/* ascii char */
|
||||
if ((*ptr >= 0x01) && (*ptr <= 0x7F))
|
||||
{
|
||||
if (!buf_putchar(buf, *ptr++))
|
||||
if (!buf_putchar(buf, (char)*ptr++))
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -298,9 +312,9 @@ char * sanitize_utf8(const char *s, unsigned int l)
|
|||
/* Sanitize given string and strip all invalid XML bytes
|
||||
* Validate UTF-8 sequences
|
||||
* Escape XML control chars */
|
||||
char * sanitize_pcdata(const char *s, unsigned int l)
|
||||
char * pcdata(const char *s, unsigned int l)
|
||||
{
|
||||
struct template_buffer *buf = buf_init();
|
||||
struct template_buffer *buf = buf_init(l);
|
||||
unsigned char *ptr = (unsigned char *)s;
|
||||
unsigned int o, v;
|
||||
char esq[8];
|
||||
|
@ -329,7 +343,7 @@ char * sanitize_pcdata(const char *s, unsigned int l)
|
|||
{
|
||||
esl = snprintf(esq, sizeof(esq), "&#%i;", *ptr);
|
||||
|
||||
if (!buf_append(buf, (unsigned char *)esq, esl))
|
||||
if (!buf_append(buf, esq, esl))
|
||||
break;
|
||||
|
||||
ptr++;
|
||||
|
@ -338,7 +352,7 @@ char * sanitize_pcdata(const char *s, unsigned int l)
|
|||
/* ascii char */
|
||||
else if (*ptr <= 0x7F)
|
||||
{
|
||||
buf_putchar(buf, *ptr++);
|
||||
buf_putchar(buf, (char)*ptr++);
|
||||
}
|
||||
|
||||
/* multi byte sequence */
|
||||
|
@ -353,3 +367,128 @@ char * sanitize_pcdata(const char *s, unsigned int l)
|
|||
|
||||
return buf_destroy(buf);
|
||||
}
|
||||
|
||||
char * striptags(const char *s, unsigned int l)
|
||||
{
|
||||
struct template_buffer *buf = buf_init(l);
|
||||
unsigned char *ptr = (unsigned char *)s;
|
||||
unsigned char *end = ptr + l;
|
||||
unsigned char *tag;
|
||||
unsigned char prev;
|
||||
char esq[8];
|
||||
int esl;
|
||||
|
||||
for (prev = ' '; ptr < end; ptr++)
|
||||
{
|
||||
if ((*ptr == '<') && ((ptr + 2) < end) &&
|
||||
((*(ptr + 1) == '/') || isalpha(*(ptr + 1))))
|
||||
{
|
||||
for (tag = ptr; tag < end; tag++)
|
||||
{
|
||||
if (*tag == '>')
|
||||
{
|
||||
if (!isspace(prev))
|
||||
buf_putchar(buf, ' ');
|
||||
|
||||
ptr = tag;
|
||||
prev = ' ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isspace(*ptr))
|
||||
{
|
||||
if (!isspace(prev))
|
||||
buf_putchar(buf, *ptr);
|
||||
|
||||
prev = *ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(*ptr)
|
||||
{
|
||||
case '"':
|
||||
case '\'':
|
||||
case '<':
|
||||
case '>':
|
||||
case '&':
|
||||
esl = snprintf(esq, sizeof(esq), "&#%i;", *ptr);
|
||||
buf_append(buf, esq, esl);
|
||||
break;
|
||||
|
||||
default:
|
||||
buf_putchar(buf, *ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
prev = *ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return buf_destroy(buf);
|
||||
}
|
||||
|
||||
void luastr_escape(struct template_buffer *out, const char *s, unsigned int l,
|
||||
int escape_xml)
|
||||
{
|
||||
int esl;
|
||||
char esq[8];
|
||||
char *ptr;
|
||||
|
||||
for (ptr = (char *)s; ptr < (s + l); ptr++)
|
||||
{
|
||||
switch (*ptr)
|
||||
{
|
||||
case '\\':
|
||||
buf_append(out, "\\\\", 2);
|
||||
break;
|
||||
|
||||
case '"':
|
||||
if (escape_xml)
|
||||
buf_append(out, """, 5);
|
||||
else
|
||||
buf_append(out, "\\\"", 2);
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
buf_append(out, "\\n", 2);
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
case '&':
|
||||
case '<':
|
||||
case '>':
|
||||
if (escape_xml)
|
||||
{
|
||||
esl = snprintf(esq, sizeof(esq), "&#%i;", *ptr);
|
||||
buf_append(out, esq, esl);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
buf_putchar(out, *ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void luastr_translate(struct template_buffer *out, const char *s, unsigned int l,
|
||||
int escape_xml)
|
||||
{
|
||||
char *tr;
|
||||
int trlen;
|
||||
|
||||
switch (lmo_translate(s, l, &tr, &trlen))
|
||||
{
|
||||
case 0:
|
||||
luastr_escape(out, tr, trlen, escape_xml);
|
||||
break;
|
||||
|
||||
case -1:
|
||||
luastr_escape(out, s, l, escape_xml);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* no catalog loaded */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* LuCI Template - Utility header
|
||||
*
|
||||
* Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
|
||||
* Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -26,13 +26,24 @@
|
|||
|
||||
/* buffer object */
|
||||
struct template_buffer {
|
||||
unsigned char *data;
|
||||
unsigned char *dptr;
|
||||
char *data;
|
||||
char *dptr;
|
||||
unsigned int size;
|
||||
unsigned int fill;
|
||||
};
|
||||
|
||||
char * sanitize_utf8(const char *s, unsigned int l);
|
||||
char * sanitize_pcdata(const char *s, unsigned int l);
|
||||
struct template_buffer * buf_init(int size);
|
||||
int buf_grow(struct template_buffer *buf, int size);
|
||||
int buf_putchar(struct template_buffer *buf, char c);
|
||||
int buf_append(struct template_buffer *buf, const char *s, int len);
|
||||
int buf_length(struct template_buffer *buf);
|
||||
char * buf_destroy(struct template_buffer *buf);
|
||||
|
||||
char * utf8(const char *s, unsigned int l);
|
||||
char * pcdata(const char *s, unsigned int l);
|
||||
char * striptags(const char *s, unsigned int l);
|
||||
|
||||
void luastr_escape(struct template_buffer *out, const char *s, unsigned int l, int escape_xml);
|
||||
void luastr_translate(struct template_buffer *out, const char *s, unsigned int l, int escape_xml);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,15 +30,13 @@ function action_status()
|
|||
end
|
||||
end
|
||||
|
||||
function action_restart()
|
||||
function action_restart(args)
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local rqp = luci.dispatcher.context.requestpath
|
||||
|
||||
if rqp[3] then
|
||||
if args then
|
||||
local service
|
||||
local services = { }
|
||||
|
||||
for service in rqp[3]:gmatch("[%w_-]+") do
|
||||
for service in args:gmatch("[%w_-]+") do
|
||||
services[#services+1] = service
|
||||
end
|
||||
|
||||
|
|
|
@ -153,35 +153,40 @@ function wifi_network(id)
|
|||
return { }
|
||||
end
|
||||
|
||||
function switch_status(dev)
|
||||
local ports = { }
|
||||
local swc = io.popen("swconfig dev %q show" % dev, "r")
|
||||
if swc then
|
||||
local l
|
||||
repeat
|
||||
l = swc:read("*l")
|
||||
if l then
|
||||
local port, up = l:match("port:(%d+) link:(%w+)")
|
||||
if port then
|
||||
local speed = l:match(" speed:(%d+)")
|
||||
local duplex = l:match(" (%w+)-duplex")
|
||||
local txflow = l:match(" (txflow)")
|
||||
local rxflow = l:match(" (rxflow)")
|
||||
local auto = l:match(" (auto)")
|
||||
function switch_status(devs)
|
||||
local dev
|
||||
local switches = { }
|
||||
for dev in devs:gmatch("[^%s,]+") do
|
||||
local ports = { }
|
||||
local swc = io.popen("swconfig dev %q show" % dev, "r")
|
||||
if swc then
|
||||
local l
|
||||
repeat
|
||||
l = swc:read("*l")
|
||||
if l then
|
||||
local port, up = l:match("port:(%d+) link:(%w+)")
|
||||
if port then
|
||||
local speed = l:match(" speed:(%d+)")
|
||||
local duplex = l:match(" (%w+)-duplex")
|
||||
local txflow = l:match(" (txflow)")
|
||||
local rxflow = l:match(" (rxflow)")
|
||||
local auto = l:match(" (auto)")
|
||||
|
||||
ports[#ports+1] = {
|
||||
port = tonumber(port) or 0,
|
||||
speed = tonumber(speed) or 0,
|
||||
link = (up == "up"),
|
||||
duplex = (duplex == "full"),
|
||||
rxflow = (not not rxflow),
|
||||
txflow = (not not txflow),
|
||||
auto = (not not auto)
|
||||
}
|
||||
ports[#ports+1] = {
|
||||
port = tonumber(port) or 0,
|
||||
speed = tonumber(speed) or 0,
|
||||
link = (up == "up"),
|
||||
duplex = (duplex == "full"),
|
||||
rxflow = (not not rxflow),
|
||||
txflow = (not not txflow),
|
||||
auto = (not not auto)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
until not l
|
||||
swc:close()
|
||||
until not l
|
||||
swc:close()
|
||||
end
|
||||
switches[dev] = ports
|
||||
end
|
||||
return ports
|
||||
return switches
|
||||
end
|
||||
|
|
|
@ -68,7 +68,7 @@ function index()
|
|||
page = entry({"admin", "network", "wireless_reconnect"}, call("wifi_reconnect"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "network", "wireless_shutdown"}, call("wifi_reconnect"), nil)
|
||||
page = entry({"admin", "network", "wireless_shutdown"}, call("wifi_shutdown"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "network", "wireless"}, arcombine(template("admin_network/wifi_overview"), cbi("admin_network/wifi")), _("Wifi"), 15)
|
||||
|
@ -156,6 +156,12 @@ function index()
|
|||
|
||||
page = entry({"admin", "network", "diag_traceroute"}, call("diag_traceroute"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "network", "diag_ping6"}, call("diag_ping6"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "network", "diag_traceroute6"}, call("diag_traceroute6"), nil)
|
||||
page.leaf = true
|
||||
-- end
|
||||
end
|
||||
|
||||
|
@ -235,13 +241,12 @@ function wifi_delete(network)
|
|||
luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless"))
|
||||
end
|
||||
|
||||
function iface_status()
|
||||
local path = luci.dispatcher.context.requestpath
|
||||
function iface_status(ifaces)
|
||||
local netm = require "luci.model.network".init()
|
||||
local rv = { }
|
||||
|
||||
local iface
|
||||
for iface in path[#path]:gmatch("[%w%.%-_]+") do
|
||||
for iface in ifaces:gmatch("[%w%.%-_]+") do
|
||||
local net = netm:get_network(iface)
|
||||
local device = net and net:get_interface()
|
||||
if device then
|
||||
|
@ -318,11 +323,8 @@ function iface_status()
|
|||
luci.http.status(404, "No such device")
|
||||
end
|
||||
|
||||
function iface_reconnect()
|
||||
local path = luci.dispatcher.context.requestpath
|
||||
local iface = path[#path]
|
||||
function iface_reconnect(iface)
|
||||
local netmd = require "luci.model.network".init()
|
||||
|
||||
local net = netmd:get_network(iface)
|
||||
if net then
|
||||
luci.sys.call("env -i /sbin/ifup %q >/dev/null 2>/dev/null" % iface)
|
||||
|
@ -333,11 +335,8 @@ function iface_reconnect()
|
|||
luci.http.status(404, "No such interface")
|
||||
end
|
||||
|
||||
function iface_shutdown()
|
||||
local path = luci.dispatcher.context.requestpath
|
||||
local iface = path[#path]
|
||||
function iface_shutdown(iface)
|
||||
local netmd = require "luci.model.network".init()
|
||||
|
||||
local net = netmd:get_network(iface)
|
||||
if net then
|
||||
luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface)
|
||||
|
@ -348,11 +347,8 @@ function iface_shutdown()
|
|||
luci.http.status(404, "No such interface")
|
||||
end
|
||||
|
||||
function iface_delete()
|
||||
local path = luci.dispatcher.context.requestpath
|
||||
local iface = path[#path]
|
||||
function iface_delete(iface)
|
||||
local netmd = require "luci.model.network".init()
|
||||
|
||||
local net = netmd:del_network(iface)
|
||||
if net then
|
||||
luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface)
|
||||
|
@ -365,13 +361,12 @@ function iface_delete()
|
|||
luci.http.status(404, "No such interface")
|
||||
end
|
||||
|
||||
function wifi_status()
|
||||
local path = luci.dispatcher.context.requestpath
|
||||
function wifi_status(devs)
|
||||
local s = require "luci.tools.status"
|
||||
local rv = { }
|
||||
|
||||
local dev
|
||||
for dev in path[#path]:gmatch("[%w%.%-]+") do
|
||||
for dev in devs:gmatch("[%w%.%-]+") do
|
||||
rv[#rv+1] = s.wifi_network(dev)
|
||||
end
|
||||
|
||||
|
@ -384,23 +379,19 @@ function wifi_status()
|
|||
luci.http.status(404, "No such device")
|
||||
end
|
||||
|
||||
function wifi_reconnect()
|
||||
local path = luci.dispatcher.context.requestpath
|
||||
local mode = path[#path-1]
|
||||
local wnet = path[#path]
|
||||
local function wifi_reconnect_shutdown(shutdown, wnet)
|
||||
local netmd = require "luci.model.network".init()
|
||||
|
||||
local net = netmd:get_wifinet(wnet)
|
||||
local dev = net:get_device()
|
||||
if dev and net then
|
||||
luci.sys.call("env -i /sbin/wifi down >/dev/null 2>/dev/null")
|
||||
|
||||
dev:set("disabled", nil)
|
||||
net:set("disabled", (mode == "wireless_shutdown") and 1 or nil)
|
||||
net:set("disabled", shutdown and 1 or nil)
|
||||
netmd:commit("wireless")
|
||||
|
||||
luci.sys.call("env -i /sbin/wifi up >/dev/null 2>/dev/null")
|
||||
luci.http.status(200, (mode == "wireless_shutdown") and "Shutdown" or "Reconnected")
|
||||
luci.http.status(200, shutdown and "Shutdown" or "Reconnected")
|
||||
|
||||
return
|
||||
end
|
||||
|
@ -408,6 +399,14 @@ function wifi_reconnect()
|
|||
luci.http.status(404, "No such radio")
|
||||
end
|
||||
|
||||
function wifi_reconnect(wnet)
|
||||
wifi_reconnect_shutdown(false, wnet)
|
||||
end
|
||||
|
||||
function wifi_shutdown(wnet)
|
||||
wifi_reconnect_shutdown(true, wnet)
|
||||
end
|
||||
|
||||
function lease_status()
|
||||
local s = require "luci.tools.status"
|
||||
|
||||
|
@ -419,18 +418,14 @@ function lease_status()
|
|||
luci.http.write(']')
|
||||
end
|
||||
|
||||
function switch_status()
|
||||
local path = luci.dispatcher.context.requestpath
|
||||
function switch_status(switches)
|
||||
local s = require "luci.tools.status"
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(s.switch_status(path[#path]))
|
||||
luci.http.write_json(s.switch_status(switches))
|
||||
end
|
||||
|
||||
function diag_command(cmd)
|
||||
local path = luci.dispatcher.context.requestpath
|
||||
local addr = path[#path]
|
||||
|
||||
function diag_command(cmd, addr)
|
||||
if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
|
||||
luci.http.prepare_content("text/plain")
|
||||
|
||||
|
@ -452,14 +447,22 @@ function diag_command(cmd)
|
|||
luci.http.status(500, "Bad address")
|
||||
end
|
||||
|
||||
function diag_ping()
|
||||
diag_command("ping -c 5 -W 1 %q 2>&1")
|
||||
function diag_ping(addr)
|
||||
diag_command("ping -c 5 -W 1 %q 2>&1", addr)
|
||||
end
|
||||
|
||||
function diag_traceroute()
|
||||
diag_command("traceroute -q 1 -w 1 -n %q 2>&1")
|
||||
function diag_traceroute(addr)
|
||||
diag_command("traceroute -q 1 -w 1 -n %q 2>&1", addr)
|
||||
end
|
||||
|
||||
function diag_nslookup()
|
||||
diag_command("nslookup %q 2>&1")
|
||||
function diag_nslookup(addr)
|
||||
diag_command("nslookup %q 2>&1", addr)
|
||||
end
|
||||
|
||||
function diag_ping6(addr)
|
||||
diag_command("ping6 -c 5 %q 2>&1", addr)
|
||||
end
|
||||
|
||||
function diag_traceroute6(addr)
|
||||
diag_command("traceroute6 -q 1 -w 2 -n %q 2>&1", addr)
|
||||
end
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue