]> git.lyx.org Git - lyx.git/blob - src/BiblioInfo.cpp
Avoid row breaking at inconvenient places.
[lyx.git] / src / BiblioInfo.cpp
1 /**
2  * \file BiblioInfo.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  * \author Herbert Voß
8  * \author Richard Kimberly Heck
9  * \author Julien Rioux
10  * \author Jürgen Spitzmüller
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "BiblioInfo.h"
18
19 #include "Buffer.h"
20 #include "BufferParams.h"
21 #include "Citation.h"
22 #include "Encoding.h"
23 #include "Language.h"
24 #include "TextClass.h"
25 #include "TocBackend.h"
26 #include "xml.h"
27
28 #include "support/convert.h"
29 #include "support/debug.h"
30 #include "support/docstream.h"
31 #include "support/FileName.h"
32 #include "support/gettext.h"
33 #include "support/lassert.h"
34 #include "support/lstrings.h"
35 #include "support/textutils.h"
36
37 #include <map>
38 #include <regex>
39 #include <set>
40
41 using namespace std;
42 using namespace lyx::support;
43
44
45 namespace lyx {
46
47 namespace {
48
49 // Remove placeholders from names
50 docstring renormalize(docstring const & input)
51 {
52         docstring res = subst(input, from_ascii("$$space!"), from_ascii(" "));
53         return subst(res, from_ascii("$$comma!"), from_ascii(","));
54 }
55
56
57 // Split the surname into prefix ("von-part") and family name
58 pair<docstring, docstring> parseSurname(docstring const & sname)
59 {
60         // Split the surname into its tokens
61         vector<docstring> pieces = getVectorFromString(sname, from_ascii(" "));
62         if (pieces.size() < 2)
63                 return make_pair(docstring(), sname);
64
65         // Now we look for pieces that begin with a lower case letter.
66         // All except for the very last token constitute the "von-part".
67         docstring prefix;
68         vector<docstring>::const_iterator it = pieces.begin();
69         vector<docstring>::const_iterator const en = pieces.end();
70         bool first = true;
71         for (; it != en; ++it) {
72                 if ((*it).empty())
73                         continue;
74                 // If this is the last piece, then what we now have is
75                 // the family name, notwithstanding the casing.
76                 if (it + 1 == en)
77                         break;
78                 char_type const c = (*it)[0];
79                 // If the piece starts with a upper case char, we assume
80                 // this is part of the surname.
81                 if (!isLower(c))
82                         break;
83                 // Nothing of the former, so add this piece to the prename
84                 if (!first)
85                         prefix += " ";
86                 else
87                         first = false;
88                 prefix += *it;
89         }
90
91         // Reconstruct the family name.
92         // Note that if we left the loop with because it + 1 == en,
93         // then this will still do the right thing, i.e., make surname
94         // just be the last piece.
95         docstring surname;
96         first = true;
97         for (; it != en; ++it) {
98                 if (!first)
99                         surname += " ";
100                 else
101                         first = false;
102                 surname += *it;
103         }
104         return make_pair(prefix, surname);
105 }
106
107
108 struct name_parts {
109         docstring surname;
110         docstring prename;
111         docstring suffix;
112         docstring prefix;
113 };
114
115
116 // gets the name parts (prename, surname, prefix, suffix) from an author-type string
117 name_parts nameParts(docstring const & iname)
118 {
119         name_parts res;
120         if (iname.empty())
121                 return res;
122
123         // First we check for goupings (via {...}) and replace blanks and
124         // commas inside groups with temporary placeholders
125         docstring name;
126         int gl = 0;
127         docstring::const_iterator p = iname.begin();
128         while (p != iname.end()) {
129                 // count grouping level
130                 if (*p == '{')
131                         ++gl;
132                 else if (*p == '}')
133                         --gl;
134                 // generate string with probable placeholders
135                 if (*p == ' ' && gl > 0)
136                         name += from_ascii("$$space!");
137                 else if (*p == ',' && gl > 0)
138                         name += from_ascii("$$comma!");
139                 else
140                         name += *p;
141                 ++p;
142         }
143
144         // Now we look for a comma, and take the last name to be everything
145         // preceding the right-most one, so that we also get the name suffix
146         // (aka "jr" part).
147         vector<docstring> pieces = getVectorFromString(name);
148         if (pieces.size() > 1) {
149                 // Whether we have a name suffix or not, the prename is
150                 // always last item
151                 res.prename = renormalize(pieces.back());
152                 // The family name, conversely, is always the first item.
153                 // However, it might contain a prefix (aka "von" part)
154                 docstring const sname = pieces.front();
155                 res.prefix = renormalize(parseSurname(sname).first);
156                 res.surname = renormalize(parseSurname(sname).second);
157                 // If we have three pieces (the maximum allowed by BibTeX),
158                 // the second one is the name suffix.
159                 if (pieces.size() > 2)
160                         res.suffix = renormalize(pieces.at(1));
161                 return res;
162         }
163
164         // OK, so now we want to look for the last name.
165         // Split on spaces, to get various tokens.
166         pieces = getVectorFromString(name, from_ascii(" "));
167         // No space: Only a family name given
168         if (pieces.size() < 2) {
169                 res.surname = renormalize(pieces.back());
170                 return res;
171         }
172         // If we get two pieces, assume "prename surname"
173         if (pieces.size() == 2) {
174                 res.prename = renormalize(pieces.front());
175                 res.surname = renormalize(pieces.back());
176                 return res;
177         }
178
179         // More than 3 pieces: A name prefix (aka "von" part) might be included.
180         // We look for the first piece that begins with a lower case letter
181         // (which is the name prefix, if it is not the last token) or the last token.
182         docstring prename;
183         vector<docstring>::const_iterator it = pieces.begin();
184         vector<docstring>::const_iterator const en = pieces.end();
185         bool first = true;
186         for (; it != en; ++it) {
187                 if ((*it).empty())
188                         continue;
189                 char_type const c = (*it)[0];
190                 // If the piece starts with a lower case char, we assume
191                 // this is the name prefix and thus prename is complete.
192                 if (isLower(c))
193                         break;
194                 // Same if this is the last piece, which is always the surname.
195                 if (it + 1 == en)
196                         break;
197                 // Nothing of the former, so add this piece to the prename
198                 if (!first)
199                         prename += " ";
200                 else
201                         first = false;
202                 prename += *it;
203         }
204
205         // Now reconstruct the family name and strip the prefix.
206         // Note that if we left the loop because it + 1 == en,
207         // then this will still do the right thing, i.e., make surname
208         // just be the last piece.
209         docstring surname;
210         first = true;
211         for (; it != en; ++it) {
212                 if (!first)
213                         surname += " ";
214                 else
215                         first = false;
216                 surname += *it;
217         }
218         res.prename = renormalize(prename);
219         res.prefix = renormalize(parseSurname(surname).first);
220         res.surname = renormalize(parseSurname(surname).second);
221         return res;
222 }
223
224
225 docstring constructName(docstring const & name, string const & scheme)
226 {
227         // re-constructs a name from name parts according
228         // to a given scheme
229         docstring const prename = nameParts(name).prename;
230         docstring const surname = nameParts(name).surname;
231         docstring const prefix = nameParts(name).prefix;
232         docstring const suffix = nameParts(name).suffix;
233         string res = scheme;
234         static regex const reg1("(.*)(\\{%prename%\\[\\[)([^\\]]+)(\\]\\]\\})(.*)");
235         static regex const reg2("(.*)(\\{%suffix%\\[\\[)([^\\]]+)(\\]\\]\\})(.*)");
236         static regex const reg3("(.*)(\\{%prefix%\\[\\[)([^\\]]+)(\\]\\]\\})(.*)");
237         smatch sub;
238         // Changing the first parameter of regex_match() may corrupt the
239         // second one. In this case we use the temporary string tmp.
240         if (regex_match(scheme, sub, reg1)) {
241                 res = sub.str(1);
242                 if (!prename.empty())
243                         res += sub.str(3);
244                 res += sub.str(5);
245         }
246         if (regex_match(res, sub, reg2)) {
247                 string tmp = sub.str(1);
248                 if (!suffix.empty())
249                         tmp += sub.str(3);
250                 res = tmp + sub.str(5);
251         }
252         if (regex_match(res, sub, reg3)) {
253                 string tmp = sub.str(1);
254                 if (!prefix.empty())
255                         tmp += sub.str(3);
256                 res = tmp + sub.str(5);
257         }
258         docstring result = from_ascii(res);
259         result = subst(result, from_ascii("%prename%"), prename);
260         result = subst(result, from_ascii("%surname%"), surname);
261         result = subst(result, from_ascii("%prefix%"), prefix);
262         result = subst(result, from_ascii("%suffix%"), suffix);
263         return result;
264 }
265
266
267 vector<docstring> const getAuthors(docstring const & author)
268 {
269         // We check for goupings (via {...}) and only consider " and "
270         // outside groups as author separator. This is to account
271         // for cases such as {{Barnes and Noble, Inc.}}, which
272         // need to be treated as one single family name.
273         // We use temporary placeholders in order to differentiate the
274         // diverse " and " cases.
275
276         // First, we temporarily replace all ampersands. It is rather unusual
277         // in author names, but can happen (consider cases such as "C \& A Corp.").
278         docstring iname = subst(author, from_ascii("&"), from_ascii("$$amp!"));
279         // Then, we temporarily make all " and " strings to ampersands in order
280         // to handle them later on a per-char level. Note that arbitrary casing
281         // ("And", "AND", "aNd", ...) is allowed in bibtex (#10465).
282         static regex const and_reg("(.* )([aA][nN][dD])( .*)");
283         smatch sub;
284         string res = to_utf8(iname);
285         while (regex_match(res, sub, and_reg))
286                 res = sub.str(1) + "&" + sub.str(3);
287         iname = from_utf8(res);
288         // Now we traverse through the string and replace the "&" by the proper
289         // output in- and outside groups
290         docstring name;
291         int gl = 0;
292         docstring::const_iterator p = iname.begin();
293         while (p != iname.end()) {
294                 // count grouping level
295                 if (*p == '{')
296                         ++gl;
297                 else if (*p == '}')
298                         --gl;
299                 // generate string with probable placeholders
300                 if (*p == '&') {
301                         if (gl > 0)
302                                 // Inside groups, we output "and"
303                                 name += from_ascii("and");
304                         else
305                                 // Outside groups, we output a separator
306                                 name += from_ascii("$$namesep!");
307                 }
308                 else
309                         name += *p;
310                 ++p;
311         }
312
313         // re-insert the literal ampersands
314         name = subst(name, from_ascii("$$amp!"), from_ascii("&"));
315
316         // Now construct the actual vector
317         return getVectorFromString(name, from_ascii(" $$namesep! "));
318 }
319
320
321 bool multipleAuthors(docstring const & author)
322 {
323         return getAuthors(author).size() > 1;
324 }
325
326
327 // converts a string containing LaTeX commands into unicode
328 // for display.
329 docstring convertLaTeXCommands(docstring const & str)
330 {
331         docstring val = str;
332         docstring ret;
333
334         bool scanning_cmd = false;
335         bool scanning_math = false;
336         bool is_section = false;
337         bool escaped = false; // used to catch \$, etc.
338         while (!val.empty()) {
339                 char_type const ch = val[0];
340
341                 // if we're scanning math, we output everything until we
342                 // find an unescaped $, at which point we break out.
343                 if (scanning_math) {
344                         if (escaped)
345                                 escaped = false;
346                         else if (ch == '\\')
347                                 escaped = true;
348                         else if (ch == '$')
349                                 scanning_math = false;
350                         ret += ch;
351                         val = val.substr(1);
352                         continue;
353                 }
354
355                 // if we're scanning a command name, then we just
356                 // discard characters until we hit something that
357                 // isn't alpha.
358                 if (scanning_cmd) {
359                         if (!is_section && ch == 'S') {
360                                 is_section = true;
361                                 val = val.substr(1);
362                                 continue;
363                         }
364                         if (isAlphaASCII(ch)) {
365                                 is_section = false;
366                                 val = val.substr(1);
367                                 escaped = false;
368                                 continue;
369                         } else if (is_section) {
370                                 ret.push_back(0x00a7);
371                                 is_section = false;
372                                 continue;
373                         }
374                         // so we're done with this command.
375                         // now we fall through and check this character.
376                         is_section = false;
377                         scanning_cmd = false;
378                 }
379
380                 // was the last character a \? If so, then this is something like:
381                 // \\ or \$, so we'll just output it. That's probably not always right...
382                 if (escaped) {
383                         // exception: output \, as THIN SPACE
384                         if (ch == ',')
385                                 ret.push_back(0x2009);
386                         else
387                                 ret += ch;
388                         val = val.substr(1);
389                         escaped = false;
390                         continue;
391                 }
392
393                 if (ch == '~') {
394                         ret += char_type(0x00a0);
395                         val = val.substr(1);
396                         continue;
397                 }
398
399                 if (ch == '$') {
400                         ret += ch;
401                         val = val.substr(1);
402                         scanning_math = true;
403                         continue;
404                 }
405
406                 // Change text mode accents in the form
407                 // {\v a} to \v{a} (see #9340).
408                 // FIXME: This is a sort of mini-tex2lyx.
409                 //        Use the real tex2lyx instead!
410                 static regex const tma_reg("^\\{\\\\[bcCdfGhHkrtuUv]\\s\\w\\}");
411                 if (regex_search(to_utf8(val), tma_reg)) {
412                         val = val.substr(1);
413                         val.replace(2, 1, from_ascii("{"));
414                         continue;
415                 }
416
417                 // Apart from the above, we just ignore braces
418                 if (ch == '{' || ch == '}') {
419                         val = val.substr(1);
420                         continue;
421                 }
422
423                 // we're going to check things that look like commands, so if
424                 // this doesn't, just output it.
425                 if (ch != '\\') {
426                         ret += ch;
427                         val = val.substr(1);
428                         continue;
429                 }
430
431                 // ok, could be a command of some sort
432                 // let's see if it corresponds to some unicode
433                 // unicodesymbols has things in the form: \"{u},
434                 // whereas we may see things like: \"u. So we'll
435                 // look for that and change it, if necessary.
436                 // FIXME: This is a sort of mini-tex2lyx.
437                 //        Use the real tex2lyx instead!
438                 static regex const reg("^\\\\\\W\\w");
439                 if (regex_search(to_utf8(val), reg)) {
440                         val.insert(3, from_ascii("}"));
441                         val.insert(2, from_ascii("{"));
442                 }
443                 bool termination;
444                 docstring rem;
445                 docstring const cnvtd = Encodings::fromLaTeXCommand(val,
446                                 Encodings::TEXT_CMD, termination, rem);
447                 if (!cnvtd.empty()) {
448                         // it did, so we'll take that bit and proceed with what's left
449                         ret += cnvtd;
450                         val = rem;
451                         continue;
452                 }
453                 // it's a command of some sort
454                 scanning_cmd = true;
455                 escaped = true;
456                 val = val.substr(1);
457         }
458         return ret;
459 }
460
461
462 // Escape '<' and '>' and remove richtext markers (e.g. {!this is richtext!}) from a string.
463 docstring processRichtext(docstring const & str, bool richtext)
464 {
465         docstring val = str;
466         docstring ret;
467
468         bool scanning_rich = false;
469         while (!val.empty()) {
470                 char_type const ch = val[0];
471                 if (ch == '{' && val.size() > 1 && val[1] == '!') {
472                         // beginning of rich text
473                         scanning_rich = true;
474                         val = val.substr(2);
475                         continue;
476                 }
477                 if (scanning_rich && ch == '!' && val.size() > 1 && val[1] == '}') {
478                         // end of rich text
479                         scanning_rich = false;
480                         val = val.substr(2);
481                         continue;
482                 }
483                 if (richtext) {
484                         if (scanning_rich)
485                                 ret += ch;
486                         else {
487                                 // we need to escape '<' and '>'
488                                 if (ch == '<')
489                                         ret += "&lt;";
490                                 else if (ch == '>')
491                                         ret += "&gt;";
492                                 else
493                                         ret += ch;
494                         }
495                 } else if (!scanning_rich /* && !richtext */)
496                         ret += ch;
497                 // else the character is discarded, which will happen only if
498                 // richtext == false and we are scanning rich text
499                 val = val.substr(1);
500         }
501         return ret;
502 }
503
504 } // namespace
505
506
507 //////////////////////////////////////////////////////////////////////
508 //
509 // BibTeXInfo
510 //
511 //////////////////////////////////////////////////////////////////////
512
513 BibTeXInfo::BibTeXInfo(docstring const & key, docstring const & type)
514         : is_bibtex_(true), bib_key_(key), num_bib_key_(0), entry_type_(type),
515           info_(), format_(), modifier_(0)
516 {}
517
518
519
520 docstring const BibTeXInfo::getAuthorOrEditorList(Buffer const * buf,
521                                           bool full, bool forceshort) const
522 {
523         docstring author = operator[]("author");
524         if (author.empty())
525                 author = operator[]("editor");
526
527         return getAuthorList(buf, author, full, forceshort);
528 }
529
530
531 docstring const BibTeXInfo::getAuthorList(Buffer const * buf,
532                 docstring const & author, bool const full, bool const forceshort,
533                 bool const allnames, bool const beginning) const
534 {
535         // Maxnames treshold depend on engine
536         size_t maxnames = buf ?
537                 buf->params().documentClass().max_citenames() : 2;
538
539         if (!is_bibtex_) {
540                 docstring const opt = label();
541                 if (opt.empty())
542                         return docstring();
543
544                 docstring authors;
545                 docstring const remainder = trim(split(opt, authors, '('));
546                 if (remainder.empty())
547                         // in this case, we didn't find a "(",
548                         // so we don't have author (year)
549                         return docstring();
550                 if (full) {
551                         // Natbib syntax is "Jones et al.(1990)Jones, Baker, and Williams"
552                         docstring const fullauthors = trim(rsplit(remainder, ')'));
553                         if (!fullauthors.empty())
554                                 return fullauthors;
555                 }
556                 return authors;
557         }
558
559         if (author.empty())
560                 return author;
561
562         // OK, we've got some names. Let's format them.
563         // Try to split the author list
564         vector<docstring> const authors = getAuthors(author);
565
566         docstring retval;
567
568         CiteEngineType const engine_type = buf ? buf->params().citeEngineType()
569                                                : ENGINE_TYPE_DEFAULT;
570
571         // These are defined in the styles
572         string const etal =
573                 buf ? buf->params().documentClass().getCiteMacro(engine_type, "B_etal")
574                     : " et al.";
575         string const namesep =
576                 buf ? buf->params().documentClass().getCiteMacro(engine_type, "B_namesep")
577                    : ", ";
578         string const lastnamesep =
579                 buf ? buf->params().documentClass().getCiteMacro(engine_type, "B_lastnamesep")
580                     : ", and ";
581         string const pairnamesep =
582                 buf ? buf->params().documentClass().getCiteMacro(engine_type, "B_pairnamesep")
583                      : " and ";
584         string firstnameform =
585                         buf ? buf->params().documentClass().getCiteMacro(engine_type, "!firstnameform")
586                              : "{%prefix%[[%prefix% ]]}%surname%{%suffix%[[, %suffix%]]}{%prename%[[, %prename%]]}";
587         if (!beginning)
588                 firstnameform = buf ? buf->params().documentClass().getCiteMacro(engine_type, "!firstbynameform")
589                                              : "%prename% {%prefix%[[%prefix% ]]}%surname%{%suffix%[[, %suffix%]]}";
590         string othernameform = buf ? buf->params().documentClass().getCiteMacro(engine_type, "!othernameform")
591                              : "{%prefix%[[%prefix% ]]}%surname%{%suffix%[[, %suffix%]]}{%prename%[[, %prename%]]}";
592         if (!beginning)
593                 othernameform = buf ? buf->params().documentClass().getCiteMacro(engine_type, "!otherbynameform")
594                                              : "%prename% {%prefix%[[%prefix% ]]}%surname%{%suffix%[[, %suffix%]]}";
595         string citenameform = buf ? buf->params().documentClass().getCiteMacro(engine_type, "!citenameform")
596                              : "{%prefix%[[%prefix% ]]}%surname%";
597
598         // Shorten the list (with et al.) if forceshort is set
599         // and the list can actually be shortened, else if maxcitenames
600         // is passed and full is not set.
601         bool shorten = forceshort && authors.size() > 1;
602         vector<docstring>::const_iterator it = authors.begin();
603         vector<docstring>::const_iterator en = authors.end();
604         for (size_t i = 0; it != en; ++it, ++i) {
605                 if (i >= maxnames && !full) {
606                         shorten = true;
607                         break;
608                 }
609                 if (*it == "others") {
610                         retval += buf ? buf->B_(etal) : from_ascii(etal);
611                         break;
612                 }
613                 if (i > 0 && i == authors.size() - 1) {
614                         if (authors.size() == 2)
615                                 retval += buf ? buf->B_(pairnamesep) : from_ascii(pairnamesep);
616                         else
617                                 retval += buf ? buf->B_(lastnamesep) : from_ascii(lastnamesep);
618                 } else if (i > 0)
619                         retval += buf ? buf->B_(namesep) : from_ascii(namesep);
620                 if (allnames)
621                         retval += (i == 0) ? constructName(*it, firstnameform)
622                                 : constructName(*it, othernameform);
623                 else
624                         retval += constructName(*it, citenameform);
625         }
626         if (shorten) {
627                 if (allnames)
628                         retval = constructName(authors[0], firstnameform) + (buf ? buf->B_(etal) : from_ascii(etal));
629                 else
630                         retval = constructName(authors[0], citenameform) + (buf ? buf->B_(etal) : from_ascii(etal));
631         }
632
633         return convertLaTeXCommands(retval);
634 }
635
636
637 docstring const BibTeXInfo::getYear() const
638 {
639         if (is_bibtex_) {
640                 // first try legacy year field
641                 docstring year = operator[]("year");
642                 if (!year.empty())
643                         return year;
644                 // now try biblatex's date field
645                 year = operator[]("date");
646                 // Format is [-]YYYY-MM-DD*/[-]YYYY-MM-DD*
647                 // We only want the years.
648                 static regex const yreg("[-]?([\\d]{4}).*");
649                 static regex const ereg(".*/[-]?([\\d]{4}).*");
650                 smatch sm;
651                 string const date = to_utf8(year);
652                 if (!regex_match(date, sm, yreg))
653                         // cannot parse year.
654                         return docstring();
655                 year = from_ascii(sm[1]);
656                 // check for an endyear
657                 if (regex_match(date, sm, ereg))
658                         year += char_type(0x2013) + from_ascii(sm[1]);
659                 return year;
660         }
661
662         docstring const opt = label();
663         if (opt.empty())
664                 return docstring();
665
666         docstring authors;
667         docstring tmp = split(opt, authors, '(');
668         if (tmp.empty())
669                 // we don't have author (year)
670                 return docstring();
671         docstring year;
672         tmp = split(tmp, year, ')');
673         return year;
674 }
675
676
677 void BibTeXInfo::getLocators(docstring & doi, docstring & url, docstring & file) const
678 {
679         if (is_bibtex_) {
680                 // get "doi" entry from citation record
681                 doi = operator[]("doi");
682                 if (!doi.empty() && !prefixIs(doi,from_ascii("http")))
683                         doi = "https://doi.org/" + doi;
684                 // get "url" entry from citation record
685                 url = operator[]("url");
686                 // get "file" entry from citation record
687                 file = operator[]("file");
688
689                 // Jabref case, "file" field has a format (depending on exporter):
690                 // Description:Location:Filetype;Description:Location:Filetype...
691                 // or simply:
692                 // Location;Location;...
693                 // We will strip out the locations and return an \n-separated list
694                 if (!file.empty()) {
695                         docstring filelist;
696                         vector<docstring> files = getVectorFromString(file, from_ascii(";"));
697                         for (auto const & f : files) {
698                                 // first try if we have Description:Location:Filetype
699                                 docstring ret, filedest, tmp;
700                                 ret = split(f, tmp, ':');
701                                 tmp = split(ret, filedest, ':');
702                                 if (filedest.empty())
703                                         // we haven't, so use the whole string
704                                         filedest = f;
705                                 // TODO howto deal with relative directories?
706                                 FileName fn(to_utf8(filedest));
707                                 if (fn.exists()) {
708                                         if (!filelist.empty())
709                                                 filelist += '\n';
710                                         filelist += "file:///" + filedest;
711                                 }
712                         }
713                         if (!filelist.empty())
714                                 file = filelist;
715                 }
716
717                 // kbibtex case, "localfile" field with format:
718                 // file1.pdf;file2.pdf
719                 // We will strip out the locations and return an \n-separated list
720                 docstring kfile;
721                 if (file.empty())
722                         kfile = operator[]("localfile");
723                 if (!kfile.empty()) {
724                         docstring filelist;
725                         vector<docstring> files = getVectorFromString(kfile, from_ascii(";"));
726                         for (auto const & f : files) {
727                                 // TODO howto deal with relative directories?
728                                 FileName fn(to_utf8(f));
729                                 if (fn.exists()) {
730                                         if (!filelist.empty())
731                                                 filelist += '\n';
732                                         filelist = "file:///" + f;
733                                 }
734                         }
735                         if (!filelist.empty())
736                                 file = filelist;
737                 }
738
739                 if (!url.empty())
740                         return;
741
742                 // try biblatex specific fields, see its manual
743                 // 3.13.7 "Electronic Publishing Informationl"
744                 docstring eprinttype = operator[]("eprinttype");
745                 docstring eprint = operator[]("eprint");
746                 if (eprint.empty())
747                         return;
748
749                 if (eprinttype == "arxiv")
750                         url = "https://arxiv.org/abs/" + eprint;
751                 if (eprinttype == "jstor")
752                         url = "https://www.jstor.org/stable/" + eprint;
753                 if (eprinttype == "pubmed")
754                         url = "http://www.ncbi.nlm.nih.gov/pubmed/" + eprint;
755                 if (eprinttype == "hdl")
756                         url = "https://hdl.handle.net/" + eprint;
757                 if (eprinttype == "googlebooks")
758                         url = "http://books.google.com/books?id=" + eprint;
759
760                 return;
761         }
762
763         // Here can be handled the bibliography environment. All one could do
764         // here is let LyX scan the entry for URL or HRef insets.
765 }
766
767
768 namespace {
769
770 docstring parseOptions(docstring const & format, string & optkey,
771                     docstring & ifpart, docstring & elsepart);
772
773 // Calls parseOptions to deal with an embedded option, such as:
774 //   {%number%[[, no.~%number%]]}
775 // which must appear at the start of format. ifelsepart gets the
776 // whole of the option, and we return what's left after the option.
777 // we return format if there is an error.
778 docstring parseEmbeddedOption(docstring const & format, docstring & ifelsepart)
779 {
780         LASSERT(format[0] == '{' && format[1] == '%', return format);
781         string optkey;
782         docstring ifpart;
783         docstring elsepart;
784         docstring const rest = parseOptions(format, optkey, ifpart, elsepart);
785         if (format == rest) { // parse error
786                 LYXERR0("ERROR! Couldn't parse `" << format <<"'.");
787                 return format;
788         }
789         LASSERT(rest.size() <= format.size(),
790                 { ifelsepart = docstring(); return format; });
791         ifelsepart = format.substr(0, format.size() - rest.size());
792         return rest;
793 }
794
795
796 // Gets a "clause" from a format string, where the clause is
797 // delimited by '[[' and ']]'. Returns what is left after the
798 // clause is removed, and returns format if there is an error.
799 docstring getClause(docstring const & format, docstring & clause)
800 {
801         docstring fmt = format;
802         // remove '[['
803         fmt = fmt.substr(2);
804         // we'll remove characters from the front of fmt as we
805         // deal with them
806         while (!fmt.empty()) {
807                 if (fmt[0] == ']' && fmt.size() > 1 && fmt[1] == ']') {
808                         // that's the end
809                         fmt = fmt.substr(2);
810                         break;
811                 }
812                 // check for an embedded option
813                 if (fmt[0] == '{' && fmt.size() > 1 && fmt[1] == '%') {
814                         docstring part;
815                         docstring const rest = parseEmbeddedOption(fmt, part);
816                         if (fmt == rest) {
817                                 LYXERR0("ERROR! Couldn't parse embedded option in `" << format <<"'.");
818                                 return format;
819                         }
820                         clause += part;
821                         fmt = rest;
822                 } else { // it's just a normal character
823                                 clause += fmt[0];
824                                 fmt = fmt.substr(1);
825                 }
826         }
827         return fmt;
828 }
829
830
831 // parse an options string, which must appear at the start of the
832 // format parameter. puts the parsed bits in optkey, ifpart, and
833 // elsepart and returns what's left after the option is removed.
834 // if there's an error, it returns format itself.
835 docstring parseOptions(docstring const & format, string & optkey,
836                     docstring & ifpart, docstring & elsepart)
837 {
838         LASSERT(format[0] == '{' && format[1] == '%', return format);
839         // strip '{%'
840         docstring fmt = format.substr(2);
841         size_t pos = fmt.find('%'); // end of key
842         if (pos == string::npos) {
843                 LYXERR0("Error parsing  `" << format <<"'. Can't find end of key.");
844                 return format;
845         }
846         optkey = to_utf8(fmt.substr(0, pos));
847         fmt = fmt.substr(pos + 1);
848         // [[format]] should be next
849         if (fmt[0] != '[' || fmt[1] != '[') {
850                 LYXERR0("Error parsing  `" << format <<"'. Can't find '[[' after key.");
851                 return format;
852         }
853
854         docstring curfmt = fmt;
855         fmt = getClause(curfmt, ifpart);
856         if (fmt == curfmt) {
857                 LYXERR0("Error parsing  `" << format <<"'. Couldn't get if clause.");
858                 return format;
859         }
860
861         if (fmt[0] == '}') // we're done, no else clause
862                 return fmt.substr(1);
863
864         // else part should follow
865         if (fmt[0] != '[' || fmt[1] != '[') {
866                 LYXERR0("Error parsing  `" << format <<"'. Can't find else clause.");
867                 return format;
868         }
869
870         curfmt = fmt;
871         fmt = getClause(curfmt, elsepart);
872         // we should be done
873         if (fmt == curfmt || fmt[0] != '}') {
874                 LYXERR0("Error parsing  `" << format <<"'. Can't find end of option.");
875                 return format;
876         }
877         return fmt.substr(1);
878 }
879
880
881 } // namespace
882
883 /* FIXME
884 Bug #9131 revealed an oddity in how we are generating citation information
885 when more than one key is given. We end up building a longer and longer format
886 string as we go, which we then have to re-parse, over and over and over again,
887 rather than generating the information for the individual keys and then putting
888 all of that together. We do that to deal with the way separators work, from what
889 I can tell, but it still feels like a hack. Fixing this would require quite a
890 bit of work, however.
891 */
892 docstring BibTeXInfo::expandFormat(docstring const & format,
893                 BibTeXInfoList const & xrefs, int & counter, Buffer const & buf,
894                 CiteItem const & ci, bool next, bool second) const
895 {
896         // incorrect use of macros could put us in an infinite loop
897         static int const max_passes = 5000;
898         // the use of overly large keys can lead to performance problems, due
899         // to eventual attempts to convert LaTeX macros to unicode. See bug
900         // #8944. By default, the size is limited to 128 (in CiteItem), but
901         // for specific purposes (such as XHTML export), it needs to be enlarged
902         // This is perhaps not the best solution, but it will have to do for now.
903         size_t const max_keysize = ci.max_key_size;
904         odocstringstream ret; // return value
905         string key;
906         bool scanning_key = false;
907         bool scanning_rich = false;
908
909         CiteEngineType const engine_type = buf.params().citeEngineType();
910         docstring fmt = format;
911         // we'll remove characters from the front of fmt as we
912         // deal with them
913         while (!fmt.empty()) {
914                 if (counter > max_passes) {
915                         LYXERR0("Recursion limit reached while parsing `"
916                                 << format << "'.");
917                         return _("ERROR!");
918                 }
919
920                 char_type thischar = fmt[0];
921                 if (thischar == '%') {
922                         // beginning or end of key
923                         if (scanning_key) {
924                                 // end of key
925                                 scanning_key = false;
926                                 // so we replace the key with its value, which may be empty
927                                 if (key[0] == '!') {
928                                         // macro
929                                         string const val =
930                                                 buf.params().documentClass().getCiteMacro(engine_type, key);
931                                         fmt = from_utf8(val) + fmt.substr(1);
932                                         counter += 1;
933                                         continue;
934                                 } else if (prefixIs(key, "B_")) {
935                                         // a translatable bit (to the Buffer language)
936                                         string const val =
937                                                 buf.params().documentClass().getCiteMacro(engine_type, key);
938                                         docstring const trans =
939                                                 translateIfPossible(from_utf8(val), buf.params().language->code());
940                                         ret << trans;
941                                 } else if (key[0] == '_') {
942                                         // a translatable bit (to the GUI language)
943                                         string const val =
944                                                 buf.params().documentClass().getCiteMacro(engine_type, key);
945                                         docstring const trans =
946                                                 translateIfPossible(from_utf8(val));
947                                         ret << trans;
948                                 } else {
949                                         docstring const val =
950                                                 getValueForKey(key, buf, ci, xrefs, max_keysize);
951                                         if (!scanning_rich)
952                                                 ret << from_ascii("{!<span class=\"bib-" + key + "\">!}");
953                                         ret << val;
954                                         if (!scanning_rich)
955                                                 ret << from_ascii("{!</span>!}");
956                                 }
957                         } else {
958                                 // beginning of key
959                                 key.clear();
960                                 scanning_key = true;
961                         }
962                 }
963                 else if (thischar == '{') {
964                         // beginning of option?
965                         if (scanning_key) {
966                                 LYXERR0("ERROR: Found `{' when scanning key in `" << format << "'.");
967                                 return _("ERROR!");
968                         }
969                         if (fmt.size() > 1) {
970                                 if (fmt[1] == '%') {
971                                         // it is the beginning of an optional format
972                                         string optkey;
973                                         docstring ifpart;
974                                         docstring elsepart;
975                                         docstring const newfmt =
976                                                 parseOptions(fmt, optkey, ifpart, elsepart);
977                                         if (newfmt == fmt) // parse error
978                                                 return _("ERROR!");
979                                         fmt = newfmt;
980                                         docstring const val =
981                                                 getValueForKey(optkey, buf, ci, xrefs);
982                                         if (optkey == "next" && next)
983                                                 ret << ifpart; // without expansion
984                                         else if (optkey == "second" && second) {
985                                                 int newcounter = 0;
986                                                 ret << expandFormat(ifpart, xrefs, newcounter, buf,
987                                                         ci, next);
988                                         } else if (!val.empty()) {
989                                                 int newcounter = 0;
990                                                 ret << expandFormat(ifpart, xrefs, newcounter, buf,
991                                                         ci, next);
992                                         } else if (!elsepart.empty()) {
993                                                 int newcounter = 0;
994                                                 ret << expandFormat(elsepart, xrefs, newcounter, buf,
995                                                         ci, next);
996                                         }
997                                         // fmt will have been shortened for us already
998                                         continue;
999                                 }
1000                                 if (fmt[1] == '!') {
1001                                         // beginning of rich text
1002                                         scanning_rich = true;
1003                                         fmt = fmt.substr(2);
1004                                         ret << from_ascii("{!");
1005                                         continue;
1006                                 }
1007                         }
1008                         // we are here if '{' was not followed by % or !.
1009                         // So it's just a character.
1010                         ret << thischar;
1011                 }
1012                 else if (scanning_rich && thischar == '!'
1013                          && fmt.size() > 1 && fmt[1] == '}') {
1014                         // end of rich text
1015                         scanning_rich = false;
1016                         fmt = fmt.substr(2);
1017                         ret << from_ascii("!}");
1018                         continue;
1019                 }
1020                 else if (scanning_key)
1021                         key += char(thischar);
1022                 else {
1023                         try {
1024                                 ret.put(thischar);
1025                         } catch (EncodingException & /* e */) {
1026                                 LYXERR0("Uncodable character '" << docstring(1, thischar) << " in citation label!");
1027                         }
1028                 }
1029                 fmt = fmt.substr(1);
1030         } // for loop
1031         if (scanning_key) {
1032                 LYXERR0("Never found end of key in `" << format << "'!");
1033                 return _("ERROR!");
1034         }
1035         if (scanning_rich) {
1036                 LYXERR0("Never found end of rich text in `" << format << "'!");
1037                 return _("ERROR!");
1038         }
1039         return ret.str();
1040 }
1041
1042
1043 docstring const & BibTeXInfo::getInfo(BibTeXInfoList const & xrefs,
1044         Buffer const & buf, CiteItem const & ci, docstring const & format_in) const
1045 {
1046         bool const richtext = ci.richtext;
1047
1048         CiteEngineType const engine_type = buf.params().citeEngineType();
1049         DocumentClass const & dc = buf.params().documentClass();
1050         docstring const & format = format_in.empty()? 
1051                                 from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_)))
1052                               : format_in;
1053
1054         if (format != format_) {
1055                 // clear caches since format changed
1056                 info_.clear();
1057                 info_richtext_.clear();
1058                 format_ = format;
1059         }
1060
1061         if (!richtext && !info_.empty()) {
1062                 info_ = convertLaTeXCommands(processRichtext(info_, false));
1063                 return info_;
1064         }
1065         if (richtext && !info_richtext_.empty())
1066                 return info_richtext_;
1067
1068         if (!is_bibtex_) {
1069                 BibTeXInfo::const_iterator it = find(from_ascii("ref"));
1070                 info_ = it->second;
1071                 return info_;
1072         }
1073
1074         int counter = 0;
1075         info_ = expandFormat(format, xrefs, counter, buf,
1076                 ci, false, false);
1077
1078         if (info_.empty()) {
1079                 // this probably shouldn't happen
1080                 return info_;
1081         }
1082
1083         if (richtext) {
1084                 info_richtext_ = convertLaTeXCommands(processRichtext(info_, true));
1085                 return info_richtext_;
1086         }
1087
1088         info_ = convertLaTeXCommands(processRichtext(info_, false));
1089         return info_;
1090 }
1091
1092
1093 docstring const BibTeXInfo::getLabel(BibTeXInfoList const & xrefs,
1094         Buffer const & buf, docstring const & format,
1095         CiteItem const & ci, bool next, bool second) const
1096 {
1097         docstring loclabel;
1098
1099         int counter = 0;
1100         loclabel = expandFormat(format, xrefs, counter, buf, ci, next, second);
1101
1102         if (!loclabel.empty() && !next) {
1103                 loclabel = processRichtext(loclabel, ci.richtext);
1104                 loclabel = convertLaTeXCommands(loclabel);
1105         }
1106
1107         return loclabel;
1108 }
1109
1110
1111 docstring const & BibTeXInfo::operator[](docstring const & field) const
1112 {
1113         BibTeXInfo::const_iterator it = find(field);
1114         if (it != end())
1115                 return it->second;
1116         static docstring const empty_value = docstring();
1117         return empty_value;
1118 }
1119
1120
1121 docstring const & BibTeXInfo::operator[](string const & field) const
1122 {
1123         return operator[](from_ascii(field));
1124 }
1125
1126
1127 docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf,
1128         CiteItem const & ci, BibTeXInfoList const & xrefs, size_t maxsize) const
1129 {
1130         // anything less is pointless
1131         LASSERT(maxsize >= 16, maxsize = 16);
1132         string key = oldkey;
1133         bool cleanit = false;
1134         if (prefixIs(oldkey, "clean:")) {
1135                 key = oldkey.substr(6);
1136                 cleanit = true;
1137         }
1138
1139         docstring ret = operator[](key);
1140         if (ret.empty() && !xrefs.empty()) {
1141                 // xr is a (reference to a) BibTeXInfo const *
1142                 for (auto const & xr : xrefs) {
1143                         if (xr && !(*xr)[key].empty()) {
1144                                 ret = (*xr)[key];
1145                                 break;
1146                         }
1147                 }
1148         }
1149         if (ret.empty()) {
1150                 // some special keys
1151                 // FIXME: dialog, textbefore and textafter have nothing to do with this
1152                 if (key == "dialog" && ci.context == CiteItem::Dialog)
1153                         ret = from_ascii("x"); // any non-empty string will do
1154                 else if (key == "export" && ci.context == CiteItem::Export)
1155                         ret = from_ascii("x"); // any non-empty string will do
1156                 else if (key == "ifstar" && ci.Starred)
1157                         ret = from_ascii("x"); // any non-empty string will do
1158                 else if (key == "ifqualified" && ci.isQualified)
1159                         ret = from_ascii("x"); // any non-empty string will do
1160                 else if (key == "entrytype")
1161                         ret = entry_type_;
1162                 else if (prefixIs(key, "ifentrytype:")
1163                          && from_ascii(key.substr(12)) == entry_type_)
1164                         ret = from_ascii("x"); // any non-empty string will do
1165                 else if (key == "key")
1166                         ret = bib_key_;
1167                 else if (key == "label")
1168                         ret = label_;
1169                 else if (key == "modifier" && modifier_ != 0)
1170                         ret = modifier_;
1171                 else if (key == "numericallabel")
1172                         ret = cite_number_;
1173                 else if (prefixIs(key, "ifmultiple:")) {
1174                         // Return whether we have multiple authors
1175                         docstring const kind = operator[](from_ascii(key.substr(11)));
1176                         if (multipleAuthors(kind))
1177                                 ret = from_ascii("x"); // any non-empty string will do
1178                 }
1179                 else if (prefixIs(key, "abbrvnames:")) {
1180                         // Special key to provide abbreviated name list,
1181                         // with respect to maxcitenames. Suitable for Bibliography
1182                         // beginnings.
1183                         docstring const kind = operator[](from_ascii(key.substr(11)));
1184                         ret = getAuthorList(&buf, kind, false, false, true);
1185                         if (ci.forceUpperCase && isLowerCase(ret[0]))
1186                                 ret[0] = uppercase(ret[0]);
1187                 } else if (prefixIs(key, "fullnames:")) {
1188                         // Return a full name list. Suitable for Bibliography
1189                         // beginnings.
1190                         docstring const kind = operator[](from_ascii(key.substr(10)));
1191                         ret = getAuthorList(&buf, kind, true, false, true);
1192                         if (ci.forceUpperCase && isLowerCase(ret[0]))
1193                                 ret[0] = uppercase(ret[0]);
1194                 } else if (prefixIs(key, "forceabbrvnames:")) {
1195                         // Special key to provide abbreviated name lists,
1196                         // irrespective of maxcitenames. Suitable for Bibliography
1197                         // beginnings.
1198                         docstring const kind = operator[](from_ascii(key.substr(15)));
1199                         ret = getAuthorList(&buf, kind, false, true, true);
1200                         if (ci.forceUpperCase && isLowerCase(ret[0]))
1201                                 ret[0] = uppercase(ret[0]);
1202                 } else if (prefixIs(key, "abbrvbynames:")) {
1203                         // Special key to provide abbreviated name list,
1204                         // with respect to maxcitenames. Suitable for further names inside a
1205                         // bibliography item // (such as "ed. by ...")
1206                         docstring const kind = operator[](from_ascii(key.substr(11)));
1207                         ret = getAuthorList(&buf, kind, false, false, true, false);
1208                         if (ci.forceUpperCase && isLowerCase(ret[0]))
1209                                 ret[0] = uppercase(ret[0]);
1210                 } else if (prefixIs(key, "fullbynames:")) {
1211                         // Return a full name list. Suitable for further names inside a
1212                         // bibliography item // (such as "ed. by ...")
1213                         docstring const kind = operator[](from_ascii(key.substr(10)));
1214                         ret = getAuthorList(&buf, kind, true, false, true, false);
1215                         if (ci.forceUpperCase && isLowerCase(ret[0]))
1216                                 ret[0] = uppercase(ret[0]);
1217                 } else if (prefixIs(key, "forceabbrvbynames:")) {
1218                         // Special key to provide abbreviated name lists,
1219                         // irrespective of maxcitenames. Suitable for further names inside a
1220                         // bibliography item // (such as "ed. by ...")
1221                         docstring const kind = operator[](from_ascii(key.substr(15)));
1222                         ret = getAuthorList(&buf, kind, false, true, true, false);
1223                         if (ci.forceUpperCase && isLowerCase(ret[0]))
1224                                 ret[0] = uppercase(ret[0]);
1225                 } else if (key == "abbrvciteauthor") {
1226                         // Special key to provide abbreviated author or
1227                         // editor names (suitable for citation labels),
1228                         // with respect to maxcitenames.
1229                         ret = getAuthorOrEditorList(&buf, false, false);
1230                         if (ci.forceUpperCase && isLowerCase(ret[0]))
1231                                 ret[0] = uppercase(ret[0]);
1232                 } else if (key == "fullciteauthor") {
1233                         // Return a full author or editor list (for citation labels)
1234                         ret = getAuthorOrEditorList(&buf, true, false);
1235                         if (ci.forceUpperCase && isLowerCase(ret[0]))
1236                                 ret[0] = uppercase(ret[0]);
1237                 } else if (key == "forceabbrvciteauthor") {
1238                         // Special key to provide abbreviated author or
1239                         // editor names (suitable for citation labels),
1240                         // irrespective of maxcitenames.
1241                         ret = getAuthorOrEditorList(&buf, false, true);
1242                         if (ci.forceUpperCase && isLowerCase(ret[0]))
1243                                 ret[0] = uppercase(ret[0]);
1244                 } else if (key == "bibentry") {
1245                         // Special key to provide the full bibliography entry: see getInfo()
1246                         CiteEngineType const engine_type = buf.params().citeEngineType();
1247                         DocumentClass const & dc = buf.params().documentClass();
1248                         docstring const & format =
1249                                 from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_), false));
1250                         int counter = 0;
1251                         ret = expandFormat(format, xrefs, counter, buf, ci, false, false);
1252                 } else if (key == "textbefore")
1253                         ret = ci.textBefore;
1254                 else if (key == "textafter")
1255                         ret = ci.textAfter;
1256                 else if (key == "curpretext") {
1257                         vector<pair<docstring, docstring>> pres = ci.getPretexts();
1258                         vector<pair<docstring, docstring>>::iterator it = pres.begin();
1259                         int numkey = 1;
1260                         for (; it != pres.end() ; ++it) {
1261                                 if ((*it).first == bib_key_ && numkey == num_bib_key_) {
1262                                         ret = (*it).second;
1263                                         pres.erase(it);
1264                                         break;
1265                                 }
1266                                 if ((*it).first == bib_key_)
1267                                         ++numkey;
1268                         }
1269                 } else if (key == "curposttext") {
1270                         vector<pair<docstring, docstring>> posts = ci.getPosttexts();
1271                         vector<pair<docstring, docstring>>::iterator it = posts.begin();
1272                         int numkey = 1;
1273                         for (; it != posts.end() ; ++it) {
1274                                 if ((*it).first == bib_key_ && numkey == num_bib_key_) {
1275                                         ret = (*it).second;
1276                                         posts.erase(it);
1277                                         break;
1278                                 }
1279                                 if ((*it).first == bib_key_)
1280                                         ++numkey;
1281                         }
1282                 } else if (key == "year")
1283                         ret = getYear();
1284         }
1285
1286         if (cleanit)
1287                 ret = xml::cleanAttr(ret);
1288
1289         // make sure it is not too big
1290         support::truncateWithEllipsis(ret, maxsize);
1291         return ret;
1292 }
1293
1294
1295 //////////////////////////////////////////////////////////////////////
1296 //
1297 // BiblioInfo
1298 //
1299 //////////////////////////////////////////////////////////////////////
1300
1301 namespace {
1302
1303 // A functor for use with sort, leading to case insensitive sorting
1304 bool compareNoCase(const docstring & a, const docstring & b) {
1305         return compare_no_case(a, b) < 0;
1306 }
1307
1308 } // namespace
1309
1310
1311 vector<docstring> const BiblioInfo::getXRefs(BibTeXInfo const & data, bool const nested) const
1312 {
1313         vector<docstring> result;
1314         if (!data.isBibTeX())
1315                 return result;
1316         // Legacy crossref field. This is not nestable.
1317         if (!nested && !data["crossref"].empty()) {
1318                 docstring const xrefkey = data["crossref"];
1319                 result.push_back(xrefkey);
1320                 // However, check for nested xdatas
1321                 BiblioInfo::const_iterator it = find(xrefkey);
1322                 if (it != end()) {
1323                         BibTeXInfo const & xref = it->second;
1324                         vector<docstring> const nxdata = getXRefs(xref, true);
1325                         if (!nxdata.empty())
1326                                 result.insert(result.end(), nxdata.begin(), nxdata.end());
1327                 }
1328         }
1329         // Biblatex's xdata field. Infinitely nestable.
1330         // XData field can consist of a comma-separated list of keys
1331         vector<docstring> const xdatakeys = getVectorFromString(data["xdata"]);
1332         if (!xdatakeys.empty()) {
1333                 for (auto const & xdatakey : xdatakeys) {
1334                         result.push_back(xdatakey);
1335                         BiblioInfo::const_iterator it = find(xdatakey);
1336                         if (it != end()) {
1337                                 BibTeXInfo const & xdata = it->second;
1338                                 vector<docstring> const nxdata = getXRefs(xdata, true);
1339                                 if (!nxdata.empty())
1340                                         result.insert(result.end(), nxdata.begin(), nxdata.end());
1341                         }
1342                 }
1343         }
1344         return result;
1345 }
1346
1347
1348 vector<docstring> const BiblioInfo::getKeys() const
1349 {
1350         vector<docstring> bibkeys;
1351         for (auto const & bi : *this)
1352                 bibkeys.push_back(bi.first);
1353         sort(bibkeys.begin(), bibkeys.end(), &compareNoCase);
1354         return bibkeys;
1355 }
1356
1357
1358 vector<docstring> const BiblioInfo::getFields() const
1359 {
1360         vector<docstring> bibfields;
1361         for (auto const & fn : field_names_)
1362                 bibfields.push_back(fn);
1363         sort(bibfields.begin(), bibfields.end());
1364         return bibfields;
1365 }
1366
1367
1368 vector<docstring> const BiblioInfo::getEntries() const
1369 {
1370         vector<docstring> bibentries;
1371         for (auto const & et : entry_types_)
1372                 bibentries.push_back(et);
1373         sort(bibentries.begin(), bibentries.end());
1374         return bibentries;
1375 }
1376
1377
1378 docstring const BiblioInfo::getAuthorOrEditorList(docstring const & key, Buffer const & buf) const
1379 {
1380         BiblioInfo::const_iterator it = find(key);
1381         if (it == end())
1382                 return docstring();
1383         BibTeXInfo const & data = it->second;
1384         return data.getAuthorOrEditorList(&buf, false);
1385 }
1386
1387
1388 docstring const BiblioInfo::getCiteNumber(docstring const & key) const
1389 {
1390         BiblioInfo::const_iterator it = find(key);
1391         if (it == end())
1392                 return docstring();
1393         BibTeXInfo const & data = it->second;
1394         return data.citeNumber();
1395 }
1396
1397 void BiblioInfo::getLocators(docstring const & key, docstring & doi, docstring & url, docstring & file) const
1398 {
1399         BiblioInfo::const_iterator it = find(key);
1400          if (it == end())
1401                 return;
1402         BibTeXInfo const & data = it->second;
1403         data.getLocators(doi,url,file);
1404 }
1405
1406
1407 docstring const BiblioInfo::getYear(docstring const & key, bool use_modifier) const
1408 {
1409         BiblioInfo::const_iterator it = find(key);
1410         if (it == end())
1411                 return docstring();
1412         BibTeXInfo const & data = it->second;
1413         docstring year = data.getYear();
1414         if (year.empty()) {
1415                 // let's try the crossrefs
1416                 vector<docstring> const xrefs = getXRefs(data);
1417                 if (xrefs.empty())
1418                         // no luck
1419                         return docstring();
1420                 for (docstring const & xref : xrefs) {
1421                         BiblioInfo::const_iterator const xrefit = find(xref);
1422                         if (xrefit == end())
1423                                 continue;
1424                         BibTeXInfo const & xref_data = xrefit->second;
1425                         year = xref_data.getYear();
1426                         if (!year.empty())
1427                                 // success!
1428                                 break;
1429                 }
1430         }
1431         if (use_modifier && data.modifier() != 0)
1432                 year += data.modifier();
1433         return year;
1434 }
1435
1436
1437 docstring const BiblioInfo::getYear(docstring const & key, Buffer const & buf, bool use_modifier) const
1438 {
1439         docstring const year = getYear(key, use_modifier);
1440         if (year.empty())
1441                 return buf.B_("No year");
1442         return year;
1443 }
1444
1445
1446 docstring const BiblioInfo::getInfo(docstring const & key,
1447         Buffer const & buf, CiteItem const & ci, docstring const & format) const
1448 {
1449         BiblioInfo::const_iterator it = find(key);
1450         if (it == end())
1451                 return _("Bibliography entry not found!");
1452         BibTeXInfo const & data = it->second;
1453         BibTeXInfoList xrefptrs;
1454         for (docstring const & xref : getXRefs(data)) {
1455                 BiblioInfo::const_iterator const xrefit = find(xref);
1456                 if (xrefit != end())
1457                         xrefptrs.push_back(&(xrefit->second));
1458         }
1459         return data.getInfo(xrefptrs, buf, ci, format);
1460 }
1461
1462
1463 docstring const BiblioInfo::getLabel(vector<docstring> keys,
1464         Buffer const & buf, string const & style, CiteItem const & ci) const
1465 {
1466         size_t max_size = ci.max_size;
1467         // shorter makes no sense
1468         LASSERT(max_size >= 16, max_size = 16);
1469
1470         // we can't display more than 10 of these, anyway
1471         // but since we truncate in the middle,
1472         // we need to split into two halfs.
1473         bool const too_many_keys = keys.size() > 10;
1474         vector<docstring> lkeys;
1475         if (too_many_keys) {
1476                 lkeys.insert(lkeys.end(), keys.end() - 5, keys.end());
1477                 keys.resize(5);
1478                 keys.insert(keys.end(), lkeys.begin(), lkeys.end());
1479         }
1480
1481         CiteEngineType const engine_type = buf.params().citeEngineType();
1482         DocumentClass const & dc = buf.params().documentClass();
1483         docstring const & format = from_utf8(dc.getCiteFormat(engine_type, style, false, "cite"));
1484         docstring ret = format;
1485         vector<docstring>::const_iterator key = keys.begin();
1486         vector<docstring>::const_iterator ken = keys.end();
1487         vector<docstring> handled_keys;
1488         for (int i = 0; key != ken; ++key, ++i) {
1489                 handled_keys.push_back(*key);
1490                 int n = 0;
1491                 for (auto const & k : handled_keys) {
1492                         if (k == *key)
1493                                 ++n;
1494                 }
1495                 BiblioInfo::const_iterator it = find(*key);
1496                 BibTeXInfo empty_data;
1497                 empty_data.key(*key);
1498                 BibTeXInfo & data = empty_data;
1499                 vector<BibTeXInfo const *> xrefptrs;
1500                 if (it != end()) {
1501                         data = it->second;
1502                         for (docstring const & xref : getXRefs(data)) {
1503                                 BiblioInfo::const_iterator const xrefit = find(xref);
1504                                 if (xrefit != end())
1505                                         xrefptrs.push_back(&(xrefit->second));
1506                         }
1507                 }
1508                 data.numKey(n);
1509                 ret = data.getLabel(xrefptrs, buf, ret, ci, key + 1 != ken, i == 1);
1510         }
1511
1512         support::truncateWithEllipsis(ret, max_size, true);
1513
1514         return ret;
1515 }
1516
1517
1518 bool BiblioInfo::isBibtex(docstring const & key) const
1519 {
1520         docstring key1;
1521         split(key, key1, ',');
1522         BiblioInfo::const_iterator it = find(key1);
1523         if (it == end())
1524                 return false;
1525         return it->second.isBibTeX();
1526 }
1527
1528
1529 BiblioInfo::CiteStringMap const BiblioInfo::getCiteStrings(
1530         vector<docstring> const & keys, vector<CitationStyle> const & styles,
1531         Buffer const & buf, CiteItem const & ci) const
1532 {
1533         if (empty())
1534                 return vector<pair<docstring,docstring>>();
1535
1536         string style;
1537         CiteStringMap csm(styles.size());
1538         for (size_t i = 0; i != csm.size(); ++i) {
1539                 style = styles[i].name;
1540                 csm[i] = make_pair(from_ascii(style), getLabel(keys, buf, style, ci));
1541         }
1542
1543         return csm;
1544 }
1545
1546
1547 void BiblioInfo::mergeBiblioInfo(BiblioInfo const & info)
1548 {
1549         bimap_.insert(info.begin(), info.end());
1550         field_names_.insert(info.field_names_.begin(), info.field_names_.end());
1551         entry_types_.insert(info.entry_types_.begin(), info.entry_types_.end());
1552 }
1553
1554
1555 namespace {
1556
1557 // used in xhtml to sort a list of BibTeXInfo objects
1558 bool lSorter(BibTeXInfo const * lhs, BibTeXInfo const * rhs)
1559 {
1560         docstring const lauth = lhs->getAuthorOrEditorList();
1561         docstring const rauth = rhs->getAuthorOrEditorList();
1562         docstring const lyear = lhs->getYear();
1563         docstring const ryear = rhs->getYear();
1564         docstring const ltitl = lhs->operator[]("title");
1565         docstring const rtitl = rhs->operator[]("title");
1566         return  (lauth < rauth)
1567                 || (lauth == rauth && lyear < ryear)
1568                 || (lauth == rauth && lyear == ryear && ltitl < rtitl);
1569 }
1570
1571 } // namespace
1572
1573
1574 void BiblioInfo::collectCitedEntries(Buffer const & buf)
1575 {
1576         cited_entries_.clear();
1577         // We are going to collect all the citation keys used in the document,
1578         // getting them from the TOC.
1579         // FIXME We may want to collect these differently, in the first case,
1580         // so that we might have them in order of appearance.
1581         set<docstring> citekeys;
1582         Toc const & toc = *buf.tocBackend().toc("citation");
1583         for (auto const & t : toc) {
1584                 if (t.str().empty())
1585                         continue;
1586                 vector<docstring> const keys = getVectorFromString(t.str());
1587                 citekeys.insert(keys.begin(), keys.end());
1588         }
1589         if (citekeys.empty())
1590                 return;
1591
1592         // We have a set of the keys used in this document.
1593         // We will now convert it to a list of the BibTeXInfo objects used in
1594         // this document...
1595         vector<BibTeXInfo const *> bi;
1596         for (auto const & ck : citekeys) {
1597                 BiblioInfo::const_iterator const bt = find(ck);
1598                 if (bt == end() || !bt->second.isBibTeX())
1599                         continue;
1600                 bi.push_back(&(bt->second));
1601         }
1602         // ...and sort it.
1603         sort(bi.begin(), bi.end(), lSorter);
1604
1605         // Now we can write the sorted keys
1606         // b is a BibTeXInfo const *
1607         for (auto const & b : bi)
1608                 cited_entries_.push_back(b->key());
1609 }
1610
1611
1612 void BiblioInfo::makeCitationLabels(Buffer const & buf)
1613 {
1614         collectCitedEntries(buf);
1615         CiteEngineType const engine_type = buf.params().citeEngineType();
1616         bool const numbers = (engine_type & ENGINE_TYPE_NUMERICAL);
1617
1618         int keynumber = 0;
1619         char modifier = 0;
1620         // used to remember the last one we saw
1621         // we'll be comparing entries to see if we need to add
1622         // modifiers, like "1984a"
1623         map<docstring, BibTeXInfo>::iterator last = bimap_.end();
1624
1625         // add letters to years
1626         for (auto const & ce : cited_entries_) {
1627                 map<docstring, BibTeXInfo>::iterator const biit = bimap_.find(ce);
1628                 // this shouldn't happen, but...
1629                 if (biit == bimap_.end())
1630                         // ...fail gracefully, anyway.
1631                         continue;
1632                 BibTeXInfo & entry = biit->second;
1633                 if (numbers) {
1634                         docstring const num = convert<docstring>(++keynumber);
1635                         entry.setCiteNumber(num);
1636                 } else {
1637                         // The first test here is checking whether this is the first
1638                         // time through the loop. If so, then we do not have anything
1639                         // with which to compare.
1640                         if (last != bimap_.end()
1641                             && entry.getAuthorOrEditorList() == last->second.getAuthorOrEditorList()
1642                             // we access the year via getYear() so as to get it from the xref,
1643                             // if we need to do so
1644                             && getYear(entry.key()) == getYear(last->second.key())) {
1645                                 if (modifier == 0) {
1646                                         // so the last one should have been 'a'
1647                                         last->second.setModifier('a');
1648                                         modifier = 'b';
1649                                 } else if (modifier == 'z')
1650                                         modifier = 'A';
1651                                 else
1652                                         modifier++;
1653                         } else {
1654                                 modifier = 0;
1655                         }
1656                         entry.setModifier(modifier);
1657                         // remember the last one
1658                         last = biit;
1659                 }
1660         }
1661         // Set the labels
1662         for (auto const & ce : cited_entries_) {
1663                 map<docstring, BibTeXInfo>::iterator const biit = bimap_.find(ce);
1664                 // this shouldn't happen, but...
1665                 if (biit == bimap_.end())
1666                         // ...fail gracefully, anyway.
1667                         continue;
1668                 BibTeXInfo & entry = biit->second;
1669                 if (numbers) {
1670                         entry.label(entry.citeNumber());
1671                 } else {
1672                         docstring const auth = entry.getAuthorOrEditorList(&buf, false);
1673                         // we do it this way so as to access the xref, if necessary
1674                         // note that this also gives us the modifier
1675                         docstring const year = getYear(ce, buf, true);
1676                         if (!auth.empty() && !year.empty())
1677                                 entry.label(auth + ' ' + year);
1678                         else
1679                                 entry.label(entry.key());
1680                 }
1681         }
1682 }
1683
1684
1685 //////////////////////////////////////////////////////////////////////
1686 //
1687 // CitationStyle
1688 //
1689 //////////////////////////////////////////////////////////////////////
1690
1691
1692 CitationStyle citationStyleFromString(string const & command,
1693                                       BufferParams const & params)
1694 {
1695         CitationStyle cs;
1696         if (command.empty())
1697                 return cs;
1698
1699         string const alias = params.getCiteAlias(command);
1700         string cmd = alias.empty() ? command : alias;
1701         if (isUpperCase(command[0])) {
1702                 cs.forceUpperCase = true;
1703                 cmd[0] = lowercase(cmd[0]);
1704         }
1705
1706         size_t const n = command.size() - 1;
1707         if (command[n] == '*') {
1708                 cs.hasStarredVersion = true;
1709                 if (suffixIs(cmd, '*'))
1710                         cmd = cmd.substr(0, cmd.size() - 1);
1711         }
1712
1713         cs.name = cmd;
1714         return cs;
1715 }
1716
1717
1718 string citationStyleToString(const CitationStyle & cs, bool const latex)
1719 {
1720         string cmd = latex ? cs.cmd : cs.name;
1721         if (cs.forceUpperCase)
1722                 cmd[0] = uppercase(cmd[0]);
1723         if (cs.hasStarredVersion)
1724                 cmd += '*';
1725         return cmd;
1726 }
1727
1728
1729 docstring authorsToDocBookAuthorGroup(docstring const & authorsString, XMLStream & xs, Buffer const & buf)
1730 {
1731         // This function closely mimics getAuthorList, but produces DocBook instead of text.
1732         // It has been greatly simplified, as the complete list of authors is always produced. No separators are required,
1733         // as the output has a database-like shape.
1734         // constructName has also been merged within, as it becomes really simple and leads to no copy-paste.
1735
1736         if (authorsString.empty()) {
1737                 return docstring();
1738         }
1739
1740         // Split the input list of authors into individual authors.
1741         vector<docstring> const authors = getAuthors(authorsString);
1742
1743         // Retrieve the "et al." variation.
1744         string const etal = buf.params().documentClass().getCiteMacro(buf.params().citeEngineType(), "_etal");
1745
1746         // Output the list of authors.
1747         xs << xml::StartTag("authorgroup");
1748         xs << xml::CR();
1749
1750         auto it = authors.cbegin();
1751         auto en = authors.cend();
1752         for (size_t i = 0; it != en; ++it, ++i) {
1753                 xs << xml::StartTag("author");
1754                 xs << xml::CR();
1755                 xs << xml::StartTag("personname");
1756                 xs << xml::CR();
1757                 docstring name = *it;
1758
1759                 // All authors go in a <personname>. If more structure is known, use it; otherwise (just "et al."), print it as such.
1760                 if (name == "others") {
1761                         xs << buf.B_(etal);
1762                 } else {
1763                         name_parts parts = nameParts(name);
1764                         if (! parts.prefix.empty()) {
1765                                 xs << xml::StartTag("honorific");
1766                                 xs << parts.prefix;
1767                                 xs << xml::EndTag("honorific");
1768                                 xs << xml::CR();
1769                         }
1770                         if (! parts.prename.empty()) {
1771                                 xs << xml::StartTag("firstname");
1772                                 xs << parts.prename;
1773                                 xs << xml::EndTag("firstname");
1774                                 xs << xml::CR();
1775                         }
1776                         if (! parts.surname.empty()) {
1777                                 xs << xml::StartTag("surname");
1778                                 xs << parts.surname;
1779                                 xs << xml::EndTag("surname");
1780                                 xs << xml::CR();
1781                         }
1782                         if (! parts.suffix.empty()) {
1783                                 xs << xml::StartTag("othername", "role=\"suffix\"");
1784                                 xs << parts.suffix;
1785                                 xs << xml::EndTag("othername");
1786                                 xs << xml::CR();
1787                         }
1788                 }
1789
1790                 xs << xml::EndTag("personname");
1791                 xs << xml::CR();
1792                 xs << xml::EndTag("author");
1793                 xs << xml::CR();
1794
1795                 // Could add an affiliation after <personname>, but not stored in BibTeX.
1796         }
1797         xs << xml::EndTag("authorgroup");
1798         xs << xml::CR();
1799
1800         return docstring();
1801 }
1802
1803 } // namespace lyx