Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 0x4A6F-master
  • 0x4A6F-rpi4
  • autinerd/experimental-openwrt-24.10
  • experimental
  • feature/addMikrotikwAP
  • master
  • nrb/airmax-test
  • nrb/ar9344-reset-sequence
  • nrb/ex400-remove-wps
  • nrb/gluon-master-cpe510
  • nrb/test-radv-filter
  • nrbffs/fastd-remove-delay
  • nrbffs/netgear-ex6120
  • v2018.2.2-ffs
  • v2018.2.3-ffs
  • v2019.1-ffs
  • v2019.1.1-ffs
  • v2019.1.2-ffs
  • v2020.1-ffs
  • v2020.1.1-ffs
  • v2020.1.3-ffs
  • v2020.2-ffs
  • v2020.2.1-ffs
  • v2020.2.2-ffs
  • v2020.2.3-ffs
  • v2021.1-ffs
  • v2021.1.1-ffs
  • v2021.1.2-ffs
  • v2022.1.1-ffs
  • v2022.1.3-ffs
  • v2022.1.4-ffs
  • v2023.1-ffs
  • v2023.2-ffs
  • v2023.2.2-ffs
  • v2023.2.3-ffs
  • v2023.2.4-ffs
  • v2023.2.5-ffs
  • experimental-2022-09-24
  • experimental-2022-09-24-base
  • experimental-2023-03-11
  • experimental-2023-03-11-base
  • experimental-2023-03-12
  • experimental-2023-03-12-base
  • experimental-2023-03-16
  • experimental-2023-03-16-base
  • experimental-2023-03-20
  • experimental-2023-03-20-base
  • experimental-2023-03-23
  • experimental-2023-03-23-base
  • experimental-2023-03-25
  • experimental-2023-03-25-base
  • experimental-2023-03-26
  • experimental-2023-03-26-base
  • experimental-2023-03-30
  • experimental-2023-03-30-base
  • experimental-2023-03-31
  • experimental-2023-03-31-base
  • experimental-2023-04-01
  • experimental-2023-04-01-base
  • experimental-2023-04-08
  • experimental-2023-04-08-base
  • experimental-2023-04-10
  • experimental-2023-04-10-base
  • experimental-2023-04-13
  • experimental-2023-04-13-base
  • experimental-2023-04-15
  • experimental-2023-04-15-base
  • experimental-2023-04-16
  • experimental-2023-04-16-base
  • experimental-2023-04-18
  • experimental-2023-04-18-base
  • experimental-2023-04-20
  • experimental-2023-04-20-base
  • experimental-2023-04-26
  • experimental-2023-04-26-base
  • experimental-2023-04-28
  • experimental-2023-04-28-base
  • experimental-2023-04-30
  • experimental-2023-04-30-base
  • experimental-2023-05-02
  • experimental-2023-05-02-base
  • experimental-2023-05-03
  • experimental-2023-05-03-base
  • experimental-2023-05-12
  • experimental-2023-05-12-base
  • experimental-2023-05-21
  • experimental-2023-05-21-base
  • experimental-2023-05-25
  • experimental-2023-05-25-base
  • experimental-2023-07-02
  • experimental-2023-07-02-base
  • experimental-2023-07-04
  • experimental-2023-07-04-base
  • experimental-2023-07-12
  • experimental-2023-07-12-base
  • experimental-2023-07-16
  • experimental-2023-07-16-base
  • experimental-2023-08-04
  • experimental-2023-08-04-base
  • experimental-2023-08-10
  • experimental-2023-08-10-base
  • experimental-2023-09-08
  • experimental-2023-09-08-base
  • experimental-2023-09-09
  • experimental-2023-09-09-base
  • experimental-2023-09-10
  • experimental-2023-09-10-base
  • experimental-2023-09-11
  • experimental-2023-09-11-base
  • experimental-2023-09-12
  • experimental-2023-09-12-base
  • experimental-2023-09-13
  • experimental-2023-09-13-base
  • experimental-2023-09-15
  • experimental-2023-09-15-base
  • experimental-2023-09-16
  • experimental-2023-09-16-base
  • experimental-2023-09-18
  • experimental-2023-09-18-base
  • experimental-2023-09-20
  • experimental-2023-09-20-base
  • experimental-2023-09-27
  • experimental-2023-09-27-base
  • experimental-2023-09-28
  • experimental-2023-09-28-base
  • experimental-2023-09-29
  • experimental-2023-09-29-base
  • experimental-2023-10-02
  • experimental-2023-10-02-base
  • experimental-2023-10-13
  • experimental-2023-10-13-base
  • experimental-2023-10-14
  • experimental-2023-10-14-base
  • experimental-2023-10-16
  • experimental-2023-10-16-base
  • experimental-2023-10-23
  • experimental-2023-10-23-base
137 results

Target

Select target project
  • firmware/gluon
  • 0x4A6F/gluon
  • patrick/gluon
