if unit or not utype then
return unit
end
local combo = collection
if ucode:find('+', 1, true) then
for item in (ucode .. '+'):gmatch('%s*(.-)%s*%+') do
if item ~= '' then
combo:add(item)
end
end
elseif ucode:find('%s') then
for item in ucode:gmatch('%S+') do
combo:add(item)
end
end
if combo.n > 1 then
local result = setmetatable({ utype = utype }, {
__index = function (self, key)
error('Bug: invalid use of automatically generated unit')
end })
for _, v in ipairs(combo) do
local component = lookup(units_index, v)
if not component or component.shouldbe or component.combination then
return nil
end
if utype ~= component.utype then
result.utype = component.utype -- set wrong type which caller will detect
break
end
end
return result
end
end  
local overrides = {} -- read from input for unit codes that should not be checked for a duplicate  
local function insert_unique_unit(data, unit, index)
-- After inserting any required built-in data, insert the unit into the
-- data table and (if index not nil) add to index,
-- but not if the unit code is already defined.
local ucode = unit.unitcode
local known = get_unit(ucode)
if known and not overrides[ucode] then
quit('m_dup_code', ucode)
end
for item, t in pairs(specials.ucode) do
unit[item] = t[ucode]
end
if index then
index[ucode] = unit
end
table.insert(data, unit)
end  
local function check_condition(condition)
-- Return true if condition appears to be valid; otherwise return false.
for _, value in ipairs({ 0, 0.1, 1, 1.1, 10, 100, 1000, 1e4, 1e5 }) do
local success, result = pcall(evaluate_condition, value, condition)
if not success then
return false
end
end
return true
end  
local function check_default_expression(default, ucode)
-- Return a numbered table of names present in param default
-- (two names if an expression, or one name (param default) otherwise).
-- Throw an error if a problem occurs.
-- An expression uses pipe-delimited fields with 'v' representing
-- the input value for the conversion.
-- Example (suffix is optional): 'v < 120 ! small ! big ! suffix'
-- returns { 'smallsuffix', 'bigsuffix' }.
if not default:find('!', 1, true) then
return { default }
end
local t = {}
for item in (default .. '!'):gmatch('%s*(.-)%s*!') do
t[#t+1] = item -- split on '!', removing leading/trailing whitespace
end
if not (#t == 3 or #t == 4) then
quit('m_def_fmt', default, ucode)
end
local condition, default1, default2 = t[1], t[2], t[3]
if #t == 4 then
default1 = default1 .. t[4]
default2 = default2 .. t[4]
end
if not check_condition(condition) then
quit('m_def_cond', default, ucode)
end
return { default1, default2 }
end  
local function check_default(default, ucode, utype, unit_table)
-- Check the given name (or expression) of a default output.
-- Normally a unit must not define itself as its default. However,
-- some units are defined merely for use in per units, and they have
-- the same ucode, utype and default.
-- Example: unit cent which cannot be converted to anything other than
-- a cent, but which can work, for example, in cent/km and cent/mi.
-- Throw an error if a problem occurs.
local done = {}
for _, default in ipairs(check_default_expression(default, ucode)) do
if done[default] then
quit('m_def_rpt', default, ucode)
end
if default == ucode and ucode ~= utype then
quit('m_def_same', ucode)
end
local default_table = get_unit(default, utype)
if not default_table then
quit('m_def_undef', default, ucode)
end
if not (utype == unit_table.utype and utype == default_table.utype) then
quit('m_def_type', default, ucode)
end
done[default] = true
end
end  
local function check_all_defaults(cfg, units)
-- Check each default in units and warn if needed.
-- This is done after all input data has been processed.
-- Throw an error if a problem occurs.
local errors = collection
local missing = collection -- unitcodes with missing defaults
for _, unit in ipairs(units) do
if not unit.shouldbe and not unit.combination then
-- This is a standard unit or an alias/per (not shouldbe, combo).
-- An alias may have a default defined, but it is optional.
local default = unit.default
local ucode = unit.unitcode
if empty(default) then
if not unit.target then -- unit should have a default
missing:add(ucode)
end
else
local ok, msg = pcall(check_default, default, ucode, unit.utype, unit)
if not ok then
errors:add(msg)
if errors.n >= cfg.maxerrors then
break
end
end
end
end
end
if errors.n > 0 then
error(errors:join, 0)
end
if missing.n > 0 then
add_warning('m_wrn_nodef')
local limit = cfg.maxerrors
for _, v in ipairs(missing) do
limit = limit - 1
if limit < 0 then
add_warning('m_wrn_more')
break
end
add_warning('m_wrn_ucode', v)
end
end
end  
local function check_all_pers(cfg, units)
-- Check each component of each "per" unit and warn if needed.
-- In addition, add any required extra fields for some types of units.
-- This is done after all input data has been processed.
-- Throw an error if a problem occurs.
local errors = collection
local function errmsg(key, ...)
errors:add(message(key, ...))
end
for _, unit in ipairs(units) do
local per = unit.per
if per then
local ucode = unit.unitcode
if #per ~= 2 then
errmsg('m_per_two', ucode)
else
local types = {}
for i, v in ipairs(per) do
if empty(v) then
errmsg('m_per_empty', ucode)
end
if not text_code.currency[v] then
local t = get_unit(v)
if t then
types[i] = t.utype
else
errmsg('m_per_undef', ucode, v)
end
end
end
if specials.utype[unit.utype] == 'type_fuel_efficiency' then
local expected = { type_volume = 1, type_length = 2 }
local top_type = expected[specials.utype[types[1]]]
local bot_type = expected[specials.utype[types[2]]]
if top_type and bot_type and top_type ~= bot_type then
unit.iscomplex = true
if top_type == 1 then
unit.invert = 1
else
unit.invert = -1
end
else
errmsg('m_per_fuel', ucode)
end
end
end
end
if errors.n >= cfg.maxerrors then
break
end
end
if errors.n > 0 then
error(errors:join, 0)
end
end  
local function update_units(units, composites, varnames)
-- Update some unit definitions with extra data defined in other sections.
-- This is done after all input data has been processed.
for _, unit in ipairs(units) do
local comp = composites[unit.unitcode]
if comp then
unit.subdivs = '{ ' .. table.concat(comp.subdivs, ', ') .. ' }'
end
local vn = varnames[unit.unitcode]
if vn then
unit.varname = vn
end
end
end  
local function make_override(cfg, data)
-- Return a function which, when called, stores a unit code that is not to be
-- checked for a duplicate. The table is stored in data (also a table).
return function (utype, fields)
local ucode = fields[1]
if empty(ucode) then
quit('m_ovr_miss')
end
if data[ucode] then
quit('m_ovr_dup', ucode)
end
data[ucode] = true
end
end  
local function make_default(cfg, data)
-- Return a function which, when called, stores a table that defines a
-- default output unit. The table is stored in data (also a table).
local defaults_index = {} -- to detect attempts to define a default twice
return function (utype, fields)
-- Store a table defining a unit.
-- This is for a unit such as 'kg' that has a default output unit
-- different from what is defined for the base unit ('g').
-- Throw an error if a problem occurs.
local ucode = fields[1]
local default = fields[2]
if empty(ucode) then
quit('m_dfs_code')
end
if empty(default) then
quit('m_dfs_none', ucode)
end
if #fields ~= 2 then
quit('m_dfs_two', ucode)
end
local unit_table = get_unit(ucode)
if not unit_table then
quit('m_dfs_undef', ucode)
end
local symbol = unit_table.defkey or unit_table.symbol
if empty(symbol) then
quit('m_dfs_sym', ucode)
end
check_default(default, ucode, utype, unit_table)
if defaults_index[ucode] then
quit('m_dfs_dup', ucode)
end
defaults_index[ucode] = default
table.insert(data, { symbol = symbol, default = default })
end
end  
local function clean_link(link, name)
-- Return link, customary where:
-- link = given link after removing any '...' wiki formatting
-- and removing any leading '+' or '*' or '@';