mod_s2s: Remove warning about hostname mismatch
[prosody.git] / util / template.lua
blobc11037c5cfa750159b8ed90ab0777292e5ca4327
1 -- luacheck: ignore 213/i
2 local stanza_mt = require "util.stanza".stanza_mt;
3 local setmetatable = setmetatable;
4 local pairs = pairs;
5 local ipairs = ipairs;
6 local error = error;
7 local envload = require "util.envload".envload;
8 local debug = debug;
9 local t_remove = table.remove;
10 local parse_xml = require "util.xml".parse;
12 local _ENV = nil;
13 -- luacheck: std none
15 local function trim_xml(stanza)
16 for i=#stanza,1,-1 do
17 local child = stanza[i];
18 if child.name then
19 trim_xml(child);
20 else
21 child = child:gsub("^%s*", ""):gsub("%s*$", "");
22 stanza[i] = child;
23 if child == "" then t_remove(stanza, i); end
24 end
25 end
26 end
28 local function create_string_string(str)
29 str = ("%q"):format(str);
30 str = str:gsub("{([^}]*)}", function(s)
31 return '"..(data["'..s..'"]or"").."';
32 end);
33 return str;
34 end
35 local function create_attr_string(attr, xmlns)
36 local str = '{';
37 for name,value in pairs(attr) do
38 if name ~= "xmlns" or value ~= xmlns then
39 str = str..("[%q]=%s;"):format(name, create_string_string(value));
40 end
41 end
42 return str..'}';
43 end
44 local function create_clone_string(stanza, lookup, xmlns)
45 if not lookup[stanza] then
46 local s = ('setmetatable({name=%q,attr=%s,tags={'):format(stanza.name, create_attr_string(stanza.attr, xmlns));
47 -- add tags
48 for i,tag in ipairs(stanza.tags) do
49 s = s..create_clone_string(tag, lookup, stanza.attr.xmlns)..";";
50 end
51 s = s..'};';
52 -- add children
53 for i,child in ipairs(stanza) do
54 if child.name then
55 s = s..create_clone_string(child, lookup, stanza.attr.xmlns)..";";
56 else
57 s = s..create_string_string(child)..";"
58 end
59 end
60 s = s..'}, stanza_mt)';
61 s = s:gsub('%.%.""', ""):gsub('([=;])""%.%.', "%1"):gsub(';"";', ";"); -- strip empty strings
62 local n = #lookup + 1;
63 lookup[n] = s;
64 lookup[stanza] = "_"..n;
65 end
66 return lookup[stanza];
67 end
68 local function create_cloner(stanza, chunkname)
69 local lookup = {};
70 local name = create_clone_string(stanza, lookup, "");
71 local src = "local setmetatable,stanza_mt=...;return function(data)";
72 for i=1,#lookup do
73 src = src.."local _"..i.."="..lookup[i]..";";
74 end
75 src = src.."return "..name..";end";
76 local f,err = envload(src, chunkname);
77 if not f then error(err); end
78 return f(setmetatable, stanza_mt);
79 end
81 local template_mt = { __tostring = function(t) return t.name end };
82 local function create_template(templates, text)
83 local stanza, err = parse_xml(text);
84 if not stanza then error(err); end
85 trim_xml(stanza);
87 local info = debug.getinfo(3, "Sl");
88 info = info and ("template(%s:%d)"):format(info.short_src:match("[^\\/]*$"), info.currentline) or "template(unknown)";
90 local template = setmetatable({ apply = create_cloner(stanza, info), name = info, text = text }, template_mt);
91 templates[text] = template;
92 return template;
93 end
95 local templates = setmetatable({}, { __mode = 'k', __index = create_template });
96 return function(text)
97 return templates[text];
98 end;