3 results
Select Git revision
  • 0x4A6F-master
  • 0x4A6F-rpi4
  • 2014.3.x
  • 2014.4.x
  • babel
  • experimental
  • hoodselector
  • master
  • nrb/gluon-master-cpe510
  • nrb/test-radv-filter
  • nrbffs/fastd-remove-delay
  • nrbffs/netgear-ex6120
  • radv-filterd
  • v2015.1.x
  • v2016.1.x
  • v2016.2.4-batmanbug
  • v2016.2.x
  • v2018.2.2-ffs
  • v2018.2.3-ffs
  • v2018.2.x
  • v2019.1-ffs
  • v2019.1.1-ffs
  • v2019.1.2-ffs
  • v2020.1-ffs
  • v2020.1.1-ffs
  • v2020.1.3-ffs
  • v2020.2-ffs
  • v2020.2.1-ffs
  • v2020.2.2-ffs
  • v2020.2.3-ffs
  • v2020.2.x
  • v2021.1-ffs
  • v2021.1.1-ffs
  • v2021.1.2-ffs
  • v2014.1
  • v2014.2
  • v2014.3
  • v2014.3.1
  • v2014.4
  • v2015.1
  • v2015.1.1
  • v2015.1.2
  • v2016.1
  • v2016.1.1
  • v2016.1.2
  • v2016.1.3
  • v2016.1.4
  • v2016.1.5
  • v2016.1.6
  • v2016.2
  • v2016.2.1
  • v2016.2.2
  • v2016.2.3
  • v2016.2.4
  • v2016.2.5
  • v2016.2.6
  • v2016.2.7
  • v2017.1
  • v2017.1.1
  • v2017.1.2
  • v2017.1.3
  • v2017.1.4
  • v2017.1.5
  • v2017.1.6
  • v2017.1.7
  • v2017.1.8
  • v2018.1
  • v2018.1.1
  • v2018.1.2
  • v2018.1.3
  • v2018.1.4
  • v2018.2
  • v2018.2-ffs0.1
  • v2018.2.1
  • v2018.2.1-ffs0.1
  • v2018.2.2-ffs0.1
  • v2018.2.3-ffs0.1
  • v2019.1-ffs0.1
  • v2019.1.1-ffs0.1
  • v2019.1.2-ffs0.1
  • v2020.1-ffs0.1
  • v2020.1.1-ffs0.1
  • v2020.1.3-ffs0.1
  • v2020.2
  • v2020.2-ffs0.1
  • v2020.2.1-ffs0.1
  • v2020.2.2-ffs0.1
  • v2020.2.3-ffs0.1
  • v2020.2.3-ffs0.2
  • v2020.2.3-ffs0.3
  • v2020.2.x-ffs0.1
  • v2021.1-ffs0.1
  • v2021.1.1-ffs0.1
  • v2021.1.1-ffs0.2
  • v2021.1.1-ffs0.3
  • v2021.1.1-ffs0.4
  • v2021.1.2-ffs0.1
  • v2021.1.2-ffs0.2
