else
format = ''; -- empty string for concatenation
end
return format;
end  
--[[---------------------< G E T _ D I S P L A Y _ N A M E S >------------------  
Returns a number that defines the number of names displayed for author and editor
name lists and a Boolean flag to indicate when et al. should be appended to the name list.  
When the value assigned to |display-xxxxors= is a number greater than or equal to zero,
return the number and the previous state of the 'etal' flag (false by default
but may have been set to true if the name list contains some variant of the text 'et al.').  
When the value assigned to |display-xxxxors= is the keyword 'etal', return a number
that is one greater than the number of authors in the list and set the 'etal' flag true.
This will cause the list_people to display all of the names in the name list followed by 'et al.'  
In all other cases, returns nil and the previous state of the 'etal' flag.  
inputs:
max: A['DisplayAuthors'] or A['DisplayEditors'], etc; a number or some flavor of etal
count: #a or #e
list_name: 'authors' or 'editors'
etal: author_etal or editor_etal  
This function sets an error message when |display-xxxxors= value greater than or equal to number of names but
not when <max> comes from global settings. When using global settings, <param> is set to the
keyword 'cs1 config' which is used to supress the normal error. Error is suppressed because it is to be expected
that some citations in an article will have the same or fewer names that the limit specified in .  
local function get_display_names (max, count, list_name, etal, param)
if utilities.is_set (max) then
if 'etal' == max:lower:gsub("[ '%.]", '') then -- the :gsub portion makes 'etal' from a variety of 'et al.' spellings and stylings
max = count + 1; -- number of authors + 1 so display all author name plus et al.
etal = true; -- overrides value set by extract_names
elseif max:match ('^%d+$') then -- if is a string of numbers
max = tonumber (max); -- make it a number
if (max >= count) and ('cs1 config' ~= param) then -- error when local |display-xxxxors= value greater than or equal to number of names; not an error when using global setting
utilities.set_message ('err_disp_name', {param, max}); -- add error message
max = nil;
end
else -- not a valid keyword or number
utilities.set_message ('err_disp_name', {param, max}); -- add error message
max = nil; -- unset; as if |display-xxxxors= had not been set
end
end  
return max, etal;
end  
--[[----------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >---------------  
Adds error if |page=, |pages=, |quote-page=, |quote-pages= has what appears to be
some form of p. or pp. abbreviation in the first characters of the parameter content.  
check page for extraneous p, p., pp, pp., pg, pg. at start of parameter value:
good pattern: '^P[^%.P%l]' matches when page begins PX or P# but not Px
where x and X are letters and # is a digit
bad pattern: '^[Pp][PpGg]' matches when page begins pp, pP, Pp, PP, pg, pG, Pg, PG  
local function extra_text_in_page_check (val, name)
if not val:match (cfg.vol_iss_pg_patterns.good_ppattern) then
for _, pattern in ipairs (cfg.vol_iss_pg_patterns.bad_ppatterns) do -- spin through the selected sequence table of patterns
if val:match (pattern) then -- when a match, error so
utilities.set_message ('err_extra_text_pages', name); -- add error message
return; -- and done
end
end
end
end  
--volume= or |issue= has what appears to be some form of redundant 'type' indicator. Applies to
both; this function looks for issue text in both |issue= and |volume= and looks for volume-like text in |voluem=
and |issue=.  
For |volume=:
'V.', or 'Vol.' (with or without the dot) abbreviations or 'Volume' in the first characters of the parameter
content (all case insensitive). 'V' and 'v' (without the dot) are presumed to be roman numerals so
are allowed.  
For |issue=:
'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the
parameter content (all case insensitive); numero styling: 'n°' with degree sign U+00B0, and № precomposed
numero sign U+2116.  
Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or
whitespace character) – param values are trimmed of whitespace by MediaWiki before delivered to the module.  
<val> is |volume= or |issue= parameter value
<name> is |volume= or |issue= parameter name for error message
<selector> is 'v' for |volume=, 'i' for |issue=  
sets error message on failure; returns nothing  
local function extra_text_in_vol_iss_check (val, name, selector)
if not utilities.is_set (val) then
return;
end  
local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue';
val = val:lower; -- force parameter value to lower case  
for _, pattern in ipairs (cfg.vol_iss_pg_patterns.vi_patterns_t) do -- spin through the sequence table of patterns
if val:match (pattern) then -- when a match, error so
utilities.set_message (handler, name); -- add error message
return; -- and done
end
end
end  
--[=[-------------------------< G E T _ V _ N A M E _ T A B L E >----------------------------------------------  
split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled
parentheses to also have commas; in the old version of the code, the doubled parentheses were included in the
rendered citation and in the metadata. Individual author names may be wikilinked  
|vauthors=Jones AB, White EB, ((Black, Brown, and Co.))  
]=]  
local function get_v_name_table (vparam, output_table, output_link_table)
local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas
local wl_type, label, link; -- wl_type not used here; just a placeholder  
local i = 1;  
while name_table[i] do
if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses
local name = name_table[i];
i = i + 1; -- bump indexer to next segment
while name_table[i] do
name = name .. ', ' .. name_table[i]; -- concatenate with previous segments
if name_table[i]:match ('^.*%)%)$') then -- if this table member has the closing doubled parentheses
break; -- and done reassembling so
end
i = i + 1; -- bump indexer
end
table.insert (output_table, name); -- and add corporate name to the output table
table.insert (output_link_table, ''); -- no wikilink
else
wl_type, label, link = utilities.is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, D; 2, D
table.insert (output_table, label); -- add this name
if 1 == wl_type then
table.insert (output_link_table, label); -- simple wikilink D
else
table.insert (output_link_table, link); -- no wikilink or D; add this link if there is one, else empty string
end
end
i = i + 1;
end
return output_table;
end  
--vauthors= or |veditors= and finds matching |xxxxor-maskn= and
|xxxxor-linkn= in args. It then returns a table of assembled names just as extract_names does.  
Author / editor names in |vauthors= or |veditors= must be in Vancouver system style. Corporate or institutional names
may sometimes be required and because such names will often fail the is_good_vanc_name and other format compliance
tests, are wrapped in doubled parentheses ((corporate name)) to suppress the format tests.  
Supports generational suffixes Jr, 2nd, 3rd, 4th–6th.  
This function sets the Vancouver error when a required comma is missing and when there is a space between an author's initials.  
local function parse_vauthors_veditors (args, vparam, list_name)
local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn=
local v_name_table = {};
local v_link_table = {}; -- when name is wikilinked, targets go in this table
local etal = false; -- return value set to true when we find some form of et al. vauthors parameter
local last, first, link, mask, suffix;
local corporate = false;