1if not modules then modules = { } end modules ['publ-aut'] = {
2 version = 1.001,
3 comment = "this module part of publication support",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9if not characters then
10 dofile(resolvers.findfile("char-def.lua"))
11 dofile(resolvers.findfile("char-ini.lua"))
12end
13
14local lpeg = lpeg
15
16local type, next, tostring, tonumber = type, next, tostring, tonumber
17local concat, sortedhash = table.concat, table.sortedhash
18local utfsub = utf.sub
19local find = string.find
20local formatters = string.formatters
21
22local P, S, C, V, Cs, Ct, Cg, Cf, Cc = lpeg.P, lpeg.S, lpeg.C, lpeg.V, lpeg.Cs, lpeg.Ct, lpeg.Cg, lpeg.Cf, lpeg.Cc
23local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
24local settings_to_hash = utilities.parsers.settings_to_hash
25
26local context = context
27
28
29local implement = interfaces.implement
30
31local publications = publications
32
33local datasets = publications.datasets
34local getcasted = publications.getcasted
35
36local allocate = utilities.storage.allocate
37
38local chardata = characters.data
39
40local trace_hashing = false trackers.register("publications.authorhash", function(v) trace_hashing = v end)
41
42local expand_authors = false directives.register("publications.prerollauthor", function(v) expand_authors = v end)
43
44local report = logs.reporter("publications","authors")
45local report_cite = logs.reporter("publications","cite")
46
47local v_last = interfaces.variables.last
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65local space = lpegpatterns.whitespace
66local comma = P(",")
67local period = P(".") + P("{.}")
68local dash = P("-") + P("{-}")
69local firstcharacter = lpegpatterns.utf8byte
70local utf8character = lpegpatterns.utf8character
71local p_and = space^1 * (P("and") + P("&&") + P("++")) * space^1
72local p_comma = space^0 * comma * space^0
73local p_space = space^1
74local p_shortone = C((utf8character -dash-period)^1)
75local p_longone = C( utf8character) * (1-dash-period)^0
76
77local p_empty = P("{}")/"" * #(p_space^0 * (P(-1) + P(",")))
78
79local andsplitter = Ct { "start",
80 start = (Cs((V("inner") + (1-p_and))^1) + p_and)^1,
81 inner = P("{") * ((V("inner") + P(1-P("}")))^1) * P("}"),
82}
83
84local commasplitter = Ct { "start",
85 start = Cs(V("outer")) + (p_empty + Cs((V("inner") + (1-p_comma))^1) + p_comma)^1,
86 outer = (P("{")/"") * ((V("inner") + P(1-P("}")))^1) * ((P("}") * P(-1))/""),
87 inner = P("{") * ((V("inner") + P(1-P("}")))^1) * P("}"),
88}
89
90local spacesplitter = Ct { "start",
91 start = Cs(V("outer")) + (Cs((V("inner") + (1-p_space))^1) + p_space)^1,
92 outer = (P("{")/"") * ((V("inner") + P(1-P("}")))^1) * ((P("}") * P(-1))/""),
93 inner = P("{") * ((V("inner") + P(1-P("}")))^1) * P("}"),
94}
95
96local p_initial = p_shortone * period * dash^0
97 + p_longone * (period + dash + P(-1))
98local initialsplitter = p_initial * P(-1) + Ct((p_initial)^1)
99
100local optionsplitter = Cf(Ct("") * Cg(C((1-space)^1) * space^0 * Cc(true))^1,rawset)
101
102local function is_upper(str)
103 local first = lpegmatch(firstcharacter,str)
104 local okay = chardata[first]
105 return okay and okay.category == "lu"
106end
107
108
109
110local cache = allocate()
111local nofhits = 0
112local nofused = 0
113
114publications.authorcache = cache
115
116local function makeinitials(firstnames)
117 if firstnames and #firstnames > 0 then
118 local initials = { }
119 for i=1,#firstnames do
120 initials[i] = lpegmatch(initialsplitter,firstnames[i])
121 end
122 return initials
123 end
124end
125
126local authormap = allocate()
127publications.authormap = authormap
128
129local prerollcmdstring = publications.prerollcmdstring
130
131local function splitauthor(author,justsplit)
132 local detail, remapped
133 if not justsplit then
134 detail = cache[author]
135 if detail then
136 return detail
137 end
138 remapped = authormap[author]
139 if remapped then
140 report("remapping %a to %a",author,remapped)
141 local detail = cache[remapped]
142 if detail then
143 cache[author] = detail
144 return detail
145 end
146 end
147 end
148 local author = remapped or author
149 local firstnames, vons, surnames, initials, juniors, options
150 if expand_authors and find(author,"\\btxcmd") then
151 author = prerollcmdstring(author)
152 end
153 local split = lpegmatch(commasplitter,author)
154 local n = #split
155 detail = {
156 original = author,
157 snippets = n,
158 }
159 if n == 1 then
160
161 local words = lpegmatch(spacesplitter,author)
162 local i = 1
163 local n = #words
164 firstnames = { }
165 vons = { }
166 surnames = { }
167 while i <= n do
168 local w = words[i]
169 if is_upper(w) then
170 firstnames[#firstnames+1], i = w, i + 1
171 else
172 break
173 end
174 end
175 while i <= n do
176 local w = words[i]
177 if is_upper(w) then
178 break
179 else
180 vons[#vons+1], i = w, i + 1
181 end
182 end
183 if i <= n then
184 while i <= n do
185 surnames[#surnames+1], i = words[i], i + 1
186 end
187 elseif #vons == 0 then
188 surnames[1] = firstnames[#firstnames]
189 firstnames[#firstnames] = nil
190 else
191
192 end
193 if #surnames == 0 then
194
195 firstnames = { }
196 vons = { }
197 surnames = { author }
198 else
199 initials = makeinitials(firstnames)
200 end
201 elseif n == 2 then
202
203
204 local words = lpegmatch(spacesplitter,split[1])
205 local i = 1
206 local n = #words
207 firstnames = { }
208 vons = { }
209 surnames = { }
210 while i <= n do
211 local w = words[i]
212 if is_upper(w) then
213 break
214 else
215 vons[#vons+1], i = w, i + 1
216 end
217 end
218 while i <= n do
219 surnames[#surnames+1] = words[i]
220 i = i + 1
221 end
222
223 local words = lpegmatch(spacesplitter,split[2])
224 local i = 1
225 local n = #words
226 while i <= n do
227 local w = words[i]
228 if is_upper(w) then
229 firstnames[#firstnames+1] = w
230 i = i + 1
231 else
232 break
233 end
234 end
235 while i <= n do
236 vons[#vons+1] = words[i]
237 i = i + 1
238 end
239 if surnames and firstnames and #surnames == 0 then
240
241 surnames[1] = firstnames[#firstnames]
242 firstnames[#firstnames] = nil
243 end
244 initials = makeinitials(firstnames)
245 elseif n == 3 then
246
247 surnames = lpegmatch(spacesplitter,split[1])
248 juniors = lpegmatch(spacesplitter,split[2])
249 firstnames = lpegmatch(spacesplitter,split[3])
250 initials = makeinitials(firstnames)
251 elseif n == 4 then
252
253 vons = lpegmatch(spacesplitter,split[1])
254 surnames = lpegmatch(spacesplitter,split[2])
255 juniors = lpegmatch(spacesplitter,split[3])
256 firstnames = lpegmatch(spacesplitter,split[4])
257 initials = makeinitials(firstnames)
258 elseif n >= 5 then
259
260
261 vons = lpegmatch(spacesplitter,split[1])
262 surnames = lpegmatch(spacesplitter,split[2])
263 juniors = lpegmatch(spacesplitter,split[3])
264 firstnames = lpegmatch(spacesplitter,split[4])
265 initials = lpegmatch(spacesplitter,split[5])
266 options = split[6]
267 if options then
268 options = lpegmatch(optionsplitter,options)
269 end
270 end
271 if firstnames and #firstnames > 0 then detail.firstnames = firstnames end
272 if vons and #vons > 0 then detail.vons = vons end
273 if surnames and #surnames > 0 then detail.surnames = surnames end
274 if initials and #initials > 0 then detail.initials = initials end
275 if juniors and #juniors > 0 then detail.juniors = juniors end
276 if options and next(options) then detail.options = options end
277 if not justsplit then
278 cache[author] = detail
279 nofhits = nofhits + 1
280 end
281 return detail
282end
283
284local function splitauthorstring(str)
285 if not str or str == "" then
286 return
287 end
288 nofused = nofused + 1
289
290 local remapped = authormap[str]
291 if remapped then
292 local detail = cache[remapped]
293 if detail then
294 cache[str] = detail
295 return { detail }
296 end
297 end
298
299 local authors = cache[str]
300 if authors then
301 return { authors }
302 end
303
304
305
306 local authors = lpegmatch(andsplitter,str) or { }
307 local nofauthors = #authors
308 for i=1,nofauthors do
309 authors[i] = splitauthor(authors[i])
310 end
311 if nofauthors > 1 and authors[nofauthors].original == "others" then
312
313 authors[nofauthors] = nil
314 authors.others = true
315 end
316 return authors
317end
318
319publications.splitoneauthor = splitauthor
320publications.splitauthor = splitauthorstring
321
322local function the_initials(initials,symbol,connector)
323 if not symbol then
324 symbol = "."
325 end
326 if not connector then
327 connector = "-"
328 end
329 local result = { }
330 local r = 0
331 for i=1,#initials do
332 local initial = initials[i]
333 if type(initial) == "table" then
334
335 local set = { }
336 local s = 0
337 for i=1,#initial do
338 if i > 1 then
339 s = s + 1 ; set[s] = connector
340 end
341 s = s + 1 ; set[s] = initial[i]
342 s = s + 1 ; set[s] = symbol
343 end
344 r = r + 1 ; result[r] = concat(set)
345 else
346
347 r = r + 1 ; result[r] = initial .. symbol
348 end
349 end
350 return result
351end
352
353local ctx_btxsetconcat = context.btxsetconcat
354local ctx_btxsetoverflow = context.btxsetoverflow
355local ctx_btxsetinitials = context.btxsetinitials
356local ctx_btxsetfirstnames = context.btxsetfirstnames
357local ctx_btxsetvons = context.btxsetvons
358local ctx_btxsetsurnames = context.btxsetsurnames
359local ctx_btxsetjuniors = context.btxsetjuniors
360local ctx_btxsetauthorvariant = context.btxsetauthorvariant
361
362local ctx_btxstartauthor = context.btxstartauthor
363local ctx_btxstopauthor = context.btxstopauthor
364
365local ctx_btxciteauthorsetup = context.btxciteauthorsetup
366local ctx_btxlistauthorsetup = context.btxlistauthorsetup
367
368local concatstate = publications.concatstate
369local f_invalid = formatters["<invalid %s: %s>"]
370
371local currentauthordata = nil
372local currentauthorsymbol = nil
373local currentauthorconnector = nil
374
375local manipulators = typesetters.manipulators
376local splitmanipulation = manipulators.splitspecification
377local applymanipulation = manipulators.applyspecification
378
379local function value(i,field)
380 if currentauthordata then
381 local entry = currentauthordata[i]
382 if entry then
383 local value = entry[field]
384 if value and #value > 0 then
385 return value
386 end
387 end
388 end
389end
390
391implement { name = "btxcurrentfirstnames", arguments = "integer", actions = function(i) local v = value(i,"firstnames") if v then context(concat(v," ")) end end }
392implement { name = "btxcurrentinitials", arguments = "integer", actions = function(i) local v = value(i,"initials") if v then context(concat(the_initials(v,currentauthorsymbol,currentauthorconnector))) end end }
393implement { name = "btxcurrentjuniors", arguments = "integer", actions = function(i) local v = value(i,"juniors") if v then context(concat(v," ")) end end }
394implement { name = "btxcurrentsurnames", arguments = "integer", actions = function(i) local v = value(i,"surnames") if v then context(concat(v," ")) end end }
395implement { name = "btxcurrentvons", arguments = "integer", actions = function(i) local v = value(i,"vons") if v then context(concat(v," ")) end end }
396
397local function btxauthorfield(i,field)
398 if currentauthordata then
399 local entry = currentauthordata[i]
400 if entry then
401 local manipulator, field = splitmanipulation(field)
402 local value = entry[field]
403 if not value or #value == 0 then
404
405 elseif manipulator then
406 for i=1,#value do
407 if i > 1 then
408 context(" ")
409 end
410 context(applymanipulation(manipulator,value) or value)
411 end
412 elseif field == "initials" then
413 context(concat(the_initials(value,currentauthorsymbol,currentauthorconnector)))
414 else
415 context(concat(value," "))
416 end
417 end
418 end
419end
420
421
422
423
424
425
426local function btxauthor(dataset,tag,field,settings)
427 local split, usedfield, kind = getcasted(dataset,tag,field)
428 if kind == "author" then
429 local max = split and #split or 0
430 if max == 0 then
431 return
432
433 end
434 local absmax = max
435 local etallimit = tonumber(settings.etallimit) or 1000
436 local etaldisplay = tonumber(settings.etaldisplay) or etallimit
437 local etaloption = settings_to_hash(settings.etaloption or "")
438 local etallast = etaloption[v_last]
439 local combiner = settings.combiner
440 local symbol = settings.symbol
441 local connector = settings.connector
442 local index = settings.index
443 if not combiner or combiner == "" then
444 combiner = "normal"
445 end
446 if not symbol then
447 symbol = "."
448 end
449 local ctx_btxsetup = settings.kind == "cite" and ctx_btxciteauthorsetup or ctx_btxlistauthorsetup
450 if max > etallimit and (etaldisplay+(etallast and 1 or 0)) < max then
451 max = etaldisplay
452 else
453 etallast = false
454 end
455 currentauthordata = split
456 currentauthorsymbol = symbol
457 currentauthorconnector = connector
458
459 local function oneauthor(i,last,justone)
460 local author = split[i]
461 if index then
462 ctx_btxstartauthor(i,1,0)
463 elseif last then
464 ctx_btxstartauthor(i,1,0)
465 ctx_btxsetconcat(0)
466 ctx_btxsetauthorvariant(combiner)
467 else
468 local state = author.state or 0
469 ctx_btxstartauthor(i,max,state)
470 ctx_btxsetconcat(concatstate(i,max))
471 ctx_btxsetauthorvariant(combiner)
472 end
473 local initials = author.initials
474 if initials and #initials > 0 then
475 ctx_btxsetinitials()
476 end
477 local firstnames = author.firstnames
478 if firstnames and #firstnames > 0 then
479 ctx_btxsetfirstnames()
480 end
481 local vons = author.vons
482 if vons and #vons > 0 then
483 ctx_btxsetvons()
484 end
485 local surnames = author.surnames
486 if surnames and #surnames > 0 then
487 ctx_btxsetsurnames()
488 end
489 local juniors = author.juniors
490 if juniors and #juniors > 0 then
491 ctx_btxsetjuniors()
492 end
493 if not index and i == max then
494 if split.others then
495 ctx_btxsetoverflow(1)
496 else
497 local overflow = #split - max
498 if overflow > 0 then
499 ctx_btxsetoverflow(overflow)
500 end
501 end
502 end
503 ctx_btxsetup(combiner)
504 ctx_btxstopauthor()
505 end
506
507 if index then
508 oneauthor(index)
509 elseif max == 1 then
510 oneauthor(1,false,true)
511 else
512 for i=1,max do
513 oneauthor(i)
514 end
515 if etallast then
516 oneauthor(absmax,true)
517 end
518 end
519
520 else
521 report("ignored field %a of tag %a, used field %a is no author",field,tag,usedfield)
522 end
523
524end
525
526implement {
527 name = "btxauthorfield",
528 actions = btxauthorfield,
529 arguments = { "integer", "string" }
530}
531
532implement {
533 name = "btxauthor",
534 actions = btxauthor,
535 arguments = {
536 "argument",
537 "argument",
538 "argument",
539 {
540 { "combiner" },
541 { "kind" },
542 { "etallimit" },
543 { "etaldisplay" },
544 { "etaloption" },
545 { "symbol" },
546 { "connector" },
547 }
548 }
549}
550
551local function components(snippet,short)
552 local vons = snippet.vons
553 local surnames = snippet.surnames
554 local initials = snippet.initials
555 local firstnames = not short and snippet.firstnames
556 local juniors = snippet.juniors
557 return
558 vons and #vons > 0 and concat(vons," ") or "",
559 surnames and #surnames > 0 and concat(surnames," ") or "",
560 initials and #initials > 0 and concat(the_initials(initials)," ") or "",
561 firstnames and #firstnames > 0 and concat(firstnames," ") or "",
562 juniors and #juniors > 0 and concat(juniors, " ") or ""
563end
564
565local collapsers = allocate { }
566
567publications.authorcollapsers = collapsers
568
569
570
571
572local function default(author)
573 local hash = author.hash
574 if hash then
575 return hash
576 end
577 local original = author.original
578 local vons = author.vons
579 local surnames = author.surnames
580 local initials = author.initials
581 local firstnames = author.firstnames
582 local juniors = author.juniors
583 local result = { }
584 local nofresult = 0
585 if vons and #vons > 0 then
586 for j=1,#vons do
587 nofresult = nofresult + 1
588 result[nofresult] = vons[j]
589 end
590 end
591 if surnames and #surnames > 0 then
592 for j=1,#surnames do
593 nofresult = nofresult + 1
594 result[nofresult] = surnames[j]
595 end
596 end
597 if initials and #initials > 0 then
598 initials = the_initials(initials)
599 for j=1,#initials do
600 nofresult = nofresult + 1
601 result[nofresult] = initials[j]
602 end
603 end
604 if firstnames and #firstnames > 0 then
605 for j=1,#firstnames do
606 nofresult = nofresult + 1
607 result[nofresult] = firstnames[j]
608 end
609 end
610 if juniors and #juniors > 0 then
611 for j=1,#juniors do
612 nofresult = nofresult + 1
613 result[nofresult] = juniors[j]
614 end
615 end
616 local hash = concat(result," ")
617 if trace_hashing then
618 report("hash: %s -> %s",original,hash)
619 end
620 author.hash = hash
621 return hash
622end
623
624local authorhashers = { }
625publications.authorhashers = authorhashers
626
627
628
629local function name(authors)
630 if type(authors) == "table" then
631 local n = #authors
632 if n == 0 then
633 return ""
634 end
635 local result = { }
636 local nofresult = 0
637 for i=1,n do
638 local author = authors[i]
639 local surnames = author.surnames
640 if surnames and #surnames > 0 then
641 for j=1,#surnames do
642 nofresult = nofresult + 1
643 result[nofresult] = surnames[j]
644 end
645 end
646 end
647 return concat(result," ")
648 else
649 return authors
650 end
651end
652
653table.setmetatableindex(authorhashers,function(t,k)
654 t[k] = name
655 return name
656end)
657
658authorhashers.normal = function(authors)
659 if type(authors) == "table" then
660 local n = #authors
661 if n == 0 then
662 return ""
663 end
664 local result = { }
665 local nofresult = 0
666 for i=1,n do
667 local author = authors[i]
668 local vons = author.vons
669 local surnames = author.surnames
670 local firstnames = author.firstnames
671 local juniors = author.juniors
672 if vons and #vons > 0 then
673 for j=1,#vons do
674 nofresult = nofresult + 1
675 result[nofresult] = vons[j]
676 end
677 end
678 if surnames and #surnames > 0 then
679 for j=1,#surnames do
680 nofresult = nofresult + 1
681 result[nofresult] = surnames[j]
682 end
683 end
684 if firstnames and #firstnames > 0 then
685 for j=1,#firstnames do
686 nofresult = nofresult + 1
687 result[nofresult] = firstnames[j]
688 end
689 end
690 if juniors and #juniors > 0 then
691 for j=1,#juniors do
692 nofresult = nofresult + 1
693 result[nofresult] = juniors[j]
694 end
695 end
696 end
697 return concat(result," ")
698 else
699 return authors
700 end
701end
702
703authorhashers.normalshort = function(authors)
704 if type(authors) == "table" then
705 local n = #authors
706 if n == 0 then
707 return ""
708 end
709 local result = { }
710 local nofresult = 0
711 for i=1,n do
712 local author = authors[i]
713 local vons = author.vons
714 local surnames = author.surnames
715 local initials = author.initials
716 local juniors = author.juniors
717 if vons and #vons > 0 then
718 for j=1,#vons do
719 nofresult = nofresult + 1
720 result[nofresult] = vons[j]
721 end
722 end
723 if surnames and #surnames > 0 then
724 for j=1,#surnames do
725 nofresult = nofresult + 1
726 result[nofresult] = surnames[j]
727 end
728 end
729 if initials and #initials > 0 then
730 initials = the_initials(initials)
731 for j=1,#initials do
732 nofresult = nofresult + 1
733 result[nofresult] = initials[j]
734 end
735 end
736 if juniors and #juniors > 0 then
737 for j=1,#juniors do
738 nofresult = nofresult + 1
739 result[nofresult] = juniors[j]
740 end
741 end
742 end
743 return concat(result," ")
744 else
745 return authors
746 end
747end
748
749local sequentialhash = function(authors)
750 if type(authors) == "table" then
751 local n = #authors
752 if n == 0 then
753 return ""
754 end
755 local result = { }
756 local nofresult = 0
757 for i=1,n do
758 local author = authors[i]
759 local vons = author.vons
760 local surnames = author.surnames
761 local firstnames = author.firstnames
762 local juniors = author.juniors
763 if firstnames and #firstnames > 0 then
764 for j=1,#firstnames do
765 nofresult = nofresult + 1
766 result[nofresult] = firstnames[j]
767 end
768 end
769 if vons and #vons > 0 then
770 for j=1,#vons do
771 nofresult = nofresult + 1
772 result[nofresult] = vons[j]
773 end
774 end
775 if surnames and #surnames > 0 then
776 for j=1,#surnames do
777 nofresult = nofresult + 1
778 result[nofresult] = surnames[j]
779 end
780 end
781 if juniors and #juniors > 0 then
782 for j=1,#juniors do
783 nofresult = nofresult + 1
784 result[nofresult] = juniors[j]
785 end
786 end
787 end
788 return concat(result," ")
789 else
790 return authors
791 end
792end
793
794local sequentialshorthash = function(authors)
795 if type(authors) == "table" then
796 local n = #authors
797 if n == 0 then
798 return ""
799 end
800 local result = { }
801 local nofresult = 0
802 for i=1,n do
803 local author = authors[i]
804 local vons = author.vons
805 local surnames = author.surnames
806 local initials = author.initials
807 local juniors = author.juniors
808 if initials and #initials > 0 then
809 initials = the_initials(initials)
810 for j=1,#initials do
811 nofresult = nofresult + 1
812 result[nofresult] = initials[j]
813 end
814 end
815 if vons and #vons > 0 then
816 for j=1,#vons do
817 nofresult = nofresult + 1
818 result[nofresult] = vons[j]
819 end
820 end
821 if surnames and #surnames > 0 then
822 for j=1,#surnames do
823 nofresult = nofresult + 1
824 result[nofresult] = surnames[j]
825 end
826 end
827 if juniors and #juniors > 0 then
828 for j=1,#juniors do
829 nofresult = nofresult + 1
830 result[nofresult] = juniors[j]
831 end
832 end
833 end
834 return concat(result," ")
835 else
836 return authors
837 end
838end
839
840authorhashers.sequential = sequentialhash
841authorhashers.sequentialshort = sequentialshorthash
842authorhashers.normalinverted = authorhashers.normal
843authorhashers.invertedshort = authorhashers.normalshort
844
845local p_clean = Cs ( (
846 P("\\btxcmd") / ""
847 + S("`~!@#$%^&*()_-+={}[]:;\"\'<>,.?/|\\") / ""
848 + lpeg.patterns.utf8character
849 )^1)
850
851
852
853authorhashers.short = function(authors)
854
855
856
857 if type(authors) == "table" then
858 local n = #authors
859 if n == 0 then
860 return "unk"
861 elseif n == 1 then
862 local surnames = authors[1].surnames
863 if not surnames or #surnames == 0 then
864 return "err"
865 else
866 local s = surnames[1]
867 local c = lpegmatch(p_clean,s)
868 if trace_hashing and s ~= c then
869 report_cite("name %a cleaned to %a for short construction",s,c)
870 end
871 return utfsub(c,1,3)
872 end
873 else
874 local t = { }
875 for i=1,n do
876 if i > 3 then
877 t[#t+1] = "+"
878 break
879 end
880 local surnames = authors[i].surnames
881 if not surnames or #surnames == 0 then
882 t[#t+1] = "?"
883 else
884 local s = surnames[1]
885 local c = lpegmatch(p_clean,s)
886 if s ~= c then
887 report_cite("name %a cleaned to %a for short construction",s,c)
888 end
889 t[#t+1] = utfsub(c,1,1)
890 end
891 end
892 return concat(t)
893 end
894 else
895 return utfsub(authors,1,3)
896 end
897end
898
899collapsers.default = default
900
901local function authorwriter(key,index)
902 if not key then
903 return ""
904 end
905 if type(key) == "string" then
906 return key
907 end
908 local n = #key
909 if n == 0 then
910 return ""
911 end
912 if index then
913 if not key[index] then
914 return ""
915 end
916 elseif n == 1 then
917 index = 1
918 end
919 if index then
920 local author = key[index]
921 local options = author.options
922 if options then
923 for option in next, options do
924 local collapse = collapsers[option]
925 if collapse then
926 return collapse(author)
927 end
928 end
929 end
930 local hash = default(author)
931
932
933
934 return hash
935 end
936 local t = { }
937 local s = 0
938 for i=1,n do
939 local author = key[i]
940 local options = author.options
941 s = s + 1
942 if options then
943 local done = false
944 for option in next, options do
945 local collapse = collapsers[option]
946 if collapse then
947 t[s] = collapse(author)
948 done = true
949 end
950 end
951 if not done then
952 t[s] = default(author)
953 end
954 else
955 t[s] = default(author)
956 end
957 end
958 local hash = concat(t," & ")
959
960
961
962 return hash
963end
964
965local function writer(key)
966 return authorwriter(key)
967end
968
969publications.writers .author = writer
970publications.casters .author = splitauthorstring
971publications.components.author = components
972
973
974
975
976
977
978
979
980
981
982
983
984publications.sortmethods.authoryear = {
985 sequence = {
986
987 { field = "author", default = "", unknown = "" },
988 { field = "year", default = "9998", unknown = "9999" },
989
990 { field = "month", default = "13", unknown = "14" },
991 { field = "day", default = "32", unknown = "33" },
992 { field = "journal", default = "", unknown = "" },
993 { field = "volume", default = "", unknown = "" },
994
995 { field = "pages", default = "", unknown = "" },
996 { field = "title", default = "", unknown = "" },
997 { field = "index", default = "", unknown = "" },
998 },
999}
1000
1001publications.sortmethods.authortitle = {
1002 sequence = {
1003 { field = "author", default = "", unknown = "" },
1004 { field = "title", default = "", unknown = "" },
1005 { field = "booktitle", default = "", unknown = "" },
1006 { field = "maintitle", default = "", unknown = "" },
1007 { field = "volume", default = "", unknown = "" },
1008 { field = "part", default = "", unknown = "" },
1009 { field = "date", default = "9998-13-32", unknown = "9999-14-33" },
1010 { field = "year", default = "9998", unknown = "9999" },
1011 { field = "month", default = "13", unknown = "14" },
1012 { field = "day", default = "32", unknown = "33" },
1013 { field = "index", default = "", unknown = "" },
1014 },
1015}
1016
1017implement {
1018 name = "btxremapauthor",
1019 arguments = "2 strings",
1020 actions = function(k,v)
1021 local a = { splitauthor(k,true) }
1022 local s1 = sequentialhash(a)
1023 local s2 = sequentialshorthash(a)
1024 if not authormap[k] then
1025 authormap[k] = v
1026 report("%a mapped onto %a",k,v)
1027 end
1028 if not authormap[s1] then
1029 authormap[s1] = v
1030 report("%a mapped onto %a, derived from %a",s1,v,k)
1031 end
1032 if not authormap[s2] then
1033 authormap[s2] = v
1034 report("%a mapped onto %a, derived from %a",s2,v,k)
1035 end
1036 end
1037}
1038
1039implement {
1040 name = "btxshowauthorremapping",
1041 actions = function(k,v)
1042 report("start author remapping")
1043 for k, v in sortedhash(authormap) do
1044 report(" %s => %s",k,v)
1045 end
1046 report("stop author remapping")
1047 end
1048}
1049 |