98 results
Show changes
Showing
with 1565 additions and 19 deletions
......@@ -19,14 +19,33 @@ msgstr "2,4GHz-WLAN"
msgid "5GHz WLAN"
msgstr "5GHz-WLAN"
msgid ""
"Configuring the node for outdoor use tunes the 5 GHz radio to a frequency "
"and transmission power that conforms with the local regulatory requirements. "
"It also enables dynamic frequency selection (DFS; radar detection). At the "
"same time, mesh functionality is disabled as it requires neighbouring nodes "
"to stay on the same channel permanently."
msgstr ""
"Ist der Knoten für den Einsatz im Freien konfiguriert, wird ein WLAN-Kanal "
"auf dem 5-GHz-Band sowie eine Sendeleistung entsprechend den gesetzlichen "
"Frequenzregulatorien gewählt. Gleichzeitig wird die dynamische Frequenzwahl "
"(DFS; Radarerkennung) aktiviert und die Mesh-Funktionalität deaktiviert, da "
"sich Nachbarknoten dauerhaft auf demselben Kanal befinden müssen."
msgid "Enable client network (access point)"
msgstr "Client-Netz aktivieren (Access Point)"
msgid "Enable mesh network (802.11s)"
msgstr "Mesh-Netz aktivieren (802.11s)"
msgid "Enable mesh network (IBSS)"
msgstr "Mesh-Netz aktivieren (IBSS)"
msgid "HT Mode"
msgstr "HT-Modus"
msgid "Node will be installed outdoors"
msgstr "Knoten wird im Außenbereich betrieben"
msgid "Outdoor Installation"
msgstr "Outdoor-Installation"
msgid "Transmission power"
msgstr "Sendeleistung"
......@@ -37,15 +56,15 @@ msgstr "WLAN"
msgid ""
"You can enable or disable your node's client and mesh network SSIDs here. "
"Please don't disable the mesh network without a good reason, so other nodes "
"can mesh with yours.<br /><br />It is also possible to configure the WLAN "
"can mesh with yours.<br><br>It is also possible to configure the WLAN "
"adapters transmission power here. Please note that the transmission power "
"values include the antenna gain where available, but there are many devices "
"for which the gain is unavailable or inaccurate."
msgstr ""
"In diesem Abschnitt hast du die Möglichkeit, die SSIDs des Client- und des "
"Mesh-Netzes zu aktivieren bzw. deaktivieren. Bitte lass die SSID des Mesh-"
"Netzes aktiviert, damit sich andere Knoten mit deinem verbinden können.<br /"
"><br />Außerdem kann hier die Sendeleistung des WLAN-Adapters konfiguriert "
"Netzes aktiviert, damit sich andere Knoten mit deinem verbinden können.<br"
"><br>Außerdem kann hier die Sendeleistung des WLAN-Adapters konfiguriert "
"werden. Wenn möglich, ist in den Werten der Sendeleistung der Antennengewinn "
"enthalten; diese Werte sind allerdings für viele Geräte nicht verfügbar oder "
"fehlerhaft."
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: PACKAGE VERSION\n"
"PO-Revision-Date: 2015-08-19 23:30+0100\n"
"Last-Translator:Tobias Bernot <tqbs@airmail.cc>\n"
"Language-Team: French\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "(default)"
msgstr "(défaut)"
msgid "2.4GHz WLAN"
msgstr "2,4GHz-WLAN"
msgstr "2,4GHz Wi-Fi"
msgid "5GHz WLAN"
msgstr "5GHz-WLAN"
msgstr "5GHz Wi-Fi"
msgid ""
"Configuring the node for outdoor use tunes the 5 GHz radio to a frequency "
"and transmission power that conforms with the local regulatory requirements. "
"It also enables dynamic frequency selection (DFS; radar detection). At the "
"same time, mesh functionality is disabled as it requires neighbouring nodes "
"to stay on the same channel permanently."
msgstr ""
msgid "Enable client network (access point)"
msgstr "Activer le réseau client (Access Point)"
......@@ -24,25 +33,32 @@ msgstr "Activer le réseau client (Access Point)"
msgid "Enable mesh network (802.11s)"
msgstr "Activer le réseau MESH (802.11s)"
msgid "Enable mesh network (IBSS)"
msgstr "Activer le réseau MESH (IBSS)"
msgid "HT Mode"
msgstr "Mode HT"
msgid "Node will be installed outdoors"
msgstr ""
msgid "Outdoor Installation"
msgstr "Installation extérieure"
msgid "Transmission power"
msgstr "Puissance d'émission"
msgid "WLAN"
msgstr "WLAN"
msgstr "Wi-Fi"
msgid ""
"You can enable or disable your node's client and mesh network SSIDs here. "
"Please don't disable the mesh network without a good reason, so other nodes "
"can mesh with yours.<br /><br />It is also possible to configure the WLAN "
"can mesh with yours.<br><br>It is also possible to configure the WLAN "
"adapters transmission power here. Please note that the transmission power "
"values include the antenna gain where available, but there are many devices "
"for which the gain is unavailable or inaccurate."
msgstr ""
"Ici vous pouvez activer ou désactiver la SSID du client ou MESH. "
"Pensez a laisser la SSID du MESH activée pour que les autres nœuds puissent se connecter. "
"<br /><br />Ici vous pouvez aussi configurer la puissance d'émmission se votre WLAN. "
"Prenez note que les valeurs fournies pour la puissance de transmission prennent "
"en compte les gains fournis par l'antenne, et que ces valeurs ne sont pas toujours disponibles ou exactes."
"Ici vous pouvez activer ou désactiver la SSID du client ou MESH. Pensez a "
"laisser la SSID du MESH activée pour que les autres nœuds puissent se "
"connecter. <br><br>Ici vous pouvez aussi configurer la puissance "
"d'émmission se votre Wi-Fi. Prenez note que les valeurs fournies pour la "
"puissance de transmission prennent en compte les gains fournis par "
"l'antenne, et que ces valeurs ne sont pas toujours disponibles ou exactes."
......@@ -10,13 +10,27 @@ msgstr ""
msgid "5GHz WLAN"
msgstr ""
msgid ""
"Configuring the node for outdoor use tunes the 5 GHz radio to a frequency "
"and transmission power that conforms with the local regulatory requirements. "
"It also enables dynamic frequency selection (DFS; radar detection). At the "
"same time, mesh functionality is disabled as it requires neighbouring nodes "
"to stay on the same channel permanently."
msgstr ""
msgid "Enable client network (access point)"
msgstr ""
msgid "Enable mesh network (802.11s)"
msgstr ""
msgid "Enable mesh network (IBSS)"
msgid "HT Mode"
msgstr ""
msgid "Node will be installed outdoors"
msgstr ""
msgid "Outdoor Installation"
msgstr ""
msgid "Transmission power"
......@@ -28,7 +42,7 @@ msgstr ""
msgid ""
"You can enable or disable your node's client and mesh network SSIDs here. "
"Please don't disable the mesh network without a good reason, so other nodes "
"can mesh with yours.<br /><br />It is also possible to configure the WLAN "
"can mesh with yours.<br><br>It is also possible to configure the WLAN "
"adapters transmission power here. Please note that the transmission power "
"values include the antenna gain where available, but there are many devices "
"for which the gain is unavailable or inaccurate."
......
local uci = require("simple-uci").cursor()
local wireless = require 'gluon.wireless'
package 'gluon-web-wifi-config'
if wireless.device_uses_wlan(uci) then
entry({"admin", "wifi-config"}, model("admin/wifi-config"), _("WLAN"), 20)
end
local iwinfo = require 'iwinfo'
local uci = require("simple-uci").cursor()
local site = require 'gluon.site'
local wireless = require 'gluon.wireless'
local function txpower_list(phy)
local list = iwinfo.nl80211.txpwrlist(phy) or { }
local off = tonumber(iwinfo.nl80211.txpower_offset(phy)) or 0
local new = { }
local prev = -1
for _, val in ipairs(list) do
local dbm = val.dbm + off
local mw = math.floor(10 ^ (dbm / 10))
if mw ~= prev then
prev = mw
table.insert(new, {
display_dbm = dbm,
display_mw = mw,
driver_dbm = val.dbm,
})
end
end
return new
end
local f = Form(translate("WLAN"))
f:section(Section, nil, translate(
"You can enable or disable your node's client and mesh network "
.. "SSIDs here. Please don't disable the mesh network without "
.. "a good reason, so other nodes can mesh with yours.<br><br>"
.. "It is also possible to configure the WLAN adapters transmission power "
.. "here. Please note that the transmission power values include the antenna gain "
.. "where available, but there are many devices for which the gain is unavailable or inaccurate."
))
local mesh_vifs_5ghz = {}
uci:foreach('wireless', 'wifi-device', function(config)
local radio = config['.name']
local is_5ghz = false
local title
if config.band == '2g' then
title = translate("2.4GHz WLAN")
elseif config.band == '5g' then
is_5ghz = true
title = translate("5GHz WLAN")
else
return
end
local p = f:section(Section, title)
local function filter_existing_interfaces(interfaces)
local out = {}
for _, interface in ipairs(interfaces) do
if uci:get('wireless', interface .. '_' .. radio) then
table.insert(out, interface)
end
end
return out
end
local function has_active_interfaces(interfaces)
for _, interface in ipairs(interfaces) do
if not uci:get_bool('wireless', interface .. '_' .. radio, 'disabled') then
return true
end
end
return false
end
local function vif_option(name, interfaces, msg)
local existing_interfaces = filter_existing_interfaces(interfaces)
if #existing_interfaces == 0 then
return
end
local o = p:option(Flag, radio .. '_' .. name .. '_enabled', msg)
o.default = has_active_interfaces(existing_interfaces)
function o:write(data)
for _, interface in ipairs(existing_interfaces) do
uci:set('wireless', interface .. '_' .. radio, 'disabled', not data)
end
end
return o
end
vif_option('client', {'client', 'owe'}, translate('Enable client network (access point)'))
local mesh_vif = vif_option('mesh', {'mesh'}, translate("Enable mesh network (802.11s)"))
if is_5ghz then
table.insert(mesh_vifs_5ghz, mesh_vif)
end
local phy = wireless.find_phy(config)
if not phy then
return
end
local txpowers = txpower_list(phy)
if #txpowers <= 1 then
return
end
local tp = p:option(ListValue, radio .. '_txpower', translate("Transmission power"))
tp.default = uci:get('wireless', radio, 'txpower') or 'default'
tp:value('default', translate("(default)"))
table.sort(txpowers, function(a, b) return a.driver_dbm > b.driver_dbm end)
for _, entry in ipairs(txpowers) do
tp:value(entry.driver_dbm, string.format("%i dBm (%i mW)", entry.display_dbm, entry.display_mw))
end
function tp:write(data)
if data == 'default' then
data = nil
end
uci:set('wireless', radio, 'txpower', data)
end
end)
if wireless.device_uses_11a(uci) and not wireless.preserve_channels(uci) then
local r = f:section(Section, translate("Outdoor Installation"), translate(
"Configuring the node for outdoor use tunes the 5 GHz radio to a frequency "
.. "and transmission power that conforms with the local regulatory requirements. "
.. "It also enables dynamic frequency selection (DFS; radar detection). At the "
.. "same time, mesh functionality is disabled as it requires neighbouring nodes "
.. "to stay on the same channel permanently."
))
local outdoor = r:option(Flag, 'outdoor', translate("Node will be installed outdoors"))
outdoor.default = uci:get_bool('gluon', 'wireless', 'outdoor')
for _, mesh_vif in ipairs(mesh_vifs_5ghz) do
mesh_vif:depends(outdoor, false)
if outdoor.default then
mesh_vif.default = not site.wifi5.mesh.disabled(false)
end
end
function outdoor:write(data)
uci:set('gluon', 'wireless', 'outdoor', data)
end
uci:foreach('wireless', 'wifi-device', function(config)
local radio = config['.name']
local band = uci:get('wireless', radio, 'band')
if band ~= '5g' then
return
end
local phy = wireless.find_phy(config)
local ht = r:option(ListValue, 'outdoor_htmode', translate('HT Mode') .. ' (' .. radio .. ')')
ht:depends(outdoor, true)
ht.default = uci:get('gluon', 'wireless', 'outdoor_' .. radio .. '_htmode') or 'default'
ht:value('default', translate("(default)"))
for mode, available in pairs(iwinfo.nl80211.htmodelist(phy)) do
if available then
ht:value(mode, mode)
end
end
function ht:write(data)
if data == 'default' then
data = nil
end
uci:set('gluon', 'wireless', 'outdoor_' .. radio .. '_htmode', data)
end
end)
end
function f:write()
uci:commit('gluon')
os.execute('/lib/gluon/upgrade/200-wireless')
uci:commit('network')
uci:commit('wireless')
end
return f
include $(TOPDIR)/rules.mk
PKG_NAME:=gluon-web
PKG_INSTALL:=1
include ../gluon.mk
include $(INCLUDE_DIR)/host-build.mk
define Package/gluon-web
TITLE:=Minimal Lua web framework derived from LuCI
DEPENDS:=+lua-jsonc +luaposix
endef
define lang-config
config GLUON_WEB_LANG_$(1)
bool "$(GLUON_LANG_$(1)) language support for gluon-web"
depends on PACKAGE_gluon-web
endef
define Package/gluon-web/config
$(foreach lang,$(GLUON_SUPPORTED_LANGS),$(call lang-config,$(lang)))
endef
define Host/Prepare
$(CP) ./src/* $(HOST_BUILD_DIR)
endef
define Host/Compile
$(call Host/Compile/Default,gluon-po2lmo)
endef
define Host/Install
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(HOST_BUILD_DIR)/gluon-po2lmo $(1)/bin/
endef
$(eval $(call BuildPackageGluon,gluon-web))
$(eval $(call HostBuild))
<%#
SPDX-FileCopyrightText: 2008 Steven Barth <steven@midlink.org>
SPDX-FileCopyrightText: 2008 Jo-Philipp Wich <jow@openwrt.org>
SPDX-License-Identifier: Apache-2.0
-%>
<h2 name="content">404 <%:Not Found%></h2>
<p><%:Sorry, the object you requested was not found.%></p>
<tt><%|message%></tt>
<%#
SPDX-FileCopyrightText: 2008 Steven Barth <steven@midlink.org>
SPDX-FileCopyrightText: 2008 Jo-Philipp Wich <jow@openwrt.org>
SPDX-License-Identifier: Apache-2.0
-%>
<h2 name="content">500 <%:Internal Server Error%></h2>
<p><%:Sorry, the server encountered an unexpected error.%></p>
<pre class="error500"><%|message%></pre>
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"PO-Revision-Date: 2013-03-29 12:13+0200\n"
"Last-Translator: Matthias Schiffer <mschiffer@universe-factory.net>\n"
"Language-Team: German\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Internal Server Error"
msgstr "Interner Serverfehler"
msgid "Not Found"
msgstr "Nicht Gefunden"
msgid "Sorry, the object you requested was not found."
msgstr "Entschuldigung, das angeforderte Objekt wurde nicht gefunden."
msgid "Sorry, the server encountered an unexpected error."
msgstr ""
"Entschuldigung, auf dem Server ist ein unerwarteter Fehler aufgetreten."
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"PO-Revision-Date: 2013-12-22 17:11+0200\n"
"Last-Translator: goofy <pierre.gaufillet@gmail.com>\n"
"Language-Team: French\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
msgid "Internal Server Error"
msgstr "Erreur Serveur Interne"
msgid "Not Found"
msgstr "Pas trouvé"
msgid "Sorry, the object you requested was not found."
msgstr "Désolé, l'objet que vous avez demandé n'as pas été trouvé."
msgid "Sorry, the server encountered an unexpected error."
msgstr "Désolé, le serveur à rencontré une erreur inattendue."
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "Internal Server Error"
msgstr ""
msgid "Not Found"
msgstr ""
msgid "Sorry, the object you requested was not found."
msgstr ""
msgid "Sorry, the server encountered an unexpected error."
msgstr ""
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2017 Matthias Schiffer <mschiffer@universe-factory.net>
-- Licensed to the public under the Apache License 2.0.
local stdlib = require 'posix.stdlib'
local http = require 'gluon.web.http'
local dispatcher = require 'gluon.web.dispatcher'
-- Limited source to avoid endless blocking
local function limitsource(handle, limit)
limit = limit or 0
local BLOCKSIZE = 2048
return function()
if limit < 1 then
handle:close()
return nil
else
local read = (limit > BLOCKSIZE) and BLOCKSIZE or limit
limit = limit - read
local chunk = handle:read(read)
if not chunk then handle:close() end
return chunk
end
end
end
return function(config)
local env = stdlib.getenv()
dispatcher(config, http.Http(
env,
limitsource(io.stdin, tonumber(env.CONTENT_LENGTH)),
io.stdout
))
end
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org>
-- Copyright 2017-2018 Matthias Schiffer <mschiffer@universe-factory.net>
-- Licensed to the public under the Apache License 2.0.
local glob = require 'posix.glob'
local json = require "jsonc"
local tpl = require "gluon.web.template"
local util = require "gluon.web.util"
local proto = require "gluon.web.http.protocol"
local function build_url(http, path)
return (http:getenv("SCRIPT_NAME") or "") .. "/" .. table.concat(path, "/")
end
local function set_language(renderer, accept)
local langs = {}
local weights = {}
local star = 0
local function add(lang, q)
if not weights[lang] then
table.insert(langs, lang)
weights[lang] = q
end
end
for match in accept:gmatch("[^,]+") do
local lang = match:match('^%s*([^%s;_-]+)')
local q = tonumber(match:match(';q=(%S+)%s*$') or 1)
if lang == '*' then
star = q
elseif lang and q > 0 then
add(lang, q)
end
end
add('en', star)
table.sort(langs, function(a, b)
return (weights[a] or 0) > (weights[b] or 0)
end)
renderer.set_language(langs)
end
local function dispatch(config, http, request)
local tree = {nodes={}}
local nodes = {[''] = tree}
local function _node(path, create)
local name = table.concat(path, ".")
local c = nodes[name]
if not c and create then
local last = table.remove(path)
local parent = _node(path, true)
c = {nodes={}}
parent.nodes[last] = c
nodes[name] = c
end
return c
end
-- Init template engine
local function attr(key, val)
if not val then
return ''
end
if type(val) == "table" then
val = json.stringify(val)
end
return string.format(' %s="%s"', key, util.pcdata(tostring(val)))
end
local renderer = tpl(config, setmetatable({
http = http,
request = request,
node = function(path) return _node({path}) end,
write = function(...) return http:write(...) end,
pcdata = util.pcdata,
urlencode = proto.urlencode,
attr = attr,
json = json.stringify,
url = function(path) return build_url(http, path) end,
}, { __index = _G }))
local function createtree()
local base = config.base_path .. "/controller/"
local function load_ctl(path)
local ctl = assert(loadfile(path))
local _pkg
local subdisp = setmetatable({
package = function(name)
_pkg = name
end,
node = function(...)
return _node({...})
end,
entry = function(entry_path, target, title, order)
local c = _node(entry_path, true)
c.target = target
c.title = title
c.order = order
c.pkg = _pkg
return c
end,
alias = function(...)
local req = {...}
return function()
http:redirect(build_url(http, req))
end
end,
call = function(func, ...)
local args = {...}
return function()
func(http, renderer, unpack(args))
end
end,
template = function(view, scope)
local pkg = _pkg
return function()
renderer.render_layout(view, scope, pkg)
end
end,
model = function(name)
local pkg = _pkg
return function()
require('gluon.web.model')(config, http, renderer, name, pkg)
end
end,
_ = function(text)
return text
end,
}, { __index = _G })
local env = setmetatable({}, { __index = subdisp })
setfenv(ctl, env)
ctl()
end
for _, path in ipairs(glob.glob(base .. "*.lua", 0) or {}) do
load_ctl(path)
end
for _, path in ipairs(glob.glob(base .. "*/*.lua", 0) or {}) do
load_ctl(path)
end
end
set_language(renderer, http:getenv("HTTP_ACCEPT_LANGUAGE") or "")
createtree()
local node = _node(request)
if not node or not node.target then
http:status(404, "Not Found")
renderer.render_layout("error/404", {
message =
"No page is registered at '/" .. table.concat(request, "/") .. "'.\n" ..
"If this URL belongs to an extension, make sure it is properly installed.\n",
}, 'gluon-web')
return
end
local ok, err = pcall(http.parse_input, http, node.filehandler)
if not ok then
http:status(400, "Bad request")
http:prepare_content("text/plain")
http:write(err .. "\r\n")
return
end
ok, err = pcall(node.target)
if not ok then
http:status(500, "Internal Server Error")
renderer.render_layout("error/500", {
message =
"Failed to execute dispatcher target for entry '/" .. table.concat(request, "/") .. "'.\n" ..
"The called action terminated with an exception:\n" .. tostring(err or "(unknown)"),
}, 'gluon-web')
end
end
return function(config, http)
local request = {}
local pathinfo = proto.urldecode(http:getenv("PATH_INFO") or "", true)
for node in pathinfo:gmatch("[^/]+") do
table.insert(request, node)
end
local ok, err = pcall(dispatch, config, http, request)
if not ok then
http:status(500, "Internal Server Error")
http:prepare_content("text/plain")
http:write(err .. "\r\n")
end
end
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2017 Matthias Schiffer <mschiffer@universe-factory.net>
-- Licensed to the public under the Apache License 2.0.
local protocol = require "gluon.web.http.protocol"
local util = require "gluon.web.util"
local M = {}
local Http = util.class()
M.Http = Http
function Http:__init__(env, input, output)
self.input = input
self.output = output
self.request = {
env = env,
headers = {},
params = protocol.urldecode_params(env.QUERY_STRING or ""),
}
self.headers = {}
end
local function push_headers(self)
if self.eoh then return end
for _, header in pairs(self.headers) do
self.output:write(string.format("%s: %s\r\n", header[1], header[2]))
end
self.output:write("\r\n")
self.eoh = true
end
function Http:parse_input(filehandler)
protocol.parse_message_body(
self.input,
self.request,
filehandler
)
end
function Http:formvalue(name)
return self:formvaluetable(name)[1]
end
function Http:formvaluetable(name)
return self.request.params[name] or {}
end
function Http:getcookie(name)
local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";")
local p = ";" .. name .. "=(.-);"
local _, _, value = c:find(p)
return value and protocol.urldecode(value)
end
function Http:getenv(name)
return self.request.env[name]
end
function Http:close()
if not self.output then return end
push_headers(self)
self.output:flush()
self.output:close()
self.output = nil
end
function Http:header(key, value)
self.headers[key:lower()] = {key, value}
end
function Http:prepare_content(mime)
if self.headers["content-type"] then return end
self:header("Content-Type", mime)
end
function Http:status(code, request)
if not self.output or self.code then return end
code = code or 200
request = request or "OK"
self.code = code
self.output:write(string.format("Status: %i %s\r\n", code, request))
end
function Http:write(content)
if not self.output then return end
self:status()
self:prepare_content("text/html; charset=utf-8")
if not self.headers["cache-control"] then
self:header("Cache-Control", "no-cache")
self:header("Expires", "0")
end
push_headers(self)
self.output:write(content)
end
function Http:redirect(url)
self:status(302, "Found")
self:header("Location", url)
self:close()
end
return M
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
-- Copyright 2017 Matthias Schiffer <mschiffer@universe-factory.net>
-- Licensed to the public under the Apache License 2.0.
-- This class contains several functions useful for http message- and content
-- decoding and to retrieve form data from raw http messages.
local M = {}
local function pump(src, snk)
while true do
local chunk, src_err = src()
local ret, snk_err = snk(chunk, src_err)
if not (chunk and ret) then
local err = src_err or snk_err
if err then
return nil, err
else
return true
end
end
end
end
function M.urlencode(s)
return (string.gsub(s, '[^a-zA-Z0-9%-_%.~]',
function(c)
local ret = ''
for i = 1, string.len(c) do
ret = ret .. string.format('%%%02X', string.byte(c, i, i))
end
return ret
end
))
end
-- the "+" sign to " " - and return the decoded string.
function M.urldecode(str, no_plus)
local function chrdec(hex)
return string.char(tonumber(hex, 16))
end
if type(str) == "string" then
if not no_plus then
str = str:gsub("+", " ")
end
str = str:gsub("%%(%x%x)", chrdec)
end
return str
end
local function initval(tbl, key)
if not tbl[key] then
tbl[key] = {}
end
table.insert(tbl[key], "")
end
local function appendval(tbl, key, chunk)
local t = tbl[key]
t[#t] = t[#t] .. chunk
end
-- from given url or string. Returns a table with urldecoded values.
-- Simple parameters are stored as string values associated with the parameter
-- name within the table. Parameters with multiple values are stored as array
-- containing the corresponding values.
function M.urldecode_params(url)
local params = {}
if url:find("?") then
url = url:gsub("^.+%?([^?]+)", "%1")
end
for pair in url:gmatch("[^&;]+") do
-- find key and value
local key = M.urldecode(pair:match("^([^=]+)"))
local val = M.urldecode(pair:match("^[^=]+=(.+)$"))
-- store
if key and key:len() > 0 then
initval(params, key)
if val then
appendval(params, key, val)
end
end
end
return params
end
-- Content-Type. Stores all extracted data associated with its parameter name
-- in the params table within the given message object. Multiple parameter
-- values are stored as tables, ordinary ones as strings.
-- If an optional file callback function is given then it is fed with the
-- file contents chunk by chunk and only the extracted file name is stored
-- within the params table. The callback function will be called subsequently
-- with three arguments:
-- o Table containing decoded (name, file) and raw (headers) mime header data
-- o String value containing a chunk of the file data
-- o Boolean which indicates whether the current chunk is the last one (eof)
local function mimedecode_message_body(src, msg, filecb)
local mime_boundary = (msg.env.CONTENT_TYPE or ''):match("^multipart/form%-data; boundary=(.+)$")
if not mime_boundary then
error("Invalid Content-Type found")
end
local tlen = 0
local inhdr = false
local field = nil
local store = nil
local lchunk = nil
local function parse_headers(chunk, pfield)
local stat
repeat
chunk, stat = chunk:gsub(
"^([A-Z][A-Za-z0-9%-_]+): +([^\r\n]+)\r\n",
function(k,v)
pfield.headers[k] = v
return ""
end
)
until stat == 0
chunk, stat = chunk:gsub("^\r\n","")
-- End of headers
if stat > 0 then
if pfield.headers["Content-Disposition"] then
if pfield.headers["Content-Disposition"]:match("^form%-data; ") then
pfield.name = pfield.headers["Content-Disposition"]:match('name="(.-)"')
pfield.file = pfield.headers["Content-Disposition"]:match('filename="(.+)"$')
end
end
if not pfield.headers["Content-Type"] then
pfield.headers["Content-Type"] = "text/plain"
end
if pfield.name then
initval(msg.params, pfield.name)
if pfield.file then
appendval(msg.params, pfield.name, pfield.file)
store = filecb
else
store = function(_, buf, _)
appendval(msg.params, pfield.name, buf)
end
end
else
store = nil
end
return chunk, true
end
return chunk, false
end
local function snk(chunk)
tlen = tlen + (chunk and #chunk or 0)
if msg.env.CONTENT_LENGTH and tlen > tonumber(msg.env.CONTENT_LENGTH) + 2 then
return nil, "Message body size exceeds Content-Length"
end
if chunk and not lchunk then
lchunk = "\r\n" .. chunk
elseif lchunk then
local data = lchunk .. (chunk or "")
local spos, epos, found
repeat
spos, epos = data:find("\r\n--" .. mime_boundary .. "\r\n", 1, true)
if not spos then
spos, epos = data:find("\r\n--" .. mime_boundary .. "--\r\n", 1, true)
end
if spos then
local predata = data:sub(1, spos - 1)
local eof
if inhdr then
predata, eof = parse_headers(predata, field)
if not eof then
return nil, "Invalid MIME section header"
elseif not field.name then
return nil, "Invalid Content-Disposition header"
end
end
if store then
store(field, predata, true)
end
field = { headers = { } }
found = true
data, eof = parse_headers(data:sub(epos + 1, #data), field)
inhdr = not eof
end
until not spos
if found then
-- We found at least some boundary. Save
-- the unparsed remaining data for the
-- next chunk.
lchunk = data
else
-- There was a complete chunk without a boundary. Parse it as headers or
-- append it as data, depending on our current state.
if inhdr then
local eof
lchunk, eof = parse_headers(data, field)
inhdr = not eof
else
-- We're inside data, so append the data. Note that we only append
-- lchunk, not all of data, since there is a chance that chunk
-- contains half a boundary. Assuming that each chunk is at least the
-- boundary in size, this should prevent problems
if store then
store(field, lchunk, false)
end
lchunk = chunk
end
end
end
return true
end
assert(pump(src, snk))
end
local function check_post_origin(msg)
local default_port = '80'
local request_scheme = 'http'
if msg.env.HTTPS then
default_port = '443'
request_scheme = 'https'
end
local request_host = msg.env.HTTP_HOST
if not request_host then
error('POST request without Host header')
end
if not request_host:match(':[0-9]+$') then
request_host = request_host .. ':' .. default_port
end
local origin = msg.env.HTTP_ORIGIN
if not origin then
error('POST request without Origin header')
end
local origin_scheme, origin_host = origin:match('^([^:]*)://(.*)$')
if not origin_host then
error('POST request with invalid Origin header')
end
if not origin_host:match(':[0-9]+$') then
local origin_port
if origin_scheme == 'http' then
origin_port = '80'
elseif origin_scheme == 'https' then
origin_port = '443'
else
error('POST request with invalid Origin header')
end
origin_host = origin_host .. ':' .. origin_port
end
if request_scheme ~= origin_scheme or request_host ~= origin_host then
error('Invalid cross-origin POST')
end
end
-- This function will examine the Content-Type within the given message object
-- to select the appropriate content decoder.
-- Currently only the multipart/form-data mime type is supported.
function M.parse_message_body(src, msg, filecb)
if msg.env.REQUEST_METHOD ~= "POST" then
return
end
check_post_origin(msg)
mimedecode_message_body(src, msg, filecb)
end
return M
-- Copyright 2018 Matthias Schiffer <mschiffer@universe-factory.net>
-- Licensed to the public under the Apache License 2.0.
local tparser = require 'gluon.web.template.parser'
local unistd = require 'posix.unistd'
return function(config)
local i18ndir = config.base_path .. "/i18n"
local function i18n_file(lang, pkg)
return string.format('%s/%s.%s.lmo', i18ndir, pkg, lang)
end
local function no_translation()
return nil
end
local function load_catalog(lang, pkg)
if pkg then
local file = i18n_file(lang, pkg)
local cat = unistd.access(file) and tparser.load_catalog(file)
if cat then return cat end
end
return no_translation
end
local i18n = {}
function i18n.supported(lang)
return lang == 'en' or unistd.access(i18n_file(lang, 'gluon-web'))
end
function i18n.load(lang, pkg)
local _translate = load_catalog(lang, pkg)
local function translate(key)
return _translate(key) or key
end
local function translatef(key, ...)
return translate(key):format(...)
end
return {
_translate = _translate,
translate = translate,
translatef = translatef,
}
end
return i18n
end
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2017-2018 Matthias Schiffer <mschiffer@universe-factory.net>
-- Licensed to the public under the Apache License 2.0.
local tparser = require 'gluon.web.template.parser'
local tostring, ipairs, setmetatable, setfenv = tostring, ipairs, setmetatable, setfenv
local pcall, assert = pcall, assert
return function(config, env)
local i18n = require('gluon.web.i18n')(config)
local viewdir = config.base_path .. '/view/'
local ctx = {}
local language = 'en'
local catalogs = {}
function ctx.set_language(langs)
for _, lang in ipairs(langs) do
if i18n.supported(lang) then
language = lang
catalogs = {}
return
end
end
end
function ctx.i18n(pkg)
local cat = catalogs[pkg] or i18n.load(language, pkg)
if pkg then catalogs[pkg] = cat end
return cat
end
local function render_template(name, template, scope, pkg)
scope = scope or {}
local t = ctx.i18n(pkg)
local locals = {
renderer = ctx,
i18n = ctx.i18n,
translate = t.translate,
translatef = t.translatef,
_translate = t._translate,
include = function(include_name)
ctx.render(include_name, scope, pkg)
end,
}
setfenv(template, setmetatable({}, {
__index = function(_, key)
return scope[key] or locals[key] or env[key]
end
}))
-- Now finally render the thing
local stat, err = pcall(template)
assert(stat, "Failed to execute template '" .. name .. "'.\n" ..
"A runtime error occurred: " .. tostring(err or "(nil)"))
end
--- Render a certain template.
-- @param name Template name
-- @param scope Scope to assign to template (optional)
-- @param pkg i18n namespace package (optional)
function ctx.render(name, scope, pkg)
local sourcefile = viewdir .. name .. ".html"
local template, _, err = tparser.parse(sourcefile)
assert(template, "Failed to load template '" .. name .. "'.\n" ..
"Error while parsing template '" .. sourcefile .. "':\n" ..
(err or "Unknown syntax error"))
render_template(name, template, scope, pkg)
end
--- Render a template from a string.
-- @param template Template string
-- @param scope Scope to assign to template (optional)
-- @param pkg i18n namespace package (optional)
function ctx.render_string(str, scope, pkg)
local template, _, err = tparser.parse_string(str)
assert(template, "Error while parsing template:\n" ..
(err or "Unknown syntax error"))
render_template('(local)', template, scope, pkg)
end
--- Render a template, wrapped in the configured layout.
-- @param name Template name
-- @param scope Scope to assign to template (optional)
-- @param pkg i18n namespace package (optional)
-- @param layout_scope Additional variables to pass to the layout template
function ctx.render_layout(name, scope, pkg, layout_scope)
ctx.render(config.layout_template, setmetatable({
content = name,
scope = scope,
pkg = pkg,
}, {
__index = layout_scope
}), config.layout_package)
end
return ctx
end
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2017 Matthias Schiffer <mschiffer@universe-factory.net>
-- Licensed to the public under the Apache License 2.0.
local tparser = require "gluon.web.template.parser"
local M = {}
--
-- Class helper routines
--
-- Instantiates a class
local function _instantiate(class, ...)
local inst = setmetatable({}, {__index = class})
if inst.__init__ then
inst:__init__(...)
end
return inst
end
-- The class object can be instantiated by calling itself.
-- Any class functions or shared parameters can be attached to this object.
-- Attaching a table to the class object makes this table shared between
-- all instances of this class. For object parameters use the __init__ function.
-- Classes can inherit member functions and values from a base class.
-- Class can be instantiated by calling them. All parameters will be passed
-- to the __init__ function of this class - if such a function exists.
-- The __init__ function must be used to set any object parameters that are not shared
-- with other objects of this class. Any return values will be ignored.
function M.class(base)
return setmetatable({}, {
__call = _instantiate,
__index = base
})
end
function M.instanceof(object, class)
while object do
if object == class then
return true
end
local mt = getmetatable(object)
object = mt and mt.__index
end
return false
end
--
-- String and data manipulation routines
--
function M.pcdata(value)
return value and tparser.pcdata(tostring(value))
end
return M
all: compile
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -D_GNU_SOURCE -std=c99 -Wall -Wextra -fPIC -fvisibility=hidden -c -o $@ $<
clean:
rm -f parser.so *.o
parser.so: template_parser.o template_utils.o template_lmo.o template_lualib.o
$(CC) $(LDFLAGS) -shared -o $@ $^
gluon-po2lmo: gluon-po2lmo.o template_lmo.o
compile: parser.so
install: compile
mkdir -p $(DESTDIR)/usr/lib/lua/gluon/web/template
cp parser.so $(DESTDIR)/usr/lib/lua/gluon/web/template/parser.so
/*
* lmo - Lua Machine Objects - PO to LMO conversion tool
*
* Copyright (C) 2009-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
*
* 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"
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
__attribute__((noreturn))
static void die(const char *msg)
{
fprintf(stderr, "Error: %s\n", msg);
exit(1);
}
__attribute__((noreturn))
static void usage(const char *name)
{
fprintf(stderr, "Usage: %s input.po output.lmo\n", name);
exit(1);
}
static void print(const void *ptr, size_t size, size_t nmemb, FILE *stream)
{
if( fwrite(ptr, size, nmemb, stream) == 0 )
die("Failed to write stdout");
}
static ssize_t extract_string(const char *src, char *dest, size_t len)
{
size_t pos = 0;
int esc = 0;
int off = -1;
for( pos = 0; (pos < strlen(src)) && (pos < len); pos++ )
{
if( (off == -1) && (src[pos] == '"') )
{
off = pos + 1;
}
else if( off >= 0 )
{
if( esc == 1 )
{
switch (src[pos])
{
case '"':
case '\\':
off++;
break;
}
dest[pos-off] = src[pos];
esc = 0;
}
else if( src[pos] == '\\' )
{
dest[pos-off] = src[pos];
esc = 1;
}
else if( src[pos] != '"' )
{
dest[pos-off] = src[pos];
}
else
{
dest[pos-off] = '\0';
break;
}
}
}
return (off > -1) ? (ssize_t) strlen(dest) : -1;
}
static int cmp_index(const void *a, const void *b)
{
uint32_t x = ((const lmo_entry_t *)a)->key_id;
uint32_t y = ((const lmo_entry_t *)b)->key_id;
if (x < y)
return -1;
else if (x > y)
return 1;
return 0;
}
static void print_uint32(uint32_t x, FILE *out)
{
uint32_t y = htonl(x);
print(&y, sizeof(uint32_t), 1, out);
}
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_uint32(e->key_id, out);
print_uint32(e->val_id, out);
print_uint32(e->offset, out);
print_uint32(e->length, out);
}
}
int main(int argc, char *argv[])
{
char line[4096];
char key[4096];
char val[4096];
char tmp[4096];
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;
if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) )
usage(argv[0]);
memset(line, 0, sizeof(key));
memset(key, 0, sizeof(val));
memset(val, 0, sizeof(val));
while( (NULL != fgets(line, sizeof(line), in)) || (state >= 2 && feof(in)) )
{
if( state == 0 && strstr(line, "msgid \"") == line )
{
switch(extract_string(line, key, sizeof(key)))
{
case -1:
die("Syntax error in msgid");
case 0:
state = 1;
break;
default:
state = 2;
}
}
else if( state == 1 || state == 2 )
{
if( strstr(line, "msgstr \"") == line || state == 2 )
{
switch(extract_string(line, val, sizeof(val)))
{
case -1:
state = 4;
break;
default:
state = 3;
}
}
else
{
switch(extract_string(line, tmp, sizeof(tmp)))
{
case -1:
state = 2;
break;
default:
strcat(key, tmp);
}
}
}
else if( state == 3 )
{
switch(extract_string(line, tmp, sizeof(tmp)))
{
case -1:
state = 4;
break;
default:
strcat(val, tmp);
}
}
if( state == 4 )
{
if( strlen(key) > 0 && strlen(val) > 0 )
{
key_id = sfh_hash(key, strlen(key));
val_id = sfh_hash(val, strlen(val));
if( key_id != val_id )
{
n_entries++;
array = realloc(array, n_entries * sizeof(lmo_entry_t));
entry = (lmo_entry_t *)array + n_entries - 1;
if (!array)
die("Out of memory");
entry->key_id = key_id;
entry->val_id = val_id;
entry->offset = offset;
entry->length = strlen(val);
length = strlen(val) + ((4 - (strlen(val) % 4)) % 4);
print(val, length, 1, out);
offset += length;
}
}
state = 0;
memset(key, 0, sizeof(key));
memset(val, 0, sizeof(val));
}
memset(line, 0, sizeof(line));
}
print_index(array, n_entries, out);
if( offset > 0 )
{
print_uint32(offset, out);
fsync(fileno(out));
fclose(out);
}
else
{
fclose(out);
unlink(argv[2]);
}
fclose(in);
return(0);
}