quit('m_var_cnt')
end
local ucode
local names = {}
for i = 1, count do
local v = fields[i]
if empty(v) then
quit('m_var_miss')
end
if i == 1 then -- unitcode
ucode = v
if not get_unit(v) then
quit('m_var_undef', v)
end
else
table.insert(names, v)
end
end
if data[ucode] then
quit('m_var_dup', ucode)
end
data[ucode] = table.concat(names, '!')
end
end  
local function reversed(t)
-- Return a numbered table in reverse order.
local reversed, count = {}, #t
for i = 1, count do
reversed[i] = t[count + 1 - i]
end
return reversed
end  
local function make_inputmultiple(cfg, data)
-- Return a function which, when called, stores a table that defines a
-- single composite (multiple input) unit. The table is stored in data (also a table).
return function (utype, fields)
-- Set or update an entry in the data table to record that a unit
-- accepts subdivisions to make a composite input unit like '|2|ft|6|in'.
-- The target units must be defined first.
-- Throw an error if a problem occurs.
local unitcode -- dummy code required for simplicity, but which is not used in output
local alternate_code -- an alternative unit code can be specified to replace convert input
local fixed_name -- a fixed name can be specified to replace the unit's normal symbol/name
local default_code
local ucodes, scales = {}, {}
for i, v in ipairs(fields) do
-- 1=composite, 2=ucode1, 3=ucode2, 4=default, 5=alternate, 6=name
if i == 1 then
if v == '' then
quit('m_cmp_miss')
end
unitcode = v
elseif 2 <= i and i <= 5 then
if not (i == 5 and v == '') then
local target = get_unit(v, (i == 4) and utype or nil) -- the default may be an auto combination
if not target then
quit('m_cmp_undef', v, unitcode)
end
if target.utype ~= utype then
quit('m_cmp_type', v, unitcode)
end
if i < 4 then
if not target.scale then
quit('m_mul_std', v, unitcode)
end
table.insert(ucodes, v)
table.insert(scales, target.scale)
elseif i == 4 then
default_code = v
else
if scales[#scales] ~= target.scale then
quit('m_cmp_scale', v, unitcode)
end
alternate_code = v
end
end
elseif i == 6 then
if v ~= '' then
fixed_name = v
end
else
quit('m_cmp_many', unitcode)
end
end
if #ucodes ~= 2 then
quit('m_cmp_two', unitcode)
end
if not default_code then
quit('m_cmp_def', unitcode)
end
-- Component units must be specified from most-significant to least-significant,
-- and each ratio of a pair of scales must be very close to an integer.
-- Currently, there will be exactly two scales and one ratio.
local ratios, count = {}, #scales
for i = 1, count do
local scale = tonumber(scales[i])
if scale == nil or scale <= 0 then
quit('m_cmp_inval', unitcode, scales[i])
end
scales[i] = scale
end
for i = 1, count - 1 do
local ratio = scales[i] / scales[i + 1]
local rounded = math.floor(ratio + 0.5)
if rounded < 2 then
quit('m_cmp_order', unitcode)
end
if math.abs(ratio - rounded)/ratio > 1e-6 then
quit('m_cmp_int', unitcode)
end
ratios[i] = rounded
end
local text = { tostring(ratios[1]) }
local function add_text(key, value)
table.insert(text, string.format('%s = %q', key, value))
end
if default_code then
add_text('default', default_code)
end
if alternate_code then
add_text('unit', alternate_code)
end
if fixed_name then
add_text('name', fixed_name)
end
local subdiv = string.format('["%s"] = { %s }', ucodes[2], table.concat(text, ', '))
local main_code = ucodes[1]
local item = data[main_code]
if item then
table.insert(item.subdivs, subdiv)
else
data[main_code] = { subdivs = { subdiv } }
end
end
end  
local function make_outputmultiple(cfg, data)
-- Return a function which, when called, stores a table that defines a
-- single multiple output unit. The table is stored in data (also a table).
return function (utype, fields)
-- Store a table defining a unit.
-- This is for a multiple unit like 'ydftin' (result in yards, feet, inches).
-- The target units must be defined first.
-- Throw an error if a problem occurs.
local unit = { utype = utype }
local ucodes, scales = {}, {}
for i, v in ipairs(fields) do
if i == 1 then -- unitcode
if v == '' then
quit('m_mul_miss')
end
unit.unitcode = v
elseif v == '' then
-- Ignore empty fields.
else
local target = get_unit(v)
if not target then
quit('m_mul_undef', v, unit.unitcode)
end
if target.utype ~= utype then
quit('m_mul_type', v, unit.unitcode)
end
if not target.scale then
quit('m_mul_std', v, unit.unitcode)
end
table.insert(ucodes, v)
table.insert(scales, target.scale)
end
end
if #ucodes < 2 then
quit(#ucodes == 0 and 'm_mul_none' or 'm_mul_one', unit.unitcode)
end
-- Component units must be specified from most-significant to least-significant
-- (so scale values will be in descending order),
-- and each ratio of a pair of scales must be very close to an integer.
-- The componenets and ratios are stored in reverse order (least significant first).
-- This script stores a unit scale as a string (might be an expression like "5/9"),
-- but scales in a multiple are handled as numbers (should never be expressions).
local ratios, count = {}, #scales
for i = 1, count do
local scale = tonumber(scales[i])
if scale == nil or scale <= 0 then
quit('m_mul_scale', unit.unitcode, scales[i])
end
scales[i] = scale
end
for i = 1, count - 1 do
local ratio = scales[i] / scales[i + 1]
local rounded = math.floor(ratio + 0.5)
if rounded < 2 then
quit('m_mul_order', unit.unitcode)
end
if math.abs(ratio - rounded)/ratio > 1e-6 then
quit('m_mul_int', unit.unitcode)
end
ratios[i] = rounded
end
unit.combination = reversed(ucodes)
unit.multiple = reversed(ratios)
insert_unique_unit(data, unit, units_index)
end
end  
-- To make updating the data module easier, this script inserts a preamble
-- and a postamble so the result can be used to replace the whole page.
local data_preamble = [=[
-- Conversion data used by Module:Convert which uses mw.loadData for
-- read-only access to this module so that it is loaded only once per page.
-- See :en:Template:Convert/Transwiki guide if copying to another wiki.
---
-- These data tables follow:
-- all_units all properties for a unit, including default output
-- default_exceptions exceptions for default output ('kg' and 'g' have different defaults)
-- link_exceptions exceptions for links ('kg' and 'g' have different links)
---
-- These tables are generated by a script which reads the wikitext of a page that
-- documents the required properties of each unit; see :en:Module:Convert/doc.
]=]  
local data_postamble = [=[
return {
all_units = all_units,
default_exceptions = default_exceptions,
link_exceptions = link_exceptions,
per_unit_fixups = per_unit_fixups,
}]=]  
local out_unit_prefix =
---
-- Do not change the data in this table because it is created by running --
-- a script that reads the wikitext from a wiki page (see note above). --
---
local all_units = {  
local out_unit_suffix =
}  
local out_default_prefix =
---
-- Do not change the data in this table because it is created by running --
-- a script that reads the wikitext from a wiki page (see note above). --
---
local default_exceptions = {
-- Prefixed units with a default different from that of the base unit.
-- Each key item is a prefixed symbol (unitcode for engineering notation).  
local out_default_suffix =
}  
local out_default_item = [[
["{symbol}"] = "{default}",]]  
local out_link_prefix =
---
-- Do not change the data in this table because it is created by running --
-- a script that reads the wikitext from a wiki page (see note above). --
---
local link_exceptions = {
-- Prefixed units with a linked article different from that of the base unit.
-- Each key item is a prefixed symbol (not unitcode).  
local out_link_suffix =
}  
local out_link_item = [[
["{symbol}"] = "{link}",]]  
local out_perunit_prefix =
---
-- Do not change the data in this table because it is created by running --
-- a script that reads the wikitext from a wiki page (see note above). --
---
local per_unit_fixups = {
-- Automatically created per units of form "x/y" may have their unit type
-- changed, for example, "length/time" is changed to "speed".