<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh">
	<id>https://zhdeletionpedia.toolforge.org/w/index.php?action=history&amp;feed=atom&amp;title=Module%3ACitation%2FCS1%2FLinks</id>
	<title>Module:Citation/CS1/Links - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://zhdeletionpedia.toolforge.org/w/index.php?action=history&amp;feed=atom&amp;title=Module%3ACitation%2FCS1%2FLinks"/>
	<link rel="alternate" type="text/html" href="https://zhdeletionpedia.toolforge.org/w/index.php?title=Module:Citation/CS1/Links&amp;action=history"/>
	<updated>2026-09-21T20:48:54Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.39.3</generator>
	<entry>
		<id>https://zhdeletionpedia.toolforge.org/w/index.php?title=Module:Citation/CS1/Links&amp;diff=7188&amp;oldid=prev</id>
		<title>Shizhao：​已从:w:Module:Citation/CS1/Links导入1个版本</title>
		<link rel="alternate" type="text/html" href="https://zhdeletionpedia.toolforge.org/w/index.php?title=Module:Citation/CS1/Links&amp;diff=7188&amp;oldid=prev"/>
		<updated>2023-04-06T14:41:33Z</updated>

		<summary type="html">&lt;p&gt;已从&lt;a href=&quot;https://zh.wikipedia.org/wiki/Module:Citation/CS1/Links&quot; class=&quot;extiw&quot; title=&quot;w:Module:Citation/CS1/Links&quot;&gt;w:Module:Citation/CS1/Links&lt;/a&gt;导入1个版本&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2023年4月6日 (四) 14:41的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;zh&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;（没有差异）&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Shizhao</name></author>
	</entry>
	<entry>
		<id>https://zhdeletionpedia.toolforge.org/w/index.php?title=Module:Citation/CS1/Links&amp;diff=7187&amp;oldid=prev</id>
		<title>w&gt;Antigng：​已保护“Module:Citation/CS1/Links”：​高风险模块（[编辑=仅允许管理员]（无限期）[移动=仅允许管理员]（无限期））</title>
		<link rel="alternate" type="text/html" href="https://zhdeletionpedia.toolforge.org/w/index.php?title=Module:Citation/CS1/Links&amp;diff=7187&amp;oldid=prev"/>
		<updated>2022-04-26T16:36:50Z</updated>

		<summary type="html">&lt;p&gt;已保护“&lt;a href=&quot;/Module:Citation/CS1/Links&quot; title=&quot;Module:Citation/CS1/Links&quot;&gt;Module:Citation/CS1/Links&lt;/a&gt;”：​&lt;a href=&quot;/w/index.php?title=WP:HRT&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;WP:HRT（页面不存在）&quot;&gt;高风险模块&lt;/a&gt;（[编辑=仅允许管理员]（无限期）[移动=仅允许管理员]（无限期））&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;--[[&lt;br /&gt;
&lt;br /&gt;
本模块用于处理维基内链和外链。目前导出四个函数：&lt;br /&gt;
&lt;br /&gt;
check_for_external_link()用于批量检查参数中可能存在的外链。&lt;br /&gt;
&lt;br /&gt;
make_external_link()依据输入的url参数和&amp;quot;显示&amp;quot;参数输出维基外链，&lt;br /&gt;
并对其中url参数的格式进行检查。若查出url格式不正确，&lt;br /&gt;
在设定&amp;quot;源&amp;quot;参数的情况下，会根据该参数产生&amp;quot;引文格式1错误&amp;quot;信息，&lt;br /&gt;
附于生成的外链后方；如&amp;quot;源&amp;quot;参数未设定，则会抛出内部错误终止程序。&lt;br /&gt;
&lt;br /&gt;
make_internal_link()依据输入的&amp;quot;目标页面&amp;quot;参数和&amp;quot;显示&amp;quot;参数输出维基内链，&lt;br /&gt;
并对其中&amp;quot;目标页面&amp;quot;参数的格式稍加检查。&lt;br /&gt;
若查出&amp;quot;目标页面&amp;quot;格式不正确(例如：含有页面标题中不允许出现的字符)，&lt;br /&gt;
在设定&amp;quot;源&amp;quot;参数的情况下，会根据该参数产生&amp;quot;引文格式1错误&amp;quot;信息，&lt;br /&gt;
该条信息被其它模块处理后会显示于引文的尾部；&lt;br /&gt;
如&amp;quot;源&amp;quot;参数未设定，则会抛出内部错误终止程序。&lt;br /&gt;
&lt;br /&gt;
以上两个函数既可用于处理模板参数，也可用于转换配置模块中的有关参数。&lt;br /&gt;
&lt;br /&gt;
但请注意，用于前者时必须指定&amp;quot;源&amp;quot;参数（即被处理的参数名称）并保证其值有效，&lt;br /&gt;
用于后者时必须确保配置文件模块编写正确。否则将导致Lua错误！&lt;br /&gt;
&lt;br /&gt;
remove_wiki_link()用于移除维基内链。&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; F O R W A R D   D E C L A R A T I O N S &amp;gt;--------------------------------------&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local is_set;&lt;br /&gt;
local append_error, set_error, throw_error;&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; I S _ S C H E M E &amp;gt;------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
does this thing that purports to be a uri scheme seem to be a valid scheme?  The scheme is checked to see if it&lt;br /&gt;
is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says:&lt;br /&gt;
	Scheme names consist of a sequence of characters beginning with a&lt;br /&gt;
   letter and followed by any combination of letters, digits, plus&lt;br /&gt;
   (&amp;quot;+&amp;quot;), period (&amp;quot;.&amp;quot;), or hyphen (&amp;quot;-&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
returns true if it does, else false&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function is_scheme (scheme)&lt;br /&gt;
	return scheme and scheme:match ('^%a[%a%d%+%.%-]*:');						-- true if scheme is set and matches the pattern&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[=[-------------------------&amp;lt; I S _ D O M A I N _ N A M E &amp;gt;--------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Does this thing that purports to be a domain name seem to be a valid domain name?&lt;br /&gt;
&lt;br /&gt;
Syntax defined here: http://tools.ietf.org/html/rfc1034#section-3.5&lt;br /&gt;
BNF defined here: https://tools.ietf.org/html/rfc4234&lt;br /&gt;
Single character names are generally reserved; see https://tools.ietf.org/html/draft-ietf-dnsind-iana-dns-01#page-15;&lt;br /&gt;
	see also [[Single-letter second-level domain]]&lt;br /&gt;
list of tlds: https://www.iana.org/domains/root/db&lt;br /&gt;
&lt;br /&gt;
rfc952 (modified by rfc 1123) requires the first and last character of a hostname to be a letter or a digit.  Between&lt;br /&gt;
the first and last characters the name may use letters, digits, and the hyphen.&lt;br /&gt;
&lt;br /&gt;
Also allowed are IPv4 addresses. IPv6 not supported&lt;br /&gt;
&lt;br /&gt;
domain is expected to be stripped of any path so that the last character in the last character of the tld.  tld&lt;br /&gt;
is two or more alpha characters.  Any preceding '//' (from splitting a url with a scheme) will be stripped&lt;br /&gt;
here.  Perhaps not necessary but retained incase it is necessary for IPv4 dot decimal.&lt;br /&gt;
&lt;br /&gt;
There are several tests:&lt;br /&gt;
	the first character of the whole domain name including subdomains must be a letter or a digit&lt;br /&gt;
	single-letter/digit second-level domains in the .org TLD&lt;br /&gt;
	q, x, and z SL domains in the .com TLD&lt;br /&gt;
	i and q SL domains in the .net TLD&lt;br /&gt;
	single-letter SL domains in the ccTLDs (where the ccTLD is two letters)&lt;br /&gt;
	two-character SL domains in gTLDs (where the gTLD is two or more letters)&lt;br /&gt;
	three-plus-character SL domains in gTLDs (where the gTLD is two or more letters)&lt;br /&gt;
	IPv4 dot-decimal address format; TLD not allowed&lt;br /&gt;
&lt;br /&gt;
returns true if domain appears to be a proper name and tld or IPv4 address, else false&lt;br /&gt;
&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
local function is_domain_name (domain)&lt;br /&gt;
	if not domain then&lt;br /&gt;
		return false;															-- if not set, abandon&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	domain = domain:gsub ('^//', '');											-- strip '//' from domain name if present; done here so we only have to do it once&lt;br /&gt;
	&lt;br /&gt;
	if not domain:match ('^[%a%d]') then										-- first character must be letter or digit&lt;br /&gt;
		return false;&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if domain:match ('%f[%a%d][%a%d]%.org$') then								-- one character .org hostname&lt;br /&gt;
		return true;&lt;br /&gt;
	elseif domain:match ('%f[%a][qxz]%.com$') then								-- assigned one character .com hostname (x.com times out 2015-12-10)&lt;br /&gt;
		return true;&lt;br /&gt;
	elseif domain:match ('%f[%a][iq]%.net$') then								-- assigned one character .net hostname (q.net registered but not active 2015-12-10)&lt;br /&gt;
		return true;&lt;br /&gt;
	elseif domain:match ('%f[%a%d][%a%d][%a%d%-]+[%a%d]%.xn%-%-[%a%d]+$') then	-- internationalized domain name with ACE prefix&lt;br /&gt;
		return true;&lt;br /&gt;
	elseif domain:match ('%f[%a%d][%a%d]%.cash$') then							-- one character/digit .cash hostname&lt;br /&gt;
		return true;&lt;br /&gt;
	elseif domain:match ('%f[%a%d][%a%d]%.%a%a$') then							-- one character hostname and cctld (2 chars)&lt;br /&gt;
		return true;&lt;br /&gt;
	elseif domain:match ('%f[%a%d][%a%d][%a%d]%.%a%a+$') then					-- two character hostname and tld&lt;br /&gt;
		return true;&lt;br /&gt;
	elseif domain:match ('%f[%a%d][%a%d][%a%d%-]+[%a%d]%.%a%a+$') then			-- three or more character hostname.hostname or hostname.tld&lt;br /&gt;
		return true;&lt;br /&gt;
	elseif domain:match ('^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?') then		-- IPv4 address&lt;br /&gt;
		return true;&lt;br /&gt;
	else&lt;br /&gt;
		return false;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; I S _ U R L &amp;gt;------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
returns true if the scheme and domain parts of a url appear to be a valid url; else false.&lt;br /&gt;
&lt;br /&gt;
This function is the last step in the validation process.  This function is separate because there are cases that&lt;br /&gt;
are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external&lt;br /&gt;
wikilinks.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function is_url (scheme, domain)&lt;br /&gt;
	if is_set (scheme) then														-- if scheme is set check it and domain&lt;br /&gt;
		return is_scheme (scheme) and is_domain_name (domain);&lt;br /&gt;
	else&lt;br /&gt;
		return is_domain_name (domain);											-- scheme not set when url is protocol relative&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S P L I T _ U R L &amp;gt;------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Split a url into a scheme, authority indicator, and domain.&lt;br /&gt;
If protocol relative url, return nil scheme and domain else return nil for both scheme and domain.&lt;br /&gt;
&lt;br /&gt;
When not protocol relative, get scheme, authority indicator, and domain.  If there is an authority indicator (one&lt;br /&gt;
or more '/' characters following the scheme's colon), make sure that there are only 2.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function split_url (url_str)&lt;br /&gt;
	local scheme, authority, domain;&lt;br /&gt;
	&lt;br /&gt;
	url_str = url_str:gsub ('([%a%d])%.?[/%?#].*$', '%1');						-- strip FQDN terminator and path(/), query(?), fragment (#) (the capture prevents false replacement of '//')&lt;br /&gt;
&lt;br /&gt;
	if url_str:match ('^//%S*') then											-- if there is what appears to be a protocol relative url&lt;br /&gt;
		domain = url_str:match ('^//(%S*)')&lt;br /&gt;
	elseif url_str:match ('%S-:/*%S+') then										-- if there is what appears to be a scheme, optional authority indicator, and domain name&lt;br /&gt;
		scheme, authority, domain = url_str:match ('(%S-:)(/*)(%S+)');			-- extract the scheme, authority indicator, and domain portions&lt;br /&gt;
		authority = authority:gsub ('//', '', 1);								-- replace place 1 pair of '/' with nothing;&lt;br /&gt;
		if is_set(authority) then												-- if anything left (1 or 3+ '/' where authority should be) then&lt;br /&gt;
			return scheme;														-- return scheme only making domain nil which will cause an error message&lt;br /&gt;
		end&lt;br /&gt;
		domain = domain:gsub ('(%a):%d+', '%1');								-- strip port number if present&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return scheme, domain;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; L I N K _ P A R A M _ O K &amp;gt;---------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
checks the content of |title-link=, |series-link=, |author-link= etc for properly formatted content: no wikilinks, no urls&lt;br /&gt;
&lt;br /&gt;
Link parameters are to hold the title of a wikipedia article so none of the WP:TITLESPECIALCHARACTERS are allowed:&lt;br /&gt;
	# &amp;lt; &amp;gt; [ ] | { } _&lt;br /&gt;
except the underscore which is used as a space in wiki urls and # which is used for section links&lt;br /&gt;
&lt;br /&gt;
returns false when the value contains any of these characters.&lt;br /&gt;
&lt;br /&gt;
When there are no illegal characters, this function returns TRUE if value DOES NOT appear to be a valid url (the&lt;br /&gt;
|&amp;lt;param&amp;gt;-link= parameter is ok); else false when value appears to be a valid url (the |&amp;lt;param&amp;gt;-link= parameter is NOT ok).&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function link_param_ok (value)&lt;br /&gt;
	local scheme, domain;&lt;br /&gt;
	if value:find ('[&amp;lt;&amp;gt;%[%]|{}]') then											-- if any prohibited characters&lt;br /&gt;
		return false;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	scheme, domain = split_url (value);											-- get scheme or nil and domain or nil from url; &lt;br /&gt;
	return not is_url (scheme, domain);											-- return true if value DOES NOT appear to be a valid url&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[=[-------------------------&amp;lt; M A K E _ I N T E R N A L _ L I N K &amp;gt;------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Format a wikilink with error checking; when both link and display text is provided, returns a wikilink in the form [[L|D]]; if only&lt;br /&gt;
link is provided (or link and display are the same), returns a wikilink in the form [[L]].&lt;br /&gt;
&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
local function make_internal_link (link, display, source)&lt;br /&gt;
	if not link_param_ok (link) then&lt;br /&gt;
		if is_set (source) then&lt;br /&gt;
			append_error ('bad_paramlink', {source});&lt;br /&gt;
		else&lt;br /&gt;
			throw_error('bad_link_no_origin');&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if is_set (display) and link ~= display then			&lt;br /&gt;
		return table.concat ({'[[', link, '|', display, ']]'});			&lt;br /&gt;
	else&lt;br /&gt;
		return table.concat ({'[[', link, ']]'});&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[=[-------------------------&amp;lt; R E M O V E _ W I K I _ L I N K &amp;gt;----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Gets the display text from a wikilink like [[A|B]] or [[B]] gives B&lt;br /&gt;
&lt;br /&gt;
The str:gsub() returns either A|B froma [[A|B]] or B from [[B]] or B from B (no wikilink markup).&lt;br /&gt;
&lt;br /&gt;
In l(), l:gsub() removes the link and pipe (if they exist); the second :gsub() trims whitespace from the label&lt;br /&gt;
if str was wrapped in wikilink markup.  Presumably, this is because without wikimarkup in str, there is no match&lt;br /&gt;
in the initial gsub, the replacement function l() doesn't get called.&lt;br /&gt;
&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
local function remove_wiki_link (str)&lt;br /&gt;
	return (str:gsub (&amp;quot;%[%[([^%[%]]*)%]%]&amp;quot;, function(l)&lt;br /&gt;
		return l:gsub (&amp;quot;^[^|]*|(.*)$&amp;quot;, &amp;quot;%1&amp;quot; ):gsub (&amp;quot;^%s*(.-)%s*$&amp;quot;, &amp;quot;%1&amp;quot;);&lt;br /&gt;
	end));&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[=[-------------------------&amp;lt; I S _ W I K I L I N K &amp;gt;--------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Determines if str is a wikilink, extracts, and returns the wikilink type, link text, and display text parts.&lt;br /&gt;
If str is a complex wikilink ([[L|D]]):&lt;br /&gt;
	returns wl_type 2 and D and L from [[L|D]];&lt;br /&gt;
if str is a simple wikilink ([[D]])&lt;br /&gt;
	returns wl_type 1 and D from [[D]] and L as empty string;&lt;br /&gt;
if not a wikilink:&lt;br /&gt;
	returns wl_type 0, str as D, and L as empty string.&lt;br /&gt;
&lt;br /&gt;
trims leading and trailing whitespace and pipes from L and D ([[L|]] and [[|D]] are accepted by MediaWiki and&lt;br /&gt;
treated like [[D]]; while [[|D|]] is not accepted by MediaWiki, here, we accept it and return D without the pipes).&lt;br /&gt;
&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
local function is_wikilink (str)&lt;br /&gt;
	local D, L&lt;br /&gt;
	local wl_type = 2;															-- assume that str is a complex wikilink [[L|D]]&lt;br /&gt;
&lt;br /&gt;
	if not str:match ('^%[%[[^%]]+%]%]$') then									-- is str some sort of a wikilink (must have some sort of content)&lt;br /&gt;
		return 0, str, '';														-- not a wikilink; return wl_type as 0, str as D, and empty string as L&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	L, D = str:match ('^%[%[([^|]+)|([^%]]+)%]%]$');							-- get L and D from [[L|D]] &lt;br /&gt;
&lt;br /&gt;
	if not is_set (D) then														-- if no separate display&lt;br /&gt;
		D = str:match ('^%[%[([^%]]*)|*%]%]$');									-- get D from [[D]] or [[D|]]&lt;br /&gt;
		wl_type = 1; &lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	D = mw.text.trim (D, '%s|');												-- trim white space and pipe characters &lt;br /&gt;
	return wl_type, D, L or '';&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S A F E _ F O R _ U R L &amp;gt;------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Escape sequences for content that will be used for URL descriptions&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function safe_for_url( str )&lt;br /&gt;
	if str:match( &amp;quot;%[%[.-%]%]&amp;quot; ) ~= nil then &lt;br /&gt;
		append_error( 'wikilink_in_url', {});&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return str:gsub( '[%[%]\n]', {	&lt;br /&gt;
		['['] = '&amp;amp;#91;',&lt;br /&gt;
		[']'] = '&amp;amp;#93;',&lt;br /&gt;
		['\n'] = ' ' } );&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; C H E C K _ U R L &amp;gt;------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Determines whether a URL string appears to be valid.&lt;br /&gt;
&lt;br /&gt;
First we test for space characters.  If any are found, return false.  Then split the url into scheme and domain&lt;br /&gt;
portions, or for protocol relative (//example.com) urls, just the domain.  Use is_url() to validate the two&lt;br /&gt;
portions of the url.  If both are valid, or for protocol relative if domain is valid, return true, else false.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function check_url( url_str )&lt;br /&gt;
	if nil == url_str:match (&amp;quot;^%S+$&amp;quot;) then										-- if there are any spaces in |url=value it can't be a proper url&lt;br /&gt;
		return false;&lt;br /&gt;
	end&lt;br /&gt;
	local scheme, domain;&lt;br /&gt;
&lt;br /&gt;
	scheme, domain = split_url (url_str);										-- get scheme or nil and domain or nil from url; &lt;br /&gt;
	return is_url (scheme, domain);												-- return true if value appears to be a valid url&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; M A K E _ E X T E R N A L _ L I N K &amp;gt;--------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Format an external link with error checking&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function make_external_link( URL, label, source )&lt;br /&gt;
	local error_str = &amp;quot;&amp;quot;;&lt;br /&gt;
	if not is_set( label ) then&lt;br /&gt;
		label = URL;&lt;br /&gt;
		if is_set( source ) then&lt;br /&gt;
			error_str = set_error( 'bare_url_missing_title', source, false, &amp;quot; &amp;quot; );&lt;br /&gt;
		else&lt;br /&gt;
			throw_error( 'bare_url_no_origin' );&lt;br /&gt;
		end			&lt;br /&gt;
	end&lt;br /&gt;
	if not check_url( URL ) then&lt;br /&gt;
		if is_set ( source ) then&lt;br /&gt;
			error_str = set_error( 'bad_url', source, false, &amp;quot; &amp;quot; ) .. error_str;&lt;br /&gt;
		else&lt;br /&gt;
			throw_error( 'bad_url_no_origin' );&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return table.concat({ &amp;quot;[&amp;quot;, URL, &amp;quot; &amp;quot;, safe_for_url( label ), &amp;quot;]&amp;quot;, error_str });&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[=[-------------------------&amp;lt; I S _ P A R A M E T E R _ E X T _ W I K I L I N K &amp;gt;----------------------------&lt;br /&gt;
&lt;br /&gt;
Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first&lt;br /&gt;
non-space characters following the opening bracket appear to be a url.  The test will also find external wikilinks&lt;br /&gt;
that use protocol relative urls. Also finds bare urls.&lt;br /&gt;
&lt;br /&gt;
The frontier pattern prevents a match on interwiki links which are similar to scheme:path urls.  The tests that&lt;br /&gt;
find bracketed urls are required because the parameters that call this test (currently |title=, |chapter=, |work=,&lt;br /&gt;
and |publisher=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]]&lt;br /&gt;
is possible as might be [[en://Hus]].&lt;br /&gt;
&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
local function is_parameter_ext_wikilink (value)&lt;br /&gt;
local scheme, domain;&lt;br /&gt;
&lt;br /&gt;
	value = value:gsub ('([^%s/])/[%a%d].*', '%1');								-- strip path information (the capture prevents false replacement of '//')&lt;br /&gt;
&lt;br /&gt;
	if value:match ('%f[%[]%[%a%S*:%S+.*%]') then								-- if ext wikilink with scheme and domain: [xxxx://yyyyy.zzz]&lt;br /&gt;
		scheme, domain = value:match ('%f[%[]%[(%a%S*:)(%S+).*%]')&lt;br /&gt;
	elseif value:match ('%f[%[]%[//%S*%.%S+.*%]') then							-- if protocol relative ext wikilink: [//yyyyy.zzz]&lt;br /&gt;
		domain = value:match ('%f[%[]%[//(%S*%.%S+).*%]');&lt;br /&gt;
	elseif value:match ('%a%S*:%S+') then										-- if bare url with scheme; may have leading or trailing plain text&lt;br /&gt;
		scheme, domain = value:match ('(%a%S*:)(%S+)');&lt;br /&gt;
	elseif value:match ('//%S*%.%S+') then										-- if protocol relative bare url: //yyyyy.zzz; may have leading or trailing plain text&lt;br /&gt;
		domain = value:match ('//(%S*%.%S+)');									-- what is left should be the domain&lt;br /&gt;
	else&lt;br /&gt;
		return false;															-- didn't find anything that is obviously a url&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return is_url (scheme, domain);												-- return true if value appears to be a valid url&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[-------------------------&amp;lt; C H E C K _ F O R _ U R L &amp;gt;-----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
loop through a list of parameters and their values.  Look at the value and if it has an external link, emit an error message.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function check_for_external_link (parameter_list)&lt;br /&gt;
local error_message = '';&lt;br /&gt;
	for k, v in pairs (parameter_list) do										-- for each parameter in the list&lt;br /&gt;
		if is_parameter_ext_wikilink (v) then									-- look at the value; if there is a url add an error message&lt;br /&gt;
			if is_set(error_message) then										-- once we've added the first portion of the error message ...&lt;br /&gt;
				error_message=error_message .. &amp;quot;, &amp;quot;;							-- ... add a comma space separator&lt;br /&gt;
			end&lt;br /&gt;
			error_message=error_message .. &amp;quot;&amp;amp;#124;&amp;quot; .. k .. &amp;quot;=&amp;quot;;				-- add the failed parameter&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if is_set (error_message) then												-- done looping, if there is an error message, display it&lt;br /&gt;
		append_error( 'param_has_ext_link', {error_message});&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S E T _ S E L E C T E D _ M O D U L E S &amp;gt;--------------------------------------&lt;br /&gt;
&lt;br /&gt;
Import some functions from Module:Citation/CS1/Utilities and Module:Citation/CS1/Error&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function set_selected_modules (utilities_page_ptr, error_page_ptr)&lt;br /&gt;
	is_set = utilities_page_ptr.is_set;&lt;br /&gt;
	&lt;br /&gt;
	append_error = error_page_ptr.append_error;&lt;br /&gt;
	set_error = error_page_ptr.set_error;&lt;br /&gt;
	throw_error = error_page_ptr.throw_error;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; E X P O R T E D   F U N C T I O N S &amp;gt;------------------------------------------&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
return {&lt;br /&gt;
	check_for_external_link = check_for_external_link,							-- exported functions&lt;br /&gt;
	make_external_link = make_external_link,&lt;br /&gt;
	make_internal_link = make_internal_link,&lt;br /&gt;
	remove_wiki_link = remove_wiki_link,&lt;br /&gt;
	&lt;br /&gt;
	set_selected_modules = set_selected_modules&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>w&gt;Antigng</name></author>
	</entry>
</feed>