మాడ్యూల్:Citation/CS1/Identifiers, మాడ్యూల్:Citation/CS1/Identifiers/sandbox: పేజీల మధ్య తేడా
(పేజీల మధ్య తేడా)
Content deleted Content added
యర్రా రామారావు (చర్చ | రచనలు) చి en:Module:Citation/CS1/Identifiers నుండి కూర్పును దిగుమతి చేసారు: వ్యాసాలకు అవసరమైనందున |
Arjunaraoc (చర్చ | రచనలు) చి en:Module:Citation/CS1/Identifiers/sandbox నుండి కూర్పును దిగుమతి చేసాం: తెవికీలోకి |
||
పంక్తి 1: | పంక్తి 1: | ||
--[[ |
|||
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- |
|||
History of changes since last sync: 2019-09-03 |
|||
]] |
|||
local has_accept_as_written, is_set, in_array, set_message, select_one, -- functions in Module:Citation/CS1/Utilities |
|||
substitute, make_wikilink; |
|||
local z; -- table of tables defined in Module:Citation/CS1/Utilities |
|||
local cfg; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration |
|||
--[[--------------------------< P A G E S C O P E V A R I A B L E S >-------------------------------------- |
|||
declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here |
|||
]] |
]] |
||
local auto_link_urls = {}; -- holds identifier URLs for those identifiers that can auto-link |title= |
|||
--============================<< H E L P E R F U N C T I O N S >>============================================ |
|||
--[[--------------------------< W I K I D A T A _ A R T I C L E _ N A M E _ G E T >---------------------------- |
|||
as an aid to internationalizing identifier-label wikilinks, gets identifier article names from Wikidata. |
|||
returns :<lang code>:<article title> when <q> has an <article title> for <lang code>; nil else |
|||
for identifiers that do not have q, returns nil |
|||
for wikis that do not have mw.wikibase installed, returns nil |
|||
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- |
|||
]] |
]] |
||
local is_set, in_array, set_error, select_one, add_maint_cat, substitute, make_wikilink; -- functions in Module:Citation/CS1/Utilities |
|||
local function wikidata_article_name_get (q) |
|||
if not is_set (q) or (q and not mw.wikibase) then -- when no q number or when a q number but mw.wikibase not installed on this wiki |
|||
return nil; -- abandon |
|||
end |
|||
local z; -- table of tables defined in Module:Citation/CS1/Utilities |
|||
local wd_article; |
|||
local this_wiki_code = cfg.this_wiki_code; -- Wikipedia subdomain; 'en' for en.wikipedia.org |
|||
local cfg; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration |
|||
wd_article = mw.wikibase.getSitelink (q, this_wiki_code .. 'wiki'); -- fetch article title from WD; nil when no title available at this wiki |
|||
if wd_article then |
|||
wd_article = table.concat ({':', this_wiki_code, ':', wd_article}); -- interwiki-style link without brackets if taken from WD; leading colon required |
|||
end |
|||
return wd_article; -- article title from WD; nil else |
|||
end |
|||
--[[--------------------------< L I N K _ L A B E L _ M A K E >------------------------------------------------ |
|||
common function to create identifier link label from handler table or from Wikidata |
|||
returns the first available of |
|||
1. redirect from local wiki's handler table (if enabled) |
|||
2. Wikidata (if there is a Wikidata entry for this identifier in the local wiki's language) |
|||
3. label specified in the local wiki's handler table |
|||
]] |
|||
local function link_label_make (handler) |
|||
local wd_article; |
|||
if not (cfg.use_identifier_redirects and is_set (handler.redirect)) then -- redirect has priority so if enabled and available don't fetch from Wikidata because expensive |
|||
wd_article = wikidata_article_name_get (handler.q); -- if Wikidata has an article title for this wiki, get it; |
|||
end |
|||
return (cfg.use_identifier_redirects and is_set (handler.redirect) and handler.redirect) or wd_article or handler.link; |
|||
end |
|||
--============================<< H E L P E R F U N C T I O N S >>============================================ |
|||
--[[--------------------------< E X T E R N A L _ L I N K _ I D >---------------------------------------------- |
--[[--------------------------< E X T E R N A L _ L I N K _ I D >---------------------------------------------- |
||
Formats a wiki |
Formats a wiki style external link |
||
]] |
]] |
||
local function external_link_id |
local function external_link_id(options) |
||
local url_string = options.id; |
local url_string = options.id; |
||
local ext_link; |
local ext_link; |
||
local |
local this_wiki_code; -- wikipedia subdomain; 'en' for en.wikipedia.org |
||
local wd_article; -- article title from |
local wd_article; -- article title from wikidata |
||
if options.encode == true or options.encode == nil then |
if options.encode == true or options.encode == nil then |
||
url_string = mw.uri.encode |
url_string = mw.uri.encode( url_string ); |
||
end |
end |
||
ext_link = mw.ustring.format ('[%s%s%s %s]', options.prefix, url_string, options.suffix or "", mw.text.nowiki(options.id)); |
|||
if options.auto_link and is_set (options.access) then |
|||
if is_set(options.access) then |
|||
auto_link_urls[options.auto_link] = table.concat ({options.prefix, url_string, options.suffix}); |
|||
ext_link = substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[options.access].class, cfg.presentation[options.access].title, ext_link}); -- add the free-to-read / paywall lock |
|||
end |
end |
||
this_wiki_code = mw.language.getContentLanguage():getCode(); -- get this wikipedia's language code (subdomain) |
|||
ext_link = mw.ustring.format ('[%s%s%s %s]', options.prefix, url_string, options.suffix or "", mw.text.nowiki (options.id)); |
|||
if is_set (options.access) then |
|||
if string.match (mw.site.server, 'wikidata') then |
|||
ext_link = substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[options.access].class, cfg.presentation[options.access].title, ext_link}); -- add the free-to-read / paywall lock |
|||
this_wiki_code = mw.getCurrentFrame():preprocess('{{int:lang}}'); -- on wikidata so use interface language setting instead |
|||
end |
|||
if is_set (options.q) and mw.wikibase then -- wikibase test here avoids script errors in third party wikis that aren't using mw.wikibase extension |
|||
wd_article = mw.wikibase.getEntity (options.q):getSitelink (this_wiki_code .. 'wiki'); -- fetch article title from wd |
|||
if wd_article then |
|||
wd_article = table.concat ({':', this_wiki_code, ':', wd_article}); -- make interwiki link if taken from wd; leading colon required |
|||
end |
|||
end |
end |
||
return table.concat ({ |
return table.concat ({ |
||
make_wikilink ( |
make_wikilink (wd_article or options.link, options.label), -- wikidata link or locally specified |
||
options.separator or ' ', |
options.separator or ' ', |
||
ext_link |
ext_link |
||
పంక్తి 108: | పంక్తి 62: | ||
--[[--------------------------< I N T E R N A L _ L I N K _ I D >---------------------------------------------- |
--[[--------------------------< I N T E R N A L _ L I N K _ I D >---------------------------------------------- |
||
Formats a wiki |
Formats a wiki style internal link |
||
TODO: Does not currently need to support options.access, options.encode, auto-linking and COinS (as in external_link_id), |
|||
but may be needed in the future for :m:Interwiki_map custom-prefixes like :arxiv:, :bibcode:, :DOI:, :hdl:, :ISSN:, |
|||
:JSTOR:, :Openlibrary:, :PMID:, :RFC:. |
|||
]] |
]] |
||
local function internal_link_id |
local function internal_link_id(options) |
||
local id = mw.ustring.gsub (options.id, '%d', cfg.date_names.local_digits); -- translate 'local' digits to Western 0-9 |
local id = mw.ustring.gsub (options.id, '%d', cfg.date_names.local_digits); -- translate 'local' digits to Western 0-9 |
||
return table.concat ( |
return table.concat ( |
||
{ |
{ |
||
make_wikilink |
make_wikilink (options.link, options.label), |
||
options.separator or ' ', |
options.separator or ' ', |
||
make_wikilink ( |
make_wikilink ( |
||
table.concat ( |
table.concat ( |
||
{ |
{ |
||
options.prefix, |
options.prefix, |
||
id, -- translated to |
id, -- translated to western digits |
||
options.suffix or '' |
options.suffix or '' |
||
}), |
}), |
||
substitute (cfg.presentation['bdi'], {'', mw.text.nowiki (options.id)}) -- bdi tags to prevent |
substitute (cfg.presentation['bdi'], {'', mw.text.nowiki (options.id)}) -- bdi tags to prevent Latn script identifiers from being reversed at rtl language wikis |
||
); -- nowiki because MediaWiki still has magic links for ISBN and the like; TODO: is it really required? |
); -- nowiki because MediaWiki still has magic links for ISBN and the like; TODO: is it really required? |
||
}); |
}); |
||
పంక్తి 138: | పంక్తి 88: | ||
--[[--------------------------< I S _ E M B A R G O E D >------------------------------------------------------ |
--[[--------------------------< I S _ E M B A R G O E D >------------------------------------------------------ |
||
Determines if a PMC identifier's online version is embargoed. Compares the date in | |
Determines if a PMC identifier's online version is embargoed. Compares the date in |embargo= against today's date. If embargo date is |
||
in the future, returns the content of |embargo=; otherwise, returns and empty string because the embargo has expired or because |
|||
|embargo= was not set in this cite. |
|||
]] |
]] |
||
పంక్తి 147: | పంక్తి 97: | ||
if is_set (embargo) then |
if is_set (embargo) then |
||
local lang = mw.getContentLanguage(); |
local lang = mw.getContentLanguage(); |
||
local good1, embargo_date, todays_date; |
local good1, embargo_date, good2, todays_date; |
||
good1, embargo_date = pcall |
good1, embargo_date = pcall( lang.formatDate, lang, 'U', embargo ); |
||
todays_date = lang |
good2, todays_date = pcall( lang.formatDate, lang, 'U' ); |
||
if good1 then |
if good1 and good2 then -- if embargo date and today's date are good dates |
||
if tonumber |
if tonumber( embargo_date ) >= tonumber( todays_date ) then -- is embargo date is in the future? |
||
return embargo; -- still embargoed |
return embargo; -- still embargoed |
||
else |
else |
||
add_maint_cat ('embargo') |
|||
set_message ('maint_pmc_embargo'); -- embargo has expired; add main cat |
|||
return ''; -- unset because embargo has expired |
return ''; -- unset because embargo has expired |
||
end |
end |
||
end |
end |
||
end |
end |
||
return ''; -- | |
return ''; -- |embargo= not set return empty string |
||
end |
|||
--[=[-------------------------< I S _ V A L I D _ R X I V _ D A T E >------------------------------------------ |
|||
for biorxiv, returns true if: |
|||
2019-12-11T00:00Z <= biorxiv_date < today + 2 days |
|||
for medrxiv, returns true if: |
|||
2020-01-01T00:00Z <= medrxiv_date < today + 2 days |
|||
The dated form of biorxiv identifier has a start date of 2019-12-11. The Unix timestamp for that date is {{#time:U|2019-12-11}} = 1576022400 |
|||
The medrxiv identifier has a start date of 2020-01-01. The Unix timestamp for that date is {{#time:U|2020-01-01}} = 1577836800 |
|||
<rxiv_date> is the date provided in those |biorxiv= parameter values that are dated and in |medrxiv= parameter values at time 00:00:00 UTC |
|||
<today> is the current date at time 00:00:00 UTC plus 48 hours |
|||
if today's date is 2023-01-01T00:00:00 then |
|||
adding 24 hours gives 2023-01-02T00:00:00 – one second more than today |
|||
adding 24 hours gives 2023-01-03T00:00:00 – one second more than tomorrow |
|||
inputs: |
|||
<y>, <m>, <d> – year, month, day parts of the date from the birxiv or medrxiv identifier |
|||
<select> 'b' for biorxiv, 'm' for medrxiv; defaults to 'b' |
|||
]=] |
|||
local function is_valid_rxiv_date (y, m, d, select) |
|||
if 0 == tonumber (m) and 12 < tonumber (m) then -- <m> must be a number 1–12 |
|||
return false; |
|||
end |
|||
if 0 == tonumber (d) and 31 < tonumber (d) then -- <d> must be a number 1–31; TODO: account for month length and leap yer? |
|||
return false; |
|||
end |
|||
local rxiv_date = table.concat ({y, m, d}, '-'); -- make ymd date string |
|||
local good1, good2; |
|||
local rxiv_ts, tomorrow_ts; -- to hold Unix timestamps representing the dates |
|||
local lang_object = mw.getContentLanguage(); |
|||
good1, rxiv_ts = pcall (lang_object.formatDate, lang_object, 'U', rxiv_date); -- convert rxiv_date value to Unix timestamp |
|||
good2, tomorrow_ts = pcall (lang_object.formatDate, lang_object, 'U', 'today + 2 days' ); -- today midnight + 2 days is one second more than all day tomorrow |
|||
if good1 and good2 then -- lang.formatDate() returns a timestamp in the local script which tonumber() may not understand |
|||
rxiv_ts = tonumber (rxiv_ts) or lang_object:parseFormattedNumber (rxiv_ts); -- convert to numbers for the comparison; |
|||
tomorrow_ts = tonumber (tomorrow_ts) or lang_object:parseFormattedNumber (tomorrow_ts); |
|||
else |
|||
return false; -- one or both failed to convert to Unix timestamp |
|||
end |
|||
local limit_ts = ((select and ('m' == select)) and 1577836800) or 1576022400; -- choose the appropriate limit timesatmp |
|||
return ((limit_ts <= rxiv_ts) and (rxiv_ts < tomorrow_ts)) -- limit_ts <= rxiv_date < tomorrow's date |
|||
end |
end |
||
పంక్తి 217: | పంక్తి 116: | ||
--[[--------------------------< IS _ V A L I D _ I S X N >----------------------------------------------------- |
--[[--------------------------< IS _ V A L I D _ I S X N >----------------------------------------------------- |
||
ISBN-10 and ISSN validator code calculates checksum across all |
ISBN-10 and ISSN validator code calculates checksum across all isbn/issn digits including the check digit. |
||
ISBN-13 is checked in isbn(). |
ISBN-13 is checked in isbn(). |
||
If the number is valid the result will be 0. Before calling this function, |
If the number is valid the result will be 0. Before calling this function, issbn/issn must be checked for length |
||
and stripped of dashes, spaces and other non- |
and stripped of dashes, spaces and other non-isxn characters. |
||
]] |
]] |
||
పంక్తి 227: | పంక్తి 126: | ||
local function is_valid_isxn (isxn_str, len) |
local function is_valid_isxn (isxn_str, len) |
||
local temp = 0; |
local temp = 0; |
||
isxn_str = { isxn_str:byte(1, len) }; |
isxn_str = { isxn_str:byte(1, len) }; -- make a table of byte values '0' → 0x30 .. '9' → 0x39, 'X' → 0x58 |
||
len = len |
len = len+1; -- adjust to be a loop counter |
||
for i, v in ipairs |
for i, v in ipairs( isxn_str ) do -- loop through all of the bytes and calculate the checksum |
||
if v == string.byte |
if v == string.byte( "X" ) then -- if checkdigit is X (compares the byte value of 'X' which is 0x58) |
||
temp = temp + 10 |
temp = temp + 10*( len - i ); -- it represents 10 decimal |
||
else |
else |
||
temp = temp + tonumber |
temp = temp + tonumber( string.char(v) )*(len-i); |
||
end |
end |
||
end |
end |
||
return temp % 11 == 0; |
return temp % 11 == 0; -- returns true if calculation result is zero |
||
end |
end |
||
పంక్తి 242: | పంక్తి 141: | ||
--[[--------------------------< IS _ V A L I D _ I S X N _ 1 3 >----------------------------------------------- |
--[[--------------------------< IS _ V A L I D _ I S X N _ 1 3 >----------------------------------------------- |
||
ISBN-13 and ISMN validator code calculates checksum across all 13 |
ISBN-13 and ISMN validator code calculates checksum across all 13 isbn/ismn digits including the check digit. |
||
If the number is valid, the result will be 0. Before calling this function, |
If the number is valid, the result will be 0. Before calling this function, isbn-13/ismn must be checked for length |
||
and stripped of dashes, spaces and other non- |
and stripped of dashes, spaces and other non-isxn-13 characters. |
||
]] |
]] |
||
పంక్తి 252: | పంక్తి 151: | ||
isxn_str = { isxn_str:byte(1, 13) }; -- make a table of byte values '0' → 0x30 .. '9' → 0x39 |
isxn_str = { isxn_str:byte(1, 13) }; -- make a table of byte values '0' → 0x30 .. '9' → 0x39 |
||
for i, v in ipairs |
for i, v in ipairs( isxn_str ) do |
||
temp = temp + (3 - 2*(i % 2)) * tonumber |
temp = temp + (3 - 2*(i % 2)) * tonumber( string.char(v) ); -- multiply odd index digits by 1, even index digits by 3 and sum; includes check digit |
||
end |
end |
||
return temp % 10 == 0; -- sum modulo 10 is zero when |
return temp % 10 == 0; -- sum modulo 10 is zero when isbn-13/ismn is correct |
||
end |
end |
||
పంక్తి 261: | పంక్తి 160: | ||
--[[--------------------------< N O R M A L I Z E _ L C C N >-------------------------------------------------- |
--[[--------------------------< N O R M A L I Z E _ L C C N >-------------------------------------------------- |
||
lccn normalization (http://www.loc.gov/marc/lccn-namespace.html#normalization) |
|||
1. Remove all blanks. |
1. Remove all blanks. |
||
2. If there is a forward slash (/) in the string, remove it, and remove all characters to the right of the forward slash. |
2. If there is a forward slash (/) in the string, remove it, and remove all characters to the right of the forward slash. |
||
పంక్తి 270: | పంక్తి 169: | ||
2. If the length of the substring is less than 6, left-fill the substring with zeroes until the length is six. |
2. If the length of the substring is less than 6, left-fill the substring with zeroes until the length is six. |
||
Returns a normalized |
Returns a normalized lccn for lccn() to validate. There is no error checking (step 3.b.1) performed in this function. |
||
]] |
]] |
||
local function normalize_lccn (lccn) |
local function normalize_lccn (lccn) |
||
lccn = lccn:gsub ("%s", ""); |
lccn = lccn:gsub ("%s", ""); -- 1. strip whitespace |
||
if nil ~= string.find (lccn, |
if nil ~= string.find (lccn,'/') then |
||
lccn = lccn:match ("(.-)/"); |
lccn = lccn:match ("(.-)/"); -- 2. remove forward slash and all character to the right of it |
||
end |
end |
||
local prefix |
local prefix |
||
local suffix |
local suffix |
||
prefix, suffix = lccn:match ("(.+)%-(.+)"); |
prefix, suffix = lccn:match ("(.+)%-(.+)"); -- 3.a remove hyphen by splitting the string into prefix and suffix |
||
if nil ~= suffix then |
if nil ~= suffix then -- if there was a hyphen |
||
suffix |
suffix=string.rep("0", 6-string.len (suffix)) .. suffix; -- 3.b.2 left fill the suffix with 0s if suffix length less than 6 |
||
lccn |
lccn=prefix..suffix; -- reassemble the lccn |
||
end |
end |
||
return lccn; |
return lccn; |
||
end |
end |
||
--============================<< I D E N T I F I E R F U N C T I O N S >>==================================== |
--============================<< I D E N T I F I E R F U N C T I O N S >>==================================== |
||
పంక్తి 298: | పంక్తి 195: | ||
--[[--------------------------< A R X I V >-------------------------------------------------------------------- |
--[[--------------------------< A R X I V >-------------------------------------------------------------------- |
||
See: |
See: http://arxiv.org/help/arxiv_identifier |
||
format and error check arXiv identifier. There are three valid forms of the identifier: |
format and error check arXiv identifier. There are three valid forms of the identifier: |
||
the first form, valid only between date codes |
the first form, valid only between date codes 9108 and 0703 is: |
||
arXiv:<archive>.<class>/<date code><number><version> |
arXiv:<archive>.<class>/<date code><number><version> |
||
where: |
where: |
||
పంక్తి 323: | పంక్తి 220: | ||
<date code> and <version> are as defined for 0704-1412 |
<date code> and <version> are as defined for 0704-1412 |
||
<number> is a five-digit number |
<number> is a five-digit number |
||
]] |
]] |
||
local function arxiv ( |
local function arxiv (id, class) |
||
local |
local handler = cfg.id_handlers['ARXIV']; |
||
local class = options.Class; -- TODO: lowercase? |
|||
local handler = options.handler; |
|||
local year, month, version; |
local year, month, version; |
||
local |
local err_cat = false; -- assume no error message |
||
local text; -- output text |
local text; -- output text |
||
if id:match("^%a[%a%.%-]+/[90]%d[01]%d%d%d%d$") or id:match("^%a[%a%.%-]+/[90]%d[01]%d%d%d%dv%d+$") then -- test for the |
if id:match("^%a[%a%.%-]+/[90]%d[01]%d%d%d%d$") or id:match("^%a[%a%.%-]+/[90]%d[01]%d%d%d%dv%d+$") then -- test for the 9108-0703 format w/ & w/o version |
||
year, month = id:match("^%a[%a%.%-]+/([90]%d)([01]%d)%d%d%d[v%d]*$"); |
year, month = id:match("^%a[%a%.%-]+/([90]%d)([01]%d)%d%d%d[v%d]*$"); |
||
year = tonumber |
year = tonumber(year); |
||
month = tonumber |
month = tonumber(month); |
||
if ((not (90 < year or 8 > year)) or (1 > month or 12 < month)) or -- if invalid year or invalid month |
if ((not (90 < year or 8 > year)) or (1 > month or 12 < month)) or -- if invalid year or invalid month |
||
((91 == year and 7 > month) or (7 == year and 3 < month)) then -- if years ok, are starting and ending months ok? |
((91 == year and 7 > month) or (7 == year and 3 < month)) then -- if years ok, are starting and ending months ok? |
||
err_cat = true; -- flag for error message |
|||
end |
end |
||
elseif id:match("^%d%d[01]%d%.%d%d%d%d$") or id:match("^%d%d[01]%d%.%d%d%d%dv%d+$") then -- test for the 0704-1412 |
elseif id:match("^%d%d[01]%d%.%d%d%d%d$") or id:match("^%d%d[01]%d%.%d%d%d%dv%d+$") then -- test for the 0704-1412 w/ & w/o version |
||
year, month = id:match("^(%d%d)([01]%d)%.%d%d%d%d[v%d]*$"); |
year, month = id:match("^(%d%d)([01]%d)%.%d%d%d%d[v%d]*$"); |
||
year = tonumber |
year = tonumber(year); |
||
month = tonumber |
month = tonumber(month); |
||
if ((7 > year) or (14 < year) or (1 > month or 12 < month)) or -- is year invalid or is month invalid? (doesn't test for future years) |
if ((7 > year) or (14 < year) or (1 > month or 12 < month)) or -- is year invalid or is month invalid? (doesn't test for future years) |
||
((7 == year) and (4 > month)) then -- when year is 07, is month invalid (before April)? |
((7 == year) and (4 > month)) then --or -- when year is 07, is month invalid (before April)? |
||
err_cat = true; -- flag for error message |
|||
end |
end |
||
elseif id:match("^%d%d[01]%d%.%d%d%d%d%d$") or id:match("^%d%d[01]%d%.%d%d%d%d%dv%d+$") then -- test for the 1501- format |
elseif id:match("^%d%d[01]%d%.%d%d%d%d%d$") or id:match("^%d%d[01]%d%.%d%d%d%d%dv%d+$") then -- test for the 1501- format w/ & w/o version |
||
year, month = id:match("^(%d%d)([01]%d)%.%d%d%d%d%d[v%d]*$"); |
year, month = id:match("^(%d%d)([01]%d)%.%d%d%d%d%d[v%d]*$"); |
||
year = tonumber |
year = tonumber(year); |
||
month = tonumber |
month = tonumber(month); |
||
if ((15 > year) or (1 > month or 12 < month)) then -- is year invalid or is month invalid? (doesn't test for future years) |
if ((15 > year) or (1 > month or 12 < month)) then -- is year invalid or is month invalid? (doesn't test for future years) |
||
err_cat = true; -- flag for error message |
|||
end |
end |
||
else |
else |
||
err_cat = true; -- not a recognized format; flag for error message |
|||
end |
end |
||
err_cat = err_cat and table.concat ({' ', set_error ('bad_arxiv')}) or ''; -- set error message if flag is true |
|||
if err_msg then |
|||
options.coins_list_t['ARXIV'] = nil; -- when error, unset so not included in COinS |
|||
end |
|||
text = external_link_id({link = handler.link, label = handler.label, q = handler.q, |
|||
local err_msg_t = {}; |
|||
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode, access=handler.access}) .. err_cat; |
|||
if err_msg then |
|||
set_message ('err_bad_arxiv'); |
|||
end |
|||
text = external_link_id ({link = handler.link, label = handler.label, q = handler.q, redirect = handler.redirect, |
|||
prefix = handler.prefix, id = id, separator = handler.separator, encode = handler.encode, access = handler.access}); |
|||
if is_set (class) then |
if is_set (class) then |
||
if id:match ('^%d+') then |
if id:match ('^%d+') then |
||
text = table.concat ({text, ' [[ |
text = table.concat ({text, ' [[//arxiv.org/archive/', class, ' ', class, ']]'}); -- external link within square brackets, not wikilink |
||
else |
else |
||
text = table.concat ({text, ' ', set_error ('class_ignored')}); |
|||
set_message ('err_class_ignored'); |
|||
end |
end |
||
end |
end |
||
return text; |
return text; |
||
end |
end |
||
పంక్తి 390: | పంక్తి 277: | ||
--[[--------------------------< B I B C O D E >-------------------------------------------------------------------- |
--[[--------------------------< B I B C O D E >-------------------------------------------------------------------- |
||
Validates (sort of) and formats a bibcode |
Validates (sort of) and formats a bibcode id. |
||
Format for bibcodes is specified here: |
Format for bibcodes is specified here: http://adsabs.harvard.edu/abs_doc/help_pages/data.html#bibcodes |
||
But, this: 2015arXiv151206696F is apparently valid so apparently, the only things that really matter are length, 19 characters |
But, this: 2015arXiv151206696F is apparently valid so apparently, the only things that really matter are length, 19 characters |
||
పంక్తి 406: | పంక్తి 293: | ||
]] |
]] |
||
local function bibcode ( |
local function bibcode (id, access) |
||
local |
local handler = cfg.id_handlers['BIBCODE']; |
||
local access = options.access; |
|||
local handler = options.handler; |
|||
local ignore_invalid = options.accept; |
|||
local err_type; |
local err_type; |
||
local err_msg = ''; |
|||
local year; |
local year; |
||
local text = external_link_id |
local text = external_link_id({link=handler.link, label=handler.label, q = handler.q, |
||
prefix |
prefix=handler.prefix, id=id, separator=handler.separator, encode=handler.encode, |
||
access |
access=access}); |
||
if 19 ~= id:len() then |
if 19 ~= id:len() then |
||
err_type = |
err_type = 'length'; |
||
else |
else |
||
year = id:match ("^(%d%d%d%d)[%a][%w&%.][%w&%.][%w&%.][%w.]+[%a%.]$") |
year = id:match ("^(%d%d%d%d)[%a][%w&%.][%w&%.][%w&%.][%w.]+[%a%.]$") -- |
||
if not year then -- if nil then no pattern match |
if not year then -- if nil then no pattern match |
||
err_type = |
err_type = 'value'; -- so value error |
||
else |
else |
||
local next_year = tonumber |
local next_year = tonumber(os.date ('%Y'))+1; -- get the current year as a number and add one for next year |
||
year = tonumber (year); -- convert year portion of bibcode to a number |
year = tonumber (year); -- convert year portion of bibcode to a number |
||
if (1000 > year) or (year > next_year) then |
if (1000 > year) or (year > next_year) then |
||
err_type = |
err_type = 'year'; -- year out of bounds |
||
end |
end |
||
if id:find('&%.') then |
if id:find('&%.') then |
||
err_type = |
err_type = 'journal'; -- journal abbreviation must not have '&.' (if it does its missing a letter) |
||
end |
|||
if id:match ('.........%.tmp%.') then -- temporary bibcodes when positions 10–14 are '.tmp.' |
|||
set_message ('maint_bibcode'); |
|||
end |
end |
||
end |
end |
||
end |
end |
||
if is_set (err_type) |
if is_set (err_type) then -- if there was an error detected |
||
text = text .. ' ' .. set_error( 'bad_bibcode', {err_type}); |
|||
options.coins_list_t['BIBCODE'] = nil; -- when error, unset so not included in COinS |
|||
end |
end |
||
return text; |
return text; |
||
end |
end |
||
పంక్తి 451: | పంక్తి 329: | ||
--[[--------------------------< B I O R X I V >----------------------------------------------------------------- |
--[[--------------------------< B I O R X I V >----------------------------------------------------------------- |
||
Format bioRxiv |
Format bioRxiv id and do simple error checking. BiorXiv ids are exactly 6 digits. |
||
The bioRxiv id is the number following the last slash in the bioRxiv-issued DOI: |
|||
6 digits. After 2019-12-11, biorXiv IDs retained the six-digit identifier but prefixed that with a yyyy.mm.dd. |
|||
https://doi.org/10.1101/078733 -> 078733 |
|||
date and suffixed with an optional version identifier. |
|||
The bioRxiv ID is the string of characters: |
|||
https://doi.org/10.1101/078733 -> 10.1101/078733 |
|||
or a date followed by a six-digit number followed by an optional version indicator 'v' and one or more digits: |
|||
https://www.biorxiv.org/content/10.1101/2019.12.11.123456v2 -> 10.1101/2019.12.11.123456v2 |
|||
see https://www.biorxiv.org/about-biorxiv |
|||
]] |
]] |
||
local function biorxiv |
local function biorxiv(id) |
||
local |
local handler = cfg.id_handlers['BIORXIV']; |
||
local err_cat = ''; -- presume that bioRxiv id is valid |
|||
local handler = options.handler; |
|||
local err_msg = true; -- flag; assume that there will be an error |
|||
if nil == id:match("^%d%d%d%d%d%d$") then -- if bioRxiv id has anything but six digits |
|||
local patterns = { |
|||
err_cat = ' ' .. set_error( 'bad_biorxiv'); -- set an error message |
|||
'^10%.1101/%d%d%d%d%d%d$', -- simple 6-digit identifier (before 2019-12-11) |
|||
'^10%.1101/(20%d%d)%.(%d%d)%.(%d%d)%.%d%d%d%d%d%dv%d+$', -- y.m.d. date + 6-digit identifier + version (after 2019-12-11) |
|||
'^10%.1101/(20%d%d)%.(%d%d)%.(%d%d)%.%d%d%d%d%d%d$', -- y.m.d. date + 6-digit identifier (after 2019-12-11) |
|||
} |
|||
for _, pattern in ipairs (patterns) do -- spin through the patterns looking for a match |
|||
if id:match (pattern) then |
|||
local y, m, d = id:match (pattern); -- found a match, attempt to get year, month and date from the identifier |
|||
if m then -- m is nil when id is the six-digit form |
|||
if not is_valid_rxiv_date (y, m, d, 'b') then -- validate the encoded date; 'b' for biorxiv limit |
|||
break; -- date fail; break out early so we don't unset the error message |
|||
end |
|||
end |
|||
err_msg = nil; -- we found a match so unset the error message |
|||
break; -- and done |
|||
end |
|||
end -- err_cat remains set here when no match |
|||
if err_msg then |
|||
options.coins_list_t['BIORXIV'] = nil; -- when error, unset so not included in COinS |
|||
set_message ('err_bad_biorxiv'); -- and set the error message |
|||
end |
end |
||
return external_link_id |
return external_link_id({link = handler.link, label = handler.label, q = handler.q, |
||
prefix |
prefix=handler.prefix,id=id,separator=handler.separator, |
||
encode |
encode=handler.encode, access=handler.access}) .. err_cat; |
||
end |
end |
||
పంక్తి 505: | పంక్తి 354: | ||
The description of the structure of this identifier can be found at Help_talk:Citation_Style_1/Archive_26#CiteSeerX_id_structure |
The description of the structure of this identifier can be found at Help_talk:Citation_Style_1/Archive_26#CiteSeerX_id_structure |
||
]] |
]] |
||
local function citeseerx ( |
local function citeseerx (id) |
||
local |
local handler = cfg.id_handlers['CITESEERX']; |
||
local handler = options.handler; |
|||
local matched; |
local matched; |
||
local text = external_link_id |
local text = external_link_id({link=handler.link, label=handler.label, q = handler.q, |
||
prefix |
prefix=handler.prefix, id=id, separator=handler.separator, encode=handler.encode, |
||
access |
access=handler.access}); |
||
matched = id:match ("^10%.1%.1%.[1-9]%d?%d?%d?%.[1-9]%d?%d?%d?$"); |
matched = id:match ("^10%.1%.1%.[1-9]%d?%d?%d?%.[1-9]%d?%d?%d?$"); |
||
if not matched then |
if not matched then |
||
text = text .. ' ' .. set_error( 'bad_citeseerx' ); |
|||
set_message ('err_bad_citeseerx' ); |
|||
options.coins_list_t['CITESEERX'] = nil; -- when error, unset so not included in COinS |
|||
end |
end |
||
return text; |
return text; |
||
end |
end |
||
పంక్తి 535: | పంక్తి 380: | ||
Suffix: character string of any length chosen by the registrant |
Suffix: character string of any length chosen by the registrant |
||
This function checks a DOI name for: prefix/suffix. If the |
This function checks a DOI name for: prefix/suffix. If the doi name contains spaces or endashes, or, if it ends |
||
with a period or a comma, this function will emit a bad_doi error message. |
with a period or a comma, this function will emit a bad_doi error message. |
||
DOI names are case-insensitive and can incorporate any printable Unicode characters so the test for spaces, endash, |
DOI names are case-insensitive and can incorporate any printable Unicode characters so the test for spaces, endash, |
||
and terminal punctuation may not be technically correct but it appears, that in practice these characters are rarely |
and terminal punctuation may not be technically correct but it appears, that in practice these characters are rarely |
||
if ever used in |
if ever used in doi names. |
||
https://www.doi.org/doi_handbook/2_Numbering.html -- 2.2 Syntax of a DOI name |
|||
https://www.doi.org/doi_handbook/2_Numbering.html#2.2.2 -- 2.2.2 DOI prefix |
|||
]] |
]] |
||
local function doi |
local function doi(id, inactive, access) |
||
local |
local cat = "" |
||
local |
local handler = cfg.id_handlers['DOI']; |
||
local access = options.access; |
|||
local ignore_invalid = options.accept; |
|||
local handler = options.handler; |
|||
local err_flag; |
|||
local text; |
local text; |
||
if is_set |
if is_set(inactive) then |
||
local inactive_year = inactive:match("%d%d%d%d"); |
local inactive_year = inactive:match("%d%d%d%d") or ''; -- try to get the year portion from the inactive date |
||
local inactive_month, good; |
local inactive_month, good; |
||
పంక్తి 568: | పంక్తి 406: | ||
end |
end |
||
end |
end |
||
else |
|||
end -- otherwise, |doi-broken-date= has something but it isn't a date |
|||
inactive_year = nil; -- |doi-broken= has something but it isn't a date |
|||
end |
|||
if is_set |
if is_set(inactive_year) and is_set (inactive_month) then |
||
table.insert( z.error_categories, 'Pages with DOIs inactive as of ' .. inactive_year .. ' ' .. inactive_month); -- use inactive month in category name |
|||
set_message ('maint_doi_inactive_dated', {inactive_year, inactive_month, ' '}); |
|||
elseif is_set |
elseif is_set(inactive_year) then |
||
table.insert( z.error_categories, 'Pages with DOIs inactive as of ' .. inactive_year); |
|||
set_message ('maint_doi_inactive_dated', {inactive_year, '', ''}); |
|||
else |
else |
||
table.insert( z.error_categories, 'Pages with inactive DOIs'); -- when inactive doesn't contain a recognizable date |
|||
set_message ('maint_doi_inactive'); |
|||
end |
end |
||
inactive = " (" .. cfg.messages['inactive'] .. ' ' .. inactive .. ')'; |
inactive = " (" .. cfg.messages['inactive'] .. ' ' .. inactive .. ')'; |
||
end |
end |
||
text = external_link_id({link = handler.link, label = handler.label, q = handler.q, |
|||
local registrant = mw.ustring.match (id, '^10%.([^/]+)/[^%s–]-[^%.,]$'); -- registrant set when DOI has the proper basic form |
|||
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode, access=access}) .. (inactive or '') |
|||
if nil == id:match("^10%.[^%s–]-/[^%s–]-[^%.,]$") or -- doi must begin with '10.', must contain a fwd slash, must not contain spaces or endashes, and must not end with period or comma |
|||
local registrant_err_patterns = { -- these patterns are for code ranges that are not supported |
|||
'^ |
id: match ('^10.5555') then -- test doi will never resolve |
||
cat = ' ' .. set_error ('bad_doi'); |
|||
'^[^1-6]%d%d%d%d$', -- 5 digits without subcode (0xxxx, 60000+); accepts: 10000–69999 |
|||
'^[^1-9]%d%d%d%.%d+$', -- 4 digits with subcode (0xxx); accepts: 1000–9999 |
|||
'^[^1-9]%d%d%d$', -- 4 digits without subcode (0xxx); accepts: 1000–9999 |
|||
'^%d%d%d%d%d%d+', -- 6 or more digits |
|||
'^%d%d?%d?$', -- less than 4 digits without subcode (3 digits with subcode is legitimate) |
|||
'^%d%d?%.[%d%.]+', -- 1 or 2 digits with subcode |
|||
'^5555$', -- test registrant will never resolve |
|||
'[^%d%.]', -- any character that isn't a digit or a dot |
|||
} |
|||
if not ignore_invalid then |
|||
if registrant then -- when DOI has proper form |
|||
for i, pattern in ipairs (registrant_err_patterns) do -- spin through error patterns |
|||
if registrant:match (pattern) then -- to validate registrant codes |
|||
err_flag = set_message ('err_bad_doi'); -- when found, mark this DOI as bad |
|||
break; -- and done |
|||
end |
|||
end |
|||
else |
|||
err_flag = set_message ('err_bad_doi'); -- invalid directory or malformed |
|||
end |
|||
else |
|||
set_message ('maint_doi_ignore'); |
|||
end |
end |
||
return text .. cat |
|||
if err_flag then |
|||
options.coins_list_t['DOI'] = nil; -- when error, unset so not included in COinS |
|||
else |
|||
if not access and cfg.known_free_doi_registrants_t[registrant] then -- |doi-access=free not set and <registrant> is known to be free |
|||
set_message ('maint_doi_unflagged_free'); -- set a maint cat |
|||
end |
|||
end |
|||
text = external_link_id ({link = handler.link, label = handler.label, q = handler.q, redirect = handler.redirect, |
|||
prefix = handler.prefix, id = id, separator = handler.separator, encode = handler.encode, access = access, |
|||
auto_link = not (err_flag or is_set (inactive) or ignore_invalid) and 'doi' or nil -- do not auto-link when |doi-broken-date= has a value or when there is a DOI error or (to play it safe, after all, auto-linking is not essential) when invalid DOIs are ignored |
|||
}) .. (inactive or ''); |
|||
return text; |
|||
end |
end |
||
పంక్తి 640: | పంక్తి 446: | ||
terminal punctuation may not be technically correct but it appears, that in practice these characters are rarely |
terminal punctuation may not be technically correct but it appears, that in practice these characters are rarely |
||
if ever used in HDLs. |
if ever used in HDLs. |
||
Query string parameters are named here: https://www.handle.net/proxy_servlet.html. query strings are not displayed |
|||
but since '?' is an allowed character in an HDL, '?' followed by one of the query parameters is the only way we |
|||
have to detect the query string so that it isn't URL-encoded with the rest of the identifier. |
|||
]] |
]] |
||
local function hdl |
local function hdl(id, access) |
||
local |
local handler = cfg.id_handlers['HDL']; |
||
local access = options.access; |
|||
local handler = options.handler; |
|||
local query_params = { -- list of known query parameters from https://www.handle.net/proxy_servlet.html |
|||
'noredirect', |
|||
'ignore_aliases', |
|||
'auth', |
|||
'cert', |
|||
'index', |
|||
'type', |
|||
'urlappend', |
|||
'locatt', |
|||
'action', |
|||
} |
|||
local text = external_link_id({link = handler.link, label = handler.label, q = handler.q, |
|||
local hdl, suffix, param = id:match ('(.-)(%?(%a+).+)$'); -- look for query string |
|||
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode, access=access}) |
|||
local found; |
|||
if nil == id:match("^[^%s–]-/[^%s–]-[^%.,]$") then -- hdl must contain a fwd slash, must not contain spaces, endashes, and must not end with period or comma |
|||
if hdl then -- when there are query strings, this is the handle identifier portion |
|||
text = text .. ' ' .. set_error( 'bad_hdl' ); |
|||
for _, q in ipairs (query_params) do -- spin through the list of query parameters |
|||
if param:match ('^' .. q) then -- if the query string begins with one of the parameters |
|||
found = true; -- announce a find |
|||
break; -- and stop looking |
|||
end |
|||
end |
|||
end |
end |
||
if found then |
|||
id = hdl; -- found so replace id with the handle portion; this will be URL-encoded, suffix will not |
|||
else |
|||
suffix = ''; -- make sure suffix is empty string for concatenation else |
|||
end |
|||
local text = external_link_id ({link = handler.link, label = handler.label, q = handler.q, redirect = handler.redirect, |
|||
prefix = handler.prefix, id = id, suffix = suffix, separator = handler.separator, encode = handler.encode, access = access}) |
|||
if nil == id:match("^[^%s–]-/[^%s–]-[^%.,]$") then -- HDL must contain a forward slash, must not contain spaces, endashes, and must not end with period or comma |
|||
set_message ('err_bad_hdl' ); |
|||
options.coins_list_t['HDL'] = nil; -- when error, unset so not included in COinS |
|||
end |
|||
return text; |
return text; |
||
end |
end |
||
పంక్తి 699: | పంక్తి 468: | ||
]] |
]] |
||
local function isbn |
local function isbn( isbn_str ) |
||
if nil ~= isbn_str:match("[^%s-0-9X]") then |
|||
local isbn_str = options.id; |
|||
return false, 'invalid character'; -- fail if isbn_str contains anything but digits, hyphens, or the uppercase X |
|||
local ignore_invalid = options.accept; |
|||
local handler = options.handler; |
|||
local function return_result (check, err_type) -- local function to handle the various returns |
|||
local ISBN = internal_link_id ({link = handler.link, label = handler.label, redirect = handler.redirect, |
|||
prefix = handler.prefix, id = isbn_str, separator = handler.separator}); |
|||
if ignore_invalid then -- if ignoring ISBN errors |
|||
set_message ('maint_isbn_ignore'); -- add a maint category even when there is no error |
|||
else -- here when not ignoring |
|||
if not check then -- and there is an error |
|||
options.coins_list_t['ISBN'] = nil; -- when error, unset so not included in COinS |
|||
set_message ('err_bad_isbn', err_type); -- set an error message |
|||
return ISBN; -- return id text |
|||
end |
|||
end |
|||
return ISBN; -- return id text |
|||
end |
end |
||
isbn_str = isbn_str:gsub( "-", "" ):gsub( " ", "" ); -- remove hyphens and spaces |
|||
local len = isbn_str:len(); |
|||
return return_result (false, cfg.err_msg_supl.char); -- fail if isbn_str contains anything but digits, hyphens, or the uppercase X |
|||
end |
|||
local id = isbn_str:gsub ('[%s-]', ''); -- remove hyphens and whitespace |
|||
local len = id:len(); |
|||
if len ~= 10 and len ~= 13 then |
if len ~= 10 and len ~= 13 then |
||
return |
return false, 'length'; -- fail if incorrect length |
||
end |
end |
||
if len == 10 then |
if len == 10 then |
||
if |
if isbn_str:match( "^%d*X?$" ) == nil then -- fail if isbn_str has 'X' anywhere but last position |
||
return |
return false, 'invalid form'; |
||
end |
|||
if not is_valid_isxn (id, 10) then -- test isbn-10 for numerical validity |
|||
return return_result (false, cfg.err_msg_supl.check); -- fail if isbn-10 is not numerically valid |
|||
end |
|||
if id:find ('^63[01]') then -- 630xxxxxxx and 631xxxxxxx are (apparently) not valid isbn group ids but are used by amazon as numeric identifiers (asin) |
|||
return return_result (false, cfg.err_msg_supl.group); -- fail if isbn-10 begins with 630/1 |
|||
end |
end |
||
return is_valid_isxn(isbn_str, 10), 'checksum'; |
|||
return return_result (true, cfg.err_msg_supl.check); -- pass if isbn-10 is numerically valid |
|||
else |
else |
||
if |
if isbn_str:match( "^%d+$" ) == nil then |
||
return |
return false, 'invalid character'; -- fail if isbn13 is not all digits |
||
end |
end |
||
if |
if isbn_str:match( "^97[89]%d*$" ) == nil then |
||
return |
return false, 'invalid prefix'; -- fail when isbn13 does not begin with 978 or 979 |
||
end |
end |
||
return is_valid_isxn_13 (isbn_str), 'checksum'; |
|||
if id:match ('^9790') then |
|||
return return_result (false, cfg.err_msg_supl.group); -- group identifier '0' is reserved to ISMN |
|||
end |
|||
return return_result (is_valid_isxn_13 (id), cfg.err_msg_supl.check); |
|||
end |
end |
||
end |
end |
||
--[[--------------------------< A |
--[[--------------------------< A M A Z O N >------------------------------------------------------------------ |
||
Formats a link to Amazon. Do simple error checking: ASIN must be mix of 10 numeric or uppercase alpha |
|||
characters. If a mix, first character must be uppercase alpha; if all numeric, ASINs must be 10-digit |
|||
ISBN. If 10-digit ISBN, add a maintenance category so a bot or AWB script can replace |asin= with |isbn=. |
|||
Error message if not 10 characters, if not ISBN-10, if mixed and first character is a digit. |
|||
Formats a link to Amazon. Do simple error checking: asin must be mix of 10 numeric or uppercase alpha |
|||
|asin=630....... and |asin=631....... are (apparently) not a legitimate ISBN though it checksums as one; these |
|||
characters. If a mix, first character must be uppercase alpha; if all numeric, asins must be 10-digit |
|||
do not cause this function to emit the maint_asin message |
|||
isbn. If 10-digit isbn, add a maintenance category so a bot or awb script can replace |asin= with |isbn=. |
|||
Error message if not 10 characters, if not isbn10, if mixed and first character is a digit. |
|||
This function is positioned here because it calls isbn() |
This function is positioned here because it calls isbn() |
||
పంక్తి 771: | పంక్తి 507: | ||
]] |
]] |
||
local function asin |
local function asin(id, domain) |
||
local |
local err_cat = "" |
||
local domain = options.ASINTLD; |
|||
local err_flag; |
|||
if not id:match("^[%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u]$") then |
if not id:match("^[%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u]$") then |
||
err_cat = ' ' .. set_error ('bad_asin'); -- asin is not a mix of 10 uppercase alpha and numeric characters |
|||
else |
else |
||
if id:match("^%d%d%d%d%d%d%d%d%d[%dX]$") then -- if 10-digit numeric (or 9 digits with terminal X) |
if id:match("^%d%d%d%d%d%d%d%d%d[%dX]$") then -- if 10-digit numeric (or 9 digits with terminal X) |
||
if |
if isbn( id ) then -- see if asin value is isbn10 |
||
add_maint_cat ('ASIN'); |
|||
if not id:find ('^63[01]') then -- 630xxxxxxx and 631xxxxxxx are (apparently) not a valid isbn prefixes but are used by amazon as a numeric identifier |
|||
elseif not is_set (err_cat) then |
|||
err_flag = set_message ('err_bad_asin'); -- ASIN has ISBN-10 form but begins with something other than 630/1 so probably an isbn |
|||
err_cat = ' ' .. set_error ('bad_asin'); -- asin is not isbn10 |
|||
end |
|||
elseif not is_set (err_flag) then |
|||
err_flag = set_message ('err_bad_asin'); -- ASIN is not ISBN-10 |
|||
end |
end |
||
elseif not id:match("^%u[%d%u]+$") then |
elseif not id:match("^%u[%d%u]+$") then |
||
err_cat = ' ' .. set_error ('bad_asin'); -- asin doesn't begin with uppercase alpha |
|||
end |
end |
||
end |
end |
||
if |
if not is_set(domain) then |
||
domain = "com"; |
domain = "com"; |
||
elseif in_array (domain, {'jp', 'uk'}) then |
elseif in_array (domain, {'jp', 'uk'}) then -- Japan, United Kingdom |
||
domain = "co." .. domain; |
domain = "co." .. domain; |
||
elseif in_array (domain, {' |
elseif in_array (domain, {'au', 'br', 'mx'}) then -- Australia, Brazil, Mexico |
||
domain = "cn"; |
|||
elseif in_array (domain, {'au', 'br', 'mx', 'sg', 'tr'}) then -- Australia, Brazil, Mexico, Singapore, Turkey |
|||
domain = "com." .. domain; |
domain = "com." .. domain; |
||
elseif not in_array (domain, {'ae', 'ca', 'cn', 'de', 'es', 'fr', 'in', 'it', 'nl', 'pl', 'sa', 'se', 'co.jp', 'co.uk', 'com', 'com.au', 'com.br', 'com.mx', 'com.sg', 'com.tr'}) then -- Arabic Emirates, Canada, China, Germany, Spain, France, Indonesia, Italy, Netherlands, Poland, Saudi Arabia, Sweden (as of 2021-03 Austria (.at), Liechtenstein (.li) and Switzerland (.ch) still redirect to the German site (.de) with special settings, so don't maintain local ASINs for them) |
|||
err_flag = set_message ('err_bad_asin_tld'); -- unsupported asin-tld value |
|||
end |
end |
||
local handler = |
local handler = cfg.id_handlers['ASIN']; |
||
return external_link_id({link=handler.link, |
|||
label=handler.label, q = handler.q, prefix=handler.prefix .. domain .. "/dp/", |
|||
if not is_set (err_flag) then |
|||
id=id, encode=handler.encode, separator = handler.separator}) .. err_cat; |
|||
options.coins_list_t['ASIN'] = handler.prefix .. domain .. "/dp/" .. id; -- asin for coins |
|||
else |
|||
options.coins_list_t['ASIN'] = nil; -- when error, unset so not included in COinS |
|||
end |
|||
return external_link_id ({link = handler.link, label = handler.label, q = handler.q, redirect = handler.redirect, |
|||
prefix = handler.prefix .. domain .. "/dp/", |
|||
id = id, encode = handler.encode, separator = handler.separator}) |
|||
end |
end |
||
పంక్తి 819: | పంక్తి 539: | ||
--[[--------------------------< I S M N >---------------------------------------------------------------------- |
--[[--------------------------< I S M N >---------------------------------------------------------------------- |
||
Determines whether an ISMN string is valid. Similar to |
Determines whether an ISMN string is valid. Similar to isbn-13, ismn is 13 digits begining 979-0-... and uses the |
||
same check digit calculations. See |
same check digit calculations. See http://www.ismn-international.org/download/Web_ISMN_Users_Manual_2008-6.pdf |
||
section 2, pages 9–12. |
section 2, pages 9–12. |
||
ismn value not made part of COinS metadata because we don't have a url or isn't a COinS-defined identifier (rft.xxx) |
|||
or an identifier registered at info-uri.info (info:) |
|||
]] |
]] |
||
local function ismn ( |
local function ismn (id) |
||
local |
local handler = cfg.id_handlers['ISMN']; |
||
local handler = options.handler; |
|||
local text; |
local text; |
||
local valid_ismn = true; |
local valid_ismn = true; |
||
పంక్తి 836: | పంక్తి 552: | ||
id_copy = id; -- save a copy because this testing is destructive |
id_copy = id; -- save a copy because this testing is destructive |
||
id |
id=id:gsub( "[%s-–]", "" ); -- strip spaces, hyphens, and endashes from the ismn |
||
if 13 ~= id:len() or id:match |
if 13 ~= id:len() or id:match( "^9790%d*$" ) == nil then -- ismn must be 13 digits and begin 9790 |
||
valid_ismn = false; |
valid_ismn = false; |
||
else |
else |
||
valid_ismn=is_valid_isxn_13 (id); -- validate |
valid_ismn=is_valid_isxn_13 (id); -- validate ismn |
||
end |
end |
||
-- text = internal_link_id({link = handler.link, label = handler.label, -- use this (or external version) when there is some place to link to |
|||
-- prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) |
|||
text = table.concat ( |
text = table.concat ( |
||
{ |
{ |
||
make_wikilink |
make_wikilink (handler.link, handler.label), |
||
handler.separator, |
handler.separator, |
||
id_copy |
id_copy |
||
}); -- because no place to link to yet |
|||
}); |
|||
if false == valid_ismn then |
if false == valid_ismn then |
||
text = text .. ' ' .. set_error( 'bad_ismn' ) -- add an error message if the ismn is invalid |
|||
options.coins_list_t['ISMN'] = nil; -- when error, unset so not included in COinS; not really necessary here because ismn not made part of COinS |
|||
set_message ('err_bad_ismn'); -- create an error message if the ISMN is invalid |
|||
end |
end |
||
పంక్తి 865: | పంక్తి 580: | ||
--[[--------------------------< I S S N >---------------------------------------------------------------------- |
--[[--------------------------< I S S N >---------------------------------------------------------------------- |
||
Validate and format an |
Validate and format an issn. This code fixes the case where an editor has included an ISSN in the citation but |
||
has separated the two groups of four digits with a space. When that condition occurred, the resulting link looked |
has separated the two groups of four digits with a space. When that condition occurred, the resulting link looked |
||
like this: |
like this: |
||
|issn=0819 4327 gives: [ |
|issn=0819 4327 gives: [http://www.worldcat.org/issn/0819 4327 0819 4327] -- can't have spaces in an external link |
||
This code now prevents that by inserting a hyphen at the |
This code now prevents that by inserting a hyphen at the issn midpoint. It also validates the issn for length |
||
and makes sure that the checkdigit agrees with the calculated value. Incorrect length (8 digits), characters |
and makes sure that the checkdigit agrees with the calculated value. Incorrect length (8 digits), characters |
||
other than 0-9 and X, or checkdigit / calculated value mismatch will all cause a check |
other than 0-9 and X, or checkdigit / calculated value mismatch will all cause a check issn error message. The |
||
issn is always displayed with a hyphen, even if the issn was given as a single group of 8 digits. |
|||
]] |
]] |
||
local function issn |
local function issn(id, e) |
||
local issn_copy = id; -- save a copy of unadulterated issn; use this version for display if issn does not validate |
|||
local id = options.id; |
|||
local |
local handler; |
||
local ignore_invalid = options.accept; |
|||
local issn_copy = id; -- save a copy of unadulterated ISSN; use this version for display if ISSN does not validate |
|||
local text; |
local text; |
||
local valid_issn = true; |
local valid_issn = true; |
||
if e then |
|||
handler = cfg.id_handlers['EISSN']; |
|||
else |
|||
handler = cfg.id_handlers['ISSN']; |
|||
end |
|||
id |
id=id:gsub( "[%s-–]", "" ); -- strip spaces, hyphens, and endashes from the issn |
||
if 8 ~= id:len() or nil == id:match |
if 8 ~= id:len() or nil == id:match( "^%d*X?$" ) then -- validate the issn: 8 digits long, containing only 0-9 or X in the last position |
||
valid_issn |
valid_issn=false; -- wrong length or improper character |
||
else |
else |
||
valid_issn |
valid_issn=is_valid_isxn(id, 8); -- validate issn |
||
end |
end |
||
if true == valid_issn then |
if true == valid_issn then |
||
id = string.sub |
id = string.sub( id, 1, 4 ) .. "-" .. string.sub( id, 5 ); -- if valid, display correctly formatted version |
||
else |
else |
||
id = issn_copy; -- if not valid, show the invalid |
id = issn_copy; -- if not valid, use the show the invalid issn with error message |
||
end |
|||
text = external_link_id ({link = handler.link, label = handler.label, q = handler.q, redirect = handler.redirect, |
|||
prefix = handler.prefix, id = id, separator = handler.separator, encode = handler.encode}) |
|||
if ignore_invalid then |
|||
set_message ('maint_issn_ignore'); |
|||
else |
|||
if false == valid_issn then |
|||
options.coins_list_t['ISSN'] = nil; -- when error, unset so not included in COinS |
|||
set_message ('err_bad_issn', (options.hkey == 'EISSN') and 'e' or ''); -- create an error message if the ISSN is invalid |
|||
end |
|||
end |
end |
||
text = external_link_id({link = handler.link, label = handler.label, q = handler.q, |
|||
return text; |
|||
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) |
|||
if false == valid_issn then |
|||
text = text .. ' ' .. set_error( 'bad_issn', e and 'e' or '' ) -- add an error message if the issn is invalid |
|||
end |
|||
return text |
|||
end |
end |
||
పంక్తి 923: | పంక్తి 636: | ||
]] |
]] |
||
local function jfm ( |
local function jfm (id) |
||
local |
local handler = cfg.id_handlers['JFM']; |
||
local handler = options.handler; |
|||
local id_num; |
local id_num; |
||
local err_cat = ''; |
|||
id_num = id:match ('^[Jj][Ff][Mm](.*)$'); -- identifier with jfm prefix; extract identifier |
id_num = id:match ('^[Jj][Ff][Mm](.*)$'); -- identifier with jfm prefix; extract identifier |
||
if is_set (id_num) then |
if is_set (id_num) then |
||
add_maint_cat ('jfm_format'); |
|||
else -- plain number without |
else -- plain number without mr prefix |
||
id_num = id; -- if here id does not have prefix |
id_num = id; -- if here id does not have prefix |
||
end |
end |
||
పంక్తి 939: | పంక్తి 652: | ||
id = id_num; -- jfm matches pattern |
id = id_num; -- jfm matches pattern |
||
else |
else |
||
err_cat = ' ' .. set_error( 'bad_jfm' ); -- set an error message |
|||
options.coins_list_t['JFM'] = nil; -- when error, unset so not included in COinS |
|||
end |
|||
return external_link_id ({link = handler.link, label = handler.label, q = handler.q, redirect = handler.redirect, |
|||
prefix = handler.prefix, id = id, separator = handler.separator, encode = handler.encode}); |
|||
end |
|||
--[[--------------------------< J S T O R >-------------------------------------------------------------------- |
|||
Format a JSTOR with some error checking |
|||
]] |
|||
local function jstor (options) |
|||
local id = options.id; |
|||
local access = options.access; |
|||
local handler = options.handler; |
|||
if id:find ('[Jj][Ss][Tt][Oo][Rr]') or id:find ('^https?://') or id:find ('%s') then |
|||
set_message ('err_bad_jstor'); -- set an error message |
|||
options.coins_list_t['JSTOR'] = nil; -- when error, unset so not included in COinS |
|||
end |
end |
||
return external_link_id |
return external_link_id({link = handler.link, label = handler.label, q = handler.q, |
||
prefix |
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat; |
||
end |
end |
||
పంక్తి 973: | పంక్తి 664: | ||
Format LCCN link and do simple error checking. LCCN is a character string 8-12 characters long. The length of |
Format LCCN link and do simple error checking. LCCN is a character string 8-12 characters long. The length of |
||
the LCCN dictates the character type of the first 1-3 characters; the rightmost eight are always digits. |
the LCCN dictates the character type of the first 1-3 characters; the rightmost eight are always digits. |
||
http://info-uri.info/registry/OAIHandler?verb=GetRecord&metadataPrefix=reg&identifier=info:lccn/ |
|||
https://oclc-research.github.io/infoURI-Frozen/info-uri.info/info:lccn/reg.html |
|||
length = 8 then all digits |
length = 8 then all digits |
||
length = 9 then lccn[1] is |
length = 9 then lccn[1] is lower case alpha |
||
length = 10 then lccn[1] and lccn[2] are both |
length = 10 then lccn[1] and lccn[2] are both lower case alpha or both digits |
||
length = 11 then lccn[1] is lower case alpha, lccn[2] and lccn[3] are both |
length = 11 then lccn[1] is lower case alpha, lccn[2] and lccn[3] are both lower case alpha or both digits |
||
length = 12 then lccn[1] and lccn[2] are both |
length = 12 then lccn[1] and lccn[2] are both lower case alpha |
||
]] |
]] |
||
local function lccn |
local function lccn(lccn) |
||
local |
local handler = cfg.id_handlers['LCCN']; |
||
local err_cat = ''; -- presume that LCCN is valid |
|||
local handler = options.handler; |
|||
local |
local id = lccn; -- local copy of the lccn |
||
local id = lccn; -- local copy of the LCCN |
|||
id = normalize_lccn (id); -- get canonical form (no whitespace, hyphens, forward slashes) |
id = normalize_lccn (id); -- get canonical form (no whitespace, hyphens, forward slashes) |
||
local len = id:len(); -- get the length of the |
local len = id:len(); -- get the length of the lccn |
||
if 8 == len then |
if 8 == len then |
||
if id:match("[^%d]") then -- if LCCN has anything but digits (nil if only digits) |
if id:match("[^%d]") then -- if LCCN has anything but digits (nil if only digits) |
||
err_cat = ' ' .. set_error( 'bad_lccn' ); -- set an error message |
|||
end |
end |
||
elseif 9 == len then -- LCCN should be adddddddd |
elseif 9 == len then -- LCCN should be adddddddd |
||
if nil == id:match("%l%d%d%d%d%d%d%d%d") then -- does it match our pattern? |
if nil == id:match("%l%d%d%d%d%d%d%d%d") then -- does it match our pattern? |
||
err_cat = ' ' .. set_error( 'bad_lccn' ); -- set an error message |
|||
end |
end |
||
elseif 10 == len then -- LCCN should be aadddddddd or dddddddddd |
elseif 10 == len then -- LCCN should be aadddddddd or dddddddddd |
||
if id:match("[^%d]") then -- if LCCN has anything but digits (nil if only digits) ... |
if id:match("[^%d]") then -- if LCCN has anything but digits (nil if only digits) ... |
||
if nil == id:match("^%l%l%d%d%d%d%d%d%d%d") then -- ... see if it matches our pattern |
if nil == id:match("^%l%l%d%d%d%d%d%d%d%d") then -- ... see if it matches our pattern |
||
err_cat = ' ' .. set_error( 'bad_lccn' ); -- no match, set an error message |
|||
end |
end |
||
end |
end |
||
elseif 11 == len then -- LCCN should be aaadddddddd or adddddddddd |
elseif 11 == len then -- LCCN should be aaadddddddd or adddddddddd |
||
if not (id:match("^%l%l%l%d%d%d%d%d%d%d%d") or id:match("^%l%d%d%d%d%d%d%d%d%d%d")) then -- see if it matches one of our patterns |
if not (id:match("^%l%l%l%d%d%d%d%d%d%d%d") or id:match("^%l%d%d%d%d%d%d%d%d%d%d")) then -- see if it matches one of our patterns |
||
err_cat = ' ' .. set_error( 'bad_lccn' ); -- no match, set an error message |
|||
end |
end |
||
elseif 12 == len then -- LCCN should be aadddddddddd |
elseif 12 == len then -- LCCN should be aadddddddddd |
||
if not id:match("^%l%l%d%d%d%d%d%d%d%d%d%d") then -- see if it matches our pattern |
if not id:match("^%l%l%d%d%d%d%d%d%d%d%d%d") then -- see if it matches our pattern |
||
err_cat = ' ' .. set_error( 'bad_lccn' ); -- no match, set an error message |
|||
end |
end |
||
else |
else |
||
err_cat = ' ' .. set_error( 'bad_lccn' ); -- wrong length, set an error message |
|||
end |
end |
||
if not is_set ( |
if not is_set (err_cat) and nil ~= lccn:find ('%s') then |
||
err_cat = ' ' .. set_error( 'bad_lccn' ); -- lccn contains a space, set an error message |
|||
end |
end |
||
return external_link_id({link = handler.link, label = handler.label, q = handler.q, |
|||
if is_set (err_flag) then |
|||
prefix=handler.prefix,id=lccn,separator=handler.separator, encode=handler.encode}) .. err_cat; |
|||
options.coins_list_t['LCCN'] = nil; -- when error, unset so not included in COinS |
|||
end |
|||
return external_link_id ({link = handler.link, label = handler.label, q = handler.q, redirect = handler.redirect, |
|||
prefix = handler.prefix, id = lccn, separator = handler.separator, encode = handler.encode}); |
|||
end |
|||
--[[--------------------------< M E D R X I V >----------------------------------------------------------------- |
|||
Format medRxiv ID and do simple error checking. Similar to later bioRxiv IDs, medRxiv IDs are prefixed with a |
|||
yyyy.mm.dd. date and suffixed with an optional version identifier. Ealiest date accepted is 2020.01.01 |
|||
The medRxiv ID is a date followed by an eight-digit number followed by an optional version indicator 'v' and one or more digits: |
|||
https://www.medrxiv.org/content/10.1101/2020.11.16.20232009v2 -> 10.1101/2020.11.16.20232009v2 |
|||
]] |
|||
local function medrxiv (options) |
|||
local id = options.id; |
|||
local handler = options.handler; |
|||
local err_msg_flag = true; -- flag; assume that there will be an error |
|||
local patterns = { |
|||
'%d%d%d%d%d%d%d%d$', -- simple 8-digit identifier; these should be relatively rare |
|||
'^10%.1101/(20%d%d)%.(%d%d)%.(%d%d)%.%d%d%d%d%d%d%d%dv%d+$', -- y.m.d. date + 8-digit identifier + version (2020-01-01 and later) |
|||
'^10%.1101/(20%d%d)%.(%d%d)%.(%d%d)%.%d%d%d%d%d%d%d%d$', -- y.m.d. date + 8-digit identifier (2020-01-01 and later) |
|||
} |
|||
for _, pattern in ipairs (patterns) do -- spin through the patterns looking for a match |
|||
if id:match (pattern) then |
|||
local y, m, d = id:match (pattern); -- found a match, attempt to get year, month and date from the identifier |
|||
if m then -- m is nil when id is the 8-digit form |
|||
if not is_valid_rxiv_date (y, m, d, 'b') then -- validate the encoded date; 'b' for medrxiv limit |
|||
break; -- date fail; break out early so we don't unset the error message |
|||
end |
|||
end |
|||
err_msg_flag = nil; -- we found a match so unset the error message |
|||
break; -- and done |
|||
end |
|||
end -- <err_msg_flag> remains set here when no match |
|||
if err_msg_flag then |
|||
options.coins_list_t['MEDRXIV'] = nil; -- when error, unset so not included in COinS |
|||
set_message ('err_bad_medrxiv'); -- and set the error message |
|||
end |
|||
return external_link_id ({link = handler.link, label = handler.label, q = handler.q, redirect = handler.redirect, |
|||
prefix = handler.prefix, id = id, separator = handler.separator, |
|||
encode = handler.encode, access = handler.access}); |
|||
end |
end |
||
పంక్తి 1,083: | పంక్తి 723: | ||
]] |
]] |
||
local function mr ( |
local function mr (id) |
||
local |
local handler = cfg.id_handlers['MR']; |
||
local handler = options.handler; |
|||
local id_num; |
local id_num; |
||
local id_len; |
local id_len; |
||
local err_cat = ''; |
|||
id_num = id:match ('^[Mm][Rr](%d+)$'); -- identifier with mr prefix |
id_num = id:match ('^[Mm][Rr](%d+)$'); -- identifier with mr prefix |
||
if is_set (id_num) then |
if is_set (id_num) then |
||
add_maint_cat ('mr_format'); |
|||
set_message ('maint_mr_format'); -- add maint cat |
|||
else -- plain number without mr prefix |
else -- plain number without mr prefix |
||
id_num = id:match ('^%d+$'); -- if here id is all digits |
id_num = id:match ('^%d+$'); -- if here id is all digits |
||
పంక్తి 1,099: | పంక్తి 739: | ||
id_len = id_num and id_num:len() or 0; |
id_len = id_num and id_num:len() or 0; |
||
if (7 >= id_len) and (0 ~= id_len) then |
if (7 >= id_len) and (0 ~= id_len) then |
||
id = string.rep ('0', 7-id_len) .. id_num; -- zero-fill leading digits |
id = string.rep ('0', 7-id_len ) .. id_num; -- zero-fill leading digits |
||
else |
else |
||
err_cat = ' ' .. set_error( 'bad_mr' ); -- set an error message |
|||
options.coins_list_t['MR'] = nil; -- when error, unset so not included in COinS |
|||
end |
end |
||
return external_link_id |
return external_link_id({link = handler.link, label = handler.label, q = handler.q, |
||
prefix |
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat; |
||
end |
end |
||
పంక్తి 1,112: | పంక్తి 751: | ||
--[[--------------------------< O C L C >---------------------------------------------------------------------- |
--[[--------------------------< O C L C >---------------------------------------------------------------------- |
||
Validate and format an |
Validate and format an oclc id. https://www.oclc.org/batchload/controlnumber.en.html {{dead link}} |
||
archived at: https://web.archive.org/web/20161228233804/https://www.oclc.org/batchload/controlnumber.en.html |
archived at: https://web.archive.org/web/20161228233804/https://www.oclc.org/batchload/controlnumber.en.html |
||
]] |
]] |
||
local function oclc ( |
local function oclc (id) |
||
local |
local handler = cfg.id_handlers['OCLC']; |
||
local handler = options.handler; |
|||
local number; |
local number; |
||
local err_msg = ''; -- empty string for concatenation |
|||
if id:match('^ocm%d%d%d%d%d%d%d%d$') then -- ocm prefix and 8 digits; 001 field (12 characters) |
if id:match('^ocm%d%d%d%d%d%d%d%d$') then -- ocm prefix and 8 digits; 001 field (12 characters) |
||
number = id:match('ocm(%d+)'); -- get the number |
number = id:match('ocm(%d+)'); -- get the number |
||
పంక్తి 1,131: | పంక్తి 770: | ||
number = id:match('%(OCoLC%)([1-9]%d*)'); -- get the number |
number = id:match('%(OCoLC%)([1-9]%d*)'); -- get the number |
||
if 9 < number:len() then |
if 9 < number:len() then |
||
number = nil; -- |
number = nil; -- contrain to 1 to 9 digits; change this when oclc issues 10-digit numbers |
||
end |
end |
||
elseif id:match('^%d+$') then -- no prefix |
elseif id:match('^%d+$') then -- no prefix |
||
number = id; -- get the number |
number = id; -- get the number |
||
if |
if 10 < number:len() then |
||
number = nil; -- |
number = nil; -- contrain to 1 to 10 digits; change this when oclc issues 11-digit numbers |
||
end |
end |
||
end |
end |
||
పంక్తి 1,143: | పంక్తి 782: | ||
id = number; -- exclude prefix, if any, from external link |
id = number; -- exclude prefix, if any, from external link |
||
else |
else |
||
err_msg = ' ' .. set_error( 'bad_oclc' ) -- add an error message if the id is malformed |
|||
options.coins_list_t['OCLC'] = nil; -- when error, unset so not included in COinS |
|||
end |
end |
||
local text = external_link_id({link=handler.link, label=handler.label, q = handler.q, |
|||
prefix |
prefix=handler.prefix, id=id, separator=handler.separator, encode=handler.encode}) .. err_msg; |
||
return text; |
|||
end |
end |
||
పంక్తి 1,158: | పంక్తి 798: | ||
]] |
]] |
||
local function openlibrary |
local function openlibrary(id, access) |
||
local |
local code; |
||
local |
local handler = cfg.id_handlers['OL']; |
||
local |
local ident; |
||
local ident, code = id:gsub('^OL', ''):match("^(%d+([AMW]))$"); -- strip optional OL prefix followed immediately by digits followed by 'A', 'M', or 'W'; |
|||
ident, code = id:gsub('^OL', ''):match("^(%d+([AMW]))$"); -- optional OL prefix followed immediately by digits followed by 'A', 'M', or 'W'; remove OL prefix |
|||
local err_flag; |
|||
local prefix = { -- these are appended to the handler.prefix according to code |
|||
['A']='authors/OL', |
|||
['M']='books/OL', |
|||
['W']='works/OL', |
|||
['X']='OL' -- not a code; spoof when 'code' in id is invalid |
|||
}; |
|||
if not ident then |
if not is_set (ident) then -- if malformed return an error |
||
return external_link_id({link=handler.link, label=handler.label, q = handler.q, |
|||
code = 'X'; -- no code or id completely invalid |
|||
prefix=handler.prefix .. 'OL', |
|||
ident = id; -- copy id to ident so that we display the flawed identifier |
|||
id=id, separator=handler.separator, encode = handler.encode, |
|||
err_flag = set_message ('err_bad_ol'); |
|||
access = access}) .. ' ' .. set_error( 'bad_ol' ); |
|||
end |
end |
||
id = ident; -- use ident without the optional OL prefix (it has been removed) |
|||
if not is_set (err_flag) then |
|||
options.coins_list_t['OL'] = handler.prefix .. prefix[code] .. ident; -- experiment for ol coins |
|||
if ( code == "A" ) then |
|||
else |
|||
return external_link_id({link=handler.link, label=handler.label, q = handler.q, |
|||
options.coins_list_t['OL'] = nil; -- when error, unset so not included in COinS |
|||
prefix=handler.prefix .. 'authors/OL', |
|||
id=id, separator=handler.separator, encode = handler.encode, |
|||
access = access}) |
|||
end |
|||
if ( code == "M" ) then |
|||
return external_link_id({link=handler.link, label=handler.label, q = handler.q, |
|||
prefix=handler.prefix .. 'books/OL', |
|||
id=id, separator=handler.separator, encode = handler.encode, |
|||
access = access}) |
|||
end |
end |
||
if ( code == "W" ) then |
|||
return external_link_id ({link = handler.link, label = handler.label, q = handler.q, redirect = handler.redirect, |
|||
return external_link_id({link=handler.link, label=handler.label, q = handler.q, |
|||
prefix = handler.prefix .. prefix[code], |
|||
prefix=handler.prefix .. 'works/OL', |
|||
id = ident, separator = handler.separator, encode = handler.encode, |
|||
id=id, separator=handler.separator, encode = handler.encode, |
|||
access = access}); |
|||
access = access}) |
|||
end |
|||
--[[--------------------------< O S T I >---------------------------------------------------------------------- |
|||
Format OSTI and do simple error checking. OSTIs are sequential numbers beginning at 1 and counting up. This |
|||
code checks the OSTI to see that it contains only digits and is less than test_limit specified in the configuration; |
|||
the value in test_limit will need to be updated periodically as more OSTIs are issued. |
|||
NB. 1018 is the lowest OSTI number found in the wild (so far) and resolving OK on the OSTI site |
|||
]] |
|||
local function osti (options) |
|||
local id = options.id; |
|||
local access = options.access; |
|||
local handler = options.handler; |
|||
if id:match("[^%d]") then -- if OSTI has anything but digits |
|||
set_message ('err_bad_osti'); -- set an error message |
|||
options.coins_list_t['OSTI'] = nil; -- when error, unset so not included in COinS |
|||
else -- OSTI is only digits |
|||
local id_num = tonumber (id); -- convert id to a number for range testing |
|||
if 1018 > id_num or handler.id_limit < id_num then -- if OSTI is outside test limit boundaries |
|||
set_message ('err_bad_osti'); -- set an error message |
|||
options.coins_list_t['OSTI'] = nil; -- when error, unset so not included in COinS |
|||
end |
|||
end |
end |
||
return external_link_id ({link = handler.link, label = handler.label, q = handler.q, redirect = handler.redirect, |
|||
prefix = handler.prefix, id = id, separator = handler.separator, encode = handler.encode, access = access}); |
|||
end |
end |
||
పంక్తి 1,238: | పంక్తి 854: | ||
]] |
]] |
||
local function pmc |
local function pmc(id, embargo) |
||
local test_limit = 7000000; -- update this value as PMCs approach |
|||
local id = options.id; |
|||
local handler = cfg.id_handlers['PMC']; |
|||
local embargo = options.Embargo; -- TODO: lowercase? |
|||
local err_cat = ''; -- presume that PMC is valid |
|||
local handler = options.handler; |
|||
local err_flag; |
|||
local id_num; |
local id_num; |
||
local text; |
local text; |
||
id_num = id:match ('^[Pp][Mm][Cc](%d+)$'); -- identifier with |
id_num = id:match ('^[Pp][Mm][Cc](%d+)$'); -- identifier with pmc prefix |
||
if is_set (id_num) then |
if is_set (id_num) then |
||
add_maint_cat ('pmc_format'); |
|||
else -- plain number without |
else -- plain number without pmc prefix |
||
id_num = id:match ('^%d+$'); -- if here id is all digits |
id_num = id:match ('^%d+$'); -- if here id is all digits |
||
end |
end |
||
if is_set (id_num) then -- id_num has a value so test it |
if is_set (id_num) then -- id_num has a value so test it |
||
id_num = tonumber |
id_num = tonumber(id_num); -- convert id_num to a number for range testing |
||
if 1 > id_num or |
if 1 > id_num or test_limit < id_num then -- if PMC is outside test limit boundaries |
||
err_cat = ' ' .. set_error( 'bad_pmc' ); -- set an error message |
|||
else |
else |
||
id = tostring (id_num); -- make sure id is a string |
id = tostring (id_num); -- make sure id is a string |
||
end |
end |
||
else -- when id format incorrect |
else -- when id format incorrect |
||
err_cat = ' ' .. set_error( 'bad_pmc' ); -- set an error message |
|||
end |
end |
||
if is_set (embargo |
if is_set (embargo) then -- is PMC is still embargoed? |
||
text = table.concat ( -- still embargoed so no external link |
text = table.concat ( -- still embargoed so no external link |
||
{ |
{ |
||
make_wikilink |
make_wikilink (handler.link, handler.label), |
||
handler.separator, |
handler.separator, |
||
id, |
id, |
||
err_cat |
|||
}); |
}); |
||
else |
else |
||
text = external_link_id |
text = external_link_id({link = handler.link, label = handler.label, q = handler.q, -- no embargo date or embargo has expired, ok to link to article |
||
prefix |
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode, access=handler.access}) .. err_cat; |
||
auto_link = not err_flag and 'pmc' or nil -- do not auto-link when PMC has error |
|||
}); |
|||
end |
end |
||
if err_flag then |
|||
options.coins_list_t['PMC'] = nil; -- when error, unset so not included in COinS |
|||
end |
|||
return text; |
return text; |
||
end |
end |
||
పంక్తి 1,295: | పంక్తి 904: | ||
]] |
]] |
||
local function pmid |
local function pmid(id) |
||
local test_limit = 32000000; -- update this value as PMIDs approach |
|||
local id = options.id; |
|||
local handler = |
local handler = cfg.id_handlers['PMID']; |
||
local err_cat = ''; -- presume that PMID is valid |
|||
if id:match("[^%d]") then -- if PMID has anything but digits |
if id:match("[^%d]") then -- if PMID has anything but digits |
||
err_cat = ' ' .. set_error( 'bad_pmid' ); -- set an error message |
|||
options.coins_list_t['PMID'] = nil; -- when error, unset so not included in COinS |
|||
else -- PMID is only digits |
else -- PMID is only digits |
||
local id_num = tonumber |
local id_num = tonumber(id); -- convert id to a number for range testing |
||
if 1 > id_num or |
if 1 > id_num or test_limit < id_num then -- if PMID is outside test limit boundaries |
||
err_cat = ' ' .. set_error( 'bad_pmid' ); -- set an error message |
|||
options.coins_list_t['PMID'] = nil; -- when error, unset so not included in COinS |
|||
end |
end |
||
end |
end |
||
return external_link_id |
return external_link_id({link = handler.link, label = handler.label, q = handler.q, |
||
prefix |
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat; |
||
end |
|||
--[[--------------------------< R F C >------------------------------------------------------------------------ |
|||
Format RFC and do simple error checking. RFCs are sequential numbers beginning at 1 and counting up. This |
|||
code checks the RFC to see that it contains only digits and is less than test_limit specified in the configuration; |
|||
the value in test_limit will need to be updated periodically as more RFCs are issued. |
|||
An index of all RFCs is here: https://tools.ietf.org/rfc/ |
|||
]] |
|||
local function rfc (options) |
|||
local id = options.id; |
|||
local handler = options.handler; |
|||
if id:match("[^%d]") then -- if RFC has anything but digits |
|||
set_message ('err_bad_rfc'); -- set an error message |
|||
options.coins_list_t['RFC'] = nil; -- when error, unset so not included in COinS |
|||
else -- RFC is only digits |
|||
local id_num = tonumber (id); -- convert id to a number for range testing |
|||
if 1 > id_num or handler.id_limit < id_num then -- if RFC is outside test limit boundaries |
|||
set_message ('err_bad_rfc'); -- set an error message |
|||
options.coins_list_t['RFC'] = nil; -- when error, unset so not included in COinS |
|||
end |
|||
end |
|||
return external_link_id ({link = handler.link, label = handler.label, q = handler.q, redirect = handler.redirect, |
|||
prefix = handler.prefix, id = id, separator = handler.separator, encode = handler.encode, access = handler.access}); |
|||
end |
|||
--[[--------------------------< S 2 C I D >-------------------------------------------------------------------- |
|||
Format an S2CID, do simple error checking |
|||
S2CIDs are sequential numbers beginning at 1 and counting up. This code checks the S2CID to see that it is only |
|||
digits and is less than test_limit; the value in local variable test_limit will need to be updated periodically |
|||
as more S2CIDs are issued. |
|||
]] |
|||
local function s2cid (options) |
|||
local id = options.id; |
|||
local access = options.access; |
|||
local handler = options.handler; |
|||
local id_num; |
|||
local text; |
|||
id_num = id:match ('^[1-9]%d*$'); -- id must be all digits; must not begin with 0; no open access flag |
|||
if is_set (id_num) then -- id_num has a value so test it |
|||
id_num = tonumber (id_num); -- convert id_num to a number for range testing |
|||
if handler.id_limit < id_num then -- if S2CID is outside test limit boundaries |
|||
set_message ('err_bad_s2cid'); -- set an error message |
|||
options.coins_list_t['S2CID'] = nil; -- when error, unset so not included in COinS |
|||
end |
|||
else -- when id format incorrect |
|||
set_message ('err_bad_s2cid'); -- set an error message |
|||
options.coins_list_t['S2CID'] = nil; -- when error, unset so not included in COinS |
|||
end |
|||
text = external_link_id ({link = handler.link, label = handler.label, q = handler.q, redirect = handler.redirect, |
|||
prefix = handler.prefix, id = id, separator = handler.separator, encode = handler.encode, access = access}); |
|||
return text; |
|||
end |
|||
--[[--------------------------< S B N >------------------------------------------------------------------------ |
|||
9-digit form of ISBN-10; uses same check-digit validation when SBN is prefixed with an additional '0' to make 10 digits |
|||
sbn value not made part of COinS metadata because we don't have a url or isn't a COinS-defined identifier (rft.xxx) |
|||
or an identifier registered at info-uri.info (info:) |
|||
]] |
|||
local function sbn (options) |
|||
local id = options.id; |
|||
local ignore_invalid = options.accept; |
|||
local handler = options.handler; |
|||
local function return_result (check, err_type) -- local function to handle the various returns |
|||
local SBN = internal_link_id ({link = handler.link, label = handler.label, redirect = handler.redirect, |
|||
prefix = handler.prefix, id = id, separator = handler.separator}); |
|||
if not ignore_invalid then -- if not ignoring SBN errors |
|||
if not check then |
|||
options.coins_list_t['SBN'] = nil; -- when error, unset so not included in COinS; not really necessary here because sbn not made part of COinS |
|||
set_message ('err_bad_sbn', {err_type}); -- display an error message |
|||
return SBN; |
|||
end |
|||
else |
|||
set_message ('maint_isbn_ignore'); -- add a maint category even when there is no error (ToDo: Possibly switch to separate message for SBNs only) |
|||
end |
|||
return SBN; |
|||
end |
|||
if id:match ('[^%s-0-9X]') then |
|||
return return_result (false, cfg.err_msg_supl.char); -- fail if SBN contains anything but digits, hyphens, or the uppercase X |
|||
end |
|||
local ident = id:gsub ('[%s-]', ''); -- remove hyphens and whitespace; they interfere with the rest of the tests |
|||
if 9 ~= ident:len() then |
|||
return return_result (false, cfg.err_msg_supl.length); -- fail if incorrect length |
|||
end |
|||
if ident:match ('^%d*X?$') == nil then |
|||
return return_result (false, cfg.err_msg_supl.form); -- fail if SBN has 'X' anywhere but last position |
|||
end |
|||
return return_result (is_valid_isxn ('0' .. ident, 10), cfg.err_msg_supl.check); |
|||
end |
end |
||
పంక్తి 1,430: | పంక్తి 925: | ||
--[[--------------------------< S S R N >---------------------------------------------------------------------- |
--[[--------------------------< S S R N >---------------------------------------------------------------------- |
||
Format an |
Format an ssrn, do simple error checking |
||
SSRNs are sequential numbers beginning at 100? and counting up. This code checks the |
SSRNs are sequential numbers beginning at 100? and counting up. This code checks the ssrn to see that it is |
||
only digits and is greater than 99 and less than test_limit; the value in local variable test_limit will need |
only digits and is greater than 99 and less than test_limit; the value in local variable test_limit will need |
||
to be updated periodically as more SSRNs are issued. |
to be updated periodically as more SSRNs are issued. |
||
పంక్తి 1,438: | పంక్తి 933: | ||
]] |
]] |
||
local function ssrn ( |
local function ssrn (id) |
||
local test_limit = 3500000; -- update this value as SSRNs approach |
|||
local id = options.id; |
|||
local handler = |
local handler = cfg.id_handlers['SSRN']; |
||
local err_cat = ''; -- presume that SSRN is valid |
|||
local id_num; |
local id_num; |
||
local text; |
local text; |
||
పంక్తి 1,447: | పంక్తి 943: | ||
if is_set (id_num) then -- id_num has a value so test it |
if is_set (id_num) then -- id_num has a value so test it |
||
id_num = tonumber |
id_num = tonumber(id_num); -- convert id_num to a number for range testing |
||
if 100 > id_num or |
if 100 > id_num or test_limit < id_num then -- if SSRN is outside test limit boundaries |
||
err_cat = ' ' .. set_error( 'bad_ssrn' ); -- set an error message |
|||
options.coins_list_t['SSRN'] = nil; -- when error, unset so not included in COinS |
|||
end |
end |
||
else -- when id format incorrect |
else -- when id format incorrect |
||
err_cat = ' ' .. set_error( 'bad_ssrn' ); -- set an error message |
|||
options.coins_list_t['SSRN'] = nil; -- when error, unset so not included in COinS |
|||
end |
end |
||
text = external_link_id |
text = external_link_id({link = handler.link, label = handler.label, q = handler.q, |
||
prefix |
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode, access=handler.access}) .. err_cat; |
||
return text; |
return text; |
||
పంక్తి 1,471: | పంక్తి 965: | ||
]] |
]] |
||
local function usenet_id ( |
local function usenet_id (id) |
||
local |
local handler = cfg.id_handlers['USENETID']; |
||
local handler = options.handler; |
|||
local text = external_link_id |
local text = external_link_id({link = handler.link, label = handler.label, q = handler.q, |
||
prefix |
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) |
||
if not id:match('^.+@.+$') or not id:match('^[^<].*[^>]$') |
if not id:match('^.+@.+$') or not id:match('^[^<].*[^>]$')then -- doesn't have '@' or has one or first or last character is '< or '>' |
||
text = text .. ' ' .. set_error( 'bad_usenet_id' ) -- add an error message if the message id is invalid |
|||
options.coins_list_t['USENETID'] = nil; -- when error, unset so not included in COinS |
|||
end |
end |
||
return text |
return text |
||
end |
end |
||
పంక్తి 1,497: | పంక్తి 989: | ||
]] |
]] |
||
local function zbl ( |
local function zbl (id) |
||
local |
local handler = cfg.id_handlers['ZBL']; |
||
local |
local err_cat = ''; |
||
if id:match('^%d%d%d%d%d%d%d%d$') then -- is this identifier using temporary format? |
if id:match('^%d%d%d%d%d%d%d%d$') then -- is this identifier using temporary format? |
||
add_maint_cat ('zbl'); -- yes, add maint cat |
|||
elseif not id:match('^%d?%d?%d?%d%.%d%d%d%d%d$') then -- not temporary, is it normal format? |
elseif not id:match('^%d?%d?%d?%d%.%d%d%d%d%d$') then -- not temporary, is it normal format? |
||
err_cat = ' ' .. set_error( 'bad_zbl' ); -- no, set an error message |
|||
options.coins_list_t['ZBL'] = nil; -- when error, unset so not included in COinS |
|||
end |
end |
||
return external_link_id |
return external_link_id({link = handler.link, label = handler.label, q = handler.q, |
||
prefix |
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat; |
||
end |
end |
||
--============================<< I N T E R F A C E F U N C T I O N S >>========================================== |
--============================<< I N T E R F A C E F U N C T I O N S >>========================================== |
||
--[[--------------------------< B U I L D _ I D _ L I S T >-------------------------------------------------------- |
|||
Takes a table of IDs created by extract_ids() and turns it into a table of formatted ID outputs. |
|||
inputs: |
|||
id_list – table of identifiers built by extract_ids() |
|||
options – table of various template parameter values used to modify some manually handled identifiers |
|||
]] |
|||
local function build_id_list( id_list, options ) |
|||
local new_list, handler = {}; |
|||
local function fallback(k) return { __index = function(t,i) return cfg.id_handlers[k][i] end } end; |
|||
for k, v in pairs( id_list ) do -- k is uc identifier name as index to cfg.id_handlers; e.g. cfg.id_handlers['ISBN'], v is a table |
|||
-- fallback to read-only cfg |
|||
handler = setmetatable( { ['id'] = v, ['access'] = options.IdAccessLevels[k] }, fallback(k) ); |
|||
if handler.mode == 'external' then |
|||
table.insert( new_list, {handler.label, external_link_id( handler ) } ); |
|||
elseif handler.mode == 'internal' then |
|||
table.insert( new_list, {handler.label, internal_link_id( handler ) } ); |
|||
elseif handler.mode ~= 'manual' then |
|||
error( cfg.messages['unknown_ID_mode'] ); |
|||
elseif k == 'ARXIV' then |
|||
table.insert( new_list, {handler.label, arxiv( v, options.Class ) } ); |
|||
elseif k == 'ASIN' then |
|||
table.insert( new_list, {handler.label, asin( v, options.ASINTLD ) } ); |
|||
elseif k == 'BIBCODE' then |
|||
table.insert( new_list, {handler.label, bibcode( v, handler.access ) } ); |
|||
elseif k == 'BIORXIV' then |
|||
table.insert( new_list, {handler.label, biorxiv( v ) } ); |
|||
elseif k == 'CITESEERX' then |
|||
table.insert( new_list, {handler.label, citeseerx( v ) } ); |
|||
elseif k == 'DOI' then |
|||
table.insert( new_list, {handler.label, doi( v, options.DoiBroken, handler.access ) } ); |
|||
elseif k == 'EISSN' then |
|||
table.insert( new_list, {handler.label, issn( v, true ) } ); -- true distinguishes eissn from issn |
|||
elseif k == 'HDL' then |
|||
table.insert( new_list, {handler.label, hdl( v, handler.access ) } ); |
|||
elseif k == 'ISBN' then |
|||
local ISBN = internal_link_id( handler ); |
|||
local check; |
|||
local err_type = ''; |
|||
check, err_type = isbn( v ); |
|||
if not check then |
|||
if is_set(options.IgnoreISBN) then -- ISBN is invalid; if |ignore-isbn-error= set |
|||
add_maint_cat ('ignore_isbn_err'); -- ad a maint category |
|||
else |
|||
ISBN = ISBN .. set_error( 'bad_isbn', {err_type}, false, " ", "" ); -- else display an error message |
|||
end |
|||
elseif is_set(options.IgnoreISBN) then -- ISBN is OK; if |ignore-isbn-error= set |
|||
add_maint_cat ('ignore_isbn_err'); -- because |ignore-isbn-error= unnecessary |
|||
end |
|||
table.insert( new_list, {handler.label, ISBN } ); |
|||
elseif k == 'ISMN' then |
|||
table.insert( new_list, {handler.label, ismn( v ) } ); |
|||
elseif k == 'ISSN' then |
|||
table.insert( new_list, {handler.label, issn( v ) } ); |
|||
elseif k == 'JFM' then |
|||
table.insert( new_list, {handler.label, jfm( v ) } ); |
|||
elseif k == 'LCCN' then |
|||
table.insert( new_list, {handler.label, lccn( v ) } ); |
|||
elseif k == 'MR' then |
|||
table.insert( new_list, {handler.label, mr( v ) } ); |
|||
elseif k == 'OCLC' then |
|||
table.insert( new_list, {handler.label, oclc( v ) } ); |
|||
elseif k == 'OL' or k == 'OLA' then |
|||
table.insert( new_list, {handler.label, openlibrary( v, handler.access ) } ); |
|||
elseif k == 'PMC' then |
|||
table.insert( new_list, {handler.label, pmc( v, options.Embargo ) } ); |
|||
elseif k == 'PMID' then |
|||
table.insert( new_list, {handler.label, pmid( v ) } ); |
|||
elseif k == 'SSRN' then |
|||
table.insert( new_list, {handler.label, ssrn( v ) } ); |
|||
elseif k == 'USENETID' then |
|||
table.insert( new_list, {handler.label, usenet_id( v ) } ); |
|||
elseif k == 'ZBL' then |
|||
table.insert( new_list, {handler.label, zbl( v ) } ); |
|||
else |
|||
error( cfg.messages['unknown_manual_ID'] ); |
|||
end |
|||
end |
|||
local function comp( a, b ) -- used in following table.sort() |
|||
return a[1]:lower() < b[1]:lower(); |
|||
end |
|||
table.sort( new_list, comp ); |
|||
for k, v in ipairs( new_list ) do |
|||
new_list[k] = v[2]; |
|||
end |
|||
return new_list; |
|||
end |
|||
--[[--------------------------< E X T R A C T _ I D S >------------------------------------------------------------ |
--[[--------------------------< E X T R A C T _ I D S >------------------------------------------------------------ |
||
పంక్తి 1,519: | పంక్తి 1,108: | ||
Populates ID table from arguments using configuration settings. Loops through cfg.id_handlers and searches args for |
Populates ID table from arguments using configuration settings. Loops through cfg.id_handlers and searches args for |
||
any of the parameters listed in each cfg.id_handlers['...'].parameters. If found, adds the parameter and value to |
any of the parameters listed in each cfg.id_handlers['...'].parameters. If found, adds the parameter and value to |
||
the identifier list. Emits redundant error message |
the identifier list. Emits redundant error message is more than one alias exists in args |
||
]] |
]] |
||
local function extract_ids |
local function extract_ids( args ) |
||
local id_list = {}; -- list of identifiers found in args |
local id_list = {}; -- list of identifiers found in args |
||
for k, v in pairs |
for k, v in pairs( cfg.id_handlers ) do -- k is uc identifier name as index to cfg.id_handlers; e.g. cfg.id_handlers['ISBN'], v is a table |
||
v = select_one |
v = select_one( args, v.parameters, 'redundant_parameters' ); -- v.parameters is a table of aliases for k; here we pick one from args if present |
||
if is_set |
if is_set(v) then id_list[k] = v; end -- if found in args, add identifier to our list |
||
end |
end |
||
return id_list; |
return id_list; |
||
పంక్తి 1,535: | పంక్తి 1,124: | ||
--[[--------------------------< E X T R A C T _ I D _ A C C E S S _ L E V E L S >-------------------------------------- |
--[[--------------------------< E X T R A C T _ I D _ A C C E S S _ L E V E L S >-------------------------------------- |
||
Fetches custom id access levels from arguments using configuration settings. |
Fetches custom id access levels from arguments using configuration settings. |
||
Parameters which have a predefined access level (e.g. arxiv) do not use this |
|||
function as they are directly rendered as free without using an additional parameter. |
|||
access-level values must match the case used in cfg.keywords['id-access'] (lowercase unless there is some special reason for something else) |
|||
returns a table of k/v pairs where k is same as the identifier's key in cfg.id_handlers and v is the assigned (valid) keyword |
|||
access-level values must match the case used in cfg.keywords_lists['id-access'] (lowercase unless there is some special reason for something else) |
|||
]] |
]] |
||
local function extract_id_access_levels |
local function extract_id_access_levels( args, id_list ) |
||
local id_accesses_list = {}; |
local id_accesses_list = {}; |
||
for k, v in pairs |
for k, v in pairs( cfg.id_handlers ) do |
||
local access_param = v.custom_access; -- name of identifier's access-level parameter |
local access_param = v.custom_access; -- name of identifier's access-level parameter |
||
if is_set |
if is_set(access_param) then |
||
local access_level = args[access_param]; -- get the assigned value if there is one |
local access_level = args[access_param]; -- get the assigned value if there is one |
||
if is_set (access_level) then |
if is_set (access_level) then |
||
if not in_array (access_level, cfg. |
if not in_array (access_level, cfg.keywords['id-access']) then -- exact match required |
||
table.insert( z.message_tail, { set_error( 'invalid_param_val', {access_param, access_level}, true ) } ); |
|||
access_level = nil; -- invalid so unset |
access_level = nil; -- invalid so unset |
||
end |
end |
||
if not is_set |
if not is_set(id_list[k]) then -- identifer access-level must have a matching identifier |
||
table.insert( z.message_tail, { set_error( 'param_access_requires_param', {k:lower()}, true ) } ); -- param name is uppercase in cfg.id_handlers (k); lowercase for error message |
|||
end |
end |
||
id_accesses_list[k] = |
id_accesses_list[k] = access_level; |
||
end |
end |
||
end |
end |
||
end |
end |
||
return id_accesses_list; |
return id_accesses_list; |
||
end |
|||
--[[--------------------------< B U I L D _ I D _ L I S T >---------------------------------------------------- |
|||
render the identifiers into a sorted sequence table |
|||
<ID_list_coins_t> is a table of k/v pairs where k is same as key in cfg.id_handlers and v is the assigned value |
|||
<options_t> is a table of various k/v option pairs provided in the call to new_build_id_list(); |
|||
modified by this function and passed to all identifier rendering functions |
|||
<access_levels_t> is a table of k/v pairs where k is same as key in cfg.id_handlers and v is the assigned value (if valid) |
|||
returns a sequence table of sorted (by hkey - 'handler' key) rendered identifier strings |
|||
]] |
|||
local function build_id_list (ID_list_coins_t, options_t, access_levels_t) |
|||
local ID_list_t = {}; |
|||
local accept; |
|||
local func_map = { --function map points to functions associated with hkey identifier |
|||
['ARXIV'] = arxiv, |
|||
['ASIN'] = asin, |
|||
['BIBCODE'] = bibcode, |
|||
['BIORXIV'] = biorxiv, |
|||
['CITESEERX'] = citeseerx, |
|||
['DOI'] = doi, |
|||
['EISSN'] = issn, |
|||
['HDL'] = hdl, |
|||
['ISBN'] = isbn, |
|||
['ISMN'] = ismn, |
|||
['ISSN'] = issn, |
|||
['JFM'] = jfm, |
|||
['JSTOR'] = jstor, |
|||
['LCCN'] = lccn, |
|||
['MEDRXIV'] = medrxiv, |
|||
['MR'] = mr, |
|||
['OCLC'] = oclc, |
|||
['OL'] = openlibrary, |
|||
['OSTI'] = osti, |
|||
['PMC'] = pmc, |
|||
['PMID'] = pmid, |
|||
['RFC'] = rfc, |
|||
['S2CID'] = s2cid, |
|||
['SBN'] = sbn, |
|||
['SSRN'] = ssrn, |
|||
['USENETID'] = usenet_id, |
|||
['ZBL'] = zbl, |
|||
} |
|||
for hkey, v in pairs (ID_list_coins_t) do |
|||
v, accept = has_accept_as_written (v); -- remove accept-as-written markup if present; accept is boolean true when markup removed; false else |
|||
-- every function gets the options table with value v and accept boolean |
|||
options_t.hkey = hkey; -- ~/Configuration handler key |
|||
options_t.id = v; -- add that identifier value to the options table |
|||
options_t.accept = accept; -- add the accept boolean flag |
|||
options_t.access = access_levels_t[hkey]; -- add the access level for those that have an |<identifier-access= parameter |
|||
options_t.handler = cfg.id_handlers[hkey]; |
|||
options_t.coins_list_t = ID_list_coins_t; -- pointer to ID_list_coins_t; for |asin= and |ol=; also to keep erroneous values out of the citation's metadata |
|||
options_t.coins_list_t[hkey] = v; -- id value without accept-as-written markup for metadata |
|||
if options_t.handler.access and not in_array (options_t.handler.access, cfg.keywords_lists['id-access']) then |
|||
error (cfg.messages['unknown_ID_access'] .. options_t.handler.access); -- here when handler access key set to a value not listed in list of allowed id access keywords |
|||
end |
|||
if func_map[hkey] then |
|||
local id_text = func_map[hkey] (options_t); -- call the function to get identifier text and any error message |
|||
table.insert (ID_list_t, {hkey, id_text}); -- add identifier text to the output sequence table |
|||
else |
|||
error (cfg.messages['unknown_ID_key'] .. hkey); -- here when func_map doesn't have a function for hkey |
|||
end |
|||
end |
|||
local function comp (a, b) -- used by following table.sort() |
|||
return a[1]:lower() < b[1]:lower(); -- sort by hkey |
|||
end |
|||
table.sort (ID_list_t, comp); -- sequence table of tables sort |
|||
for k, v in ipairs (ID_list_t) do -- convert sequence table of tables to simple sequence table of strings |
|||
ID_list_t[k] = v[2]; -- v[2] is the identifier rendering from the call to the various functions in func_map{} |
|||
end |
|||
return ID_list_t; |
|||
end |
|||
--[[--------------------------< O P T I O N S _ C H E C K >---------------------------------------------------- |
|||
check that certain option parameters have their associated identifier parameters with values |
|||
<ID_list_coins_t> is a table of k/v pairs where k is same as key in cfg.id_handlers and v is the assigned value |
|||
<ID_support_t> is a sequence table of tables created in citation0() where each subtable has four elements: |
|||
[1] is the support parameter's assigned value; empty string if not set |
|||
[2] is a text string same as key in cfg.id_handlers |
|||
[3] is cfg.error_conditions key used to create error message |
|||
[4] is original ID support parameter name used to create error message |
|||
returns nothing; on error emits an appropriate error message |
|||
]] |
|||
local function options_check (ID_list_coins_t, ID_support_t) |
|||
for _, v in ipairs (ID_support_t) do |
|||
if is_set (v[1]) and not ID_list_coins_t[v[2]] then -- when support parameter has a value but matching identifier parameter is missing or empty |
|||
set_message (v[3], (v[4])); -- emit the appropriate error message |
|||
end |
|||
end |
|||
end |
|||
--[[--------------------------< I D E N T I F I E R _ L I S T S _ G E T >-------------------------------------- |
|||
Creates two identifier lists: a k/v table of identifiers and their values to be used locally and for use in the |
|||
COinS metadata, and a sequence table of the rendered identifier strings that will be included in the rendered |
|||
citation. |
|||
]] |
|||
local function identifier_lists_get (args_t, options_t, ID_support_t) |
|||
local ID_list_coins_t = extract_ids (args_t); -- get a table of identifiers and their values for use locally and for use in COinS |
|||
options_check (ID_list_coins_t, ID_support_t); -- ID support parameters must have matching identifier parameters |
|||
local ID_access_levels_t = extract_id_access_levels (args_t, ID_list_coins_t); -- get a table of identifier access levels |
|||
local ID_list_t = build_id_list (ID_list_coins_t, options_t, ID_access_levels_t); -- get a sequence table of rendered identifier strings |
|||
return ID_list_t, ID_list_coins_t; -- return the tables |
|||
end |
end |
||
పంక్తి 1,699: | పంక్తి 1,163: | ||
cfg = cfg_table_ptr; |
cfg = cfg_table_ptr; |
||
is_set = utilities_page_ptr.is_set; -- import functions from select Module:Citation/CS1/Utilities module |
|||
is_set = utilities_page_ptr.is_set; |
|||
in_array = utilities_page_ptr.in_array; |
in_array = utilities_page_ptr.in_array; |
||
set_error = utilities_page_ptr.set_error; |
|||
select_one = utilities_page_ptr.select_one; |
select_one = utilities_page_ptr.select_one; |
||
add_maint_cat = utilities_page_ptr.add_maint_cat; |
|||
substitute = utilities_page_ptr.substitute; |
substitute = utilities_page_ptr.substitute; |
||
make_wikilink = utilities_page_ptr.make_wikilink; |
make_wikilink = utilities_page_ptr.make_wikilink; |
||
పంక్తి 1,715: | పంక్తి 1,179: | ||
return { |
return { |
||
build_id_list = build_id_list, |
|||
auto_link_urls = auto_link_urls, -- table of identifier URLs to be used when auto-linking |title= |
|||
extract_ids = extract_ids, |
|||
extract_id_access_levels = extract_id_access_levels, |
|||
identifier_lists_get = identifier_lists_get, -- experiment to replace individual calls to build_id_list(), extract_ids, extract_id_access_levels |
|||
is_embargoed = is_embargoed; |
is_embargoed = is_embargoed; |
||
set_selected_modules = set_selected_modules; |
set_selected_modules = set_selected_modules; |