+ char_type thischar = fmt[0];
+ if (thischar == '%') {
+ // beginning or end of key
+ if (scanning_key) {
+ // end of key
+ scanning_key = false;
+ // so we replace the key with its value, which may be empty
+ if (key[0] == '!') {
+ // macro
+ string const val =
+ buf.params().documentClass().getCiteMacro(engine_type, key);
+ fmt = val + fmt.substr(1);
+ continue;
+ } else if (key[0] == '_') {
+ // a translatable bit
+ string const val =
+ buf.params().documentClass().getCiteMacro(engine_type, key);
+ docstring const trans =
+ translateIfPossible(from_utf8(val), buf.params().language->code());
+ ret += trans;
+ } else {
+ docstring const val =
+ getValueForKey(key, buf, before, after, dialog, xref);
+ if (!scanning_rich)
+ ret += from_ascii("{!<span class=\"bib-" + key + "\">!}");
+ ret += val;
+ if (!scanning_rich)
+ ret += from_ascii("{!</span>!}");
+ }
+ } else {
+ // beginning of key
+ key.clear();
+ scanning_key = true;
+ }
+ }
+ else if (thischar == '{') {
+ // beginning of option?
+ if (scanning_key) {
+ LYXERR0("ERROR: Found `{' when scanning key in `" << format << "'.");
+ return _("ERROR!");
+ }
+ if (fmt.size() > 1) {
+ if (fmt[1] == '%') {
+ // it is the beginning of an optional format
+ string optkey;
+ string ifpart;
+ string elsepart;
+ string const newfmt =
+ parseOptions(fmt, optkey, ifpart, elsepart);
+ if (newfmt == fmt) // parse error
+ return _("ERROR!");
+ fmt = newfmt;
+ docstring const val =
+ getValueForKey(optkey, buf, before, after, dialog, xref);
+ if (optkey == "next" && next)
+ ret += from_utf8(ifpart); // without expansion
+ else if (!val.empty())
+ ret += expandFormat(ifpart, xref, counter, buf,
+ before, after, dialog, next);
+ else if (!elsepart.empty())
+ ret += expandFormat(elsepart, xref, counter, buf,
+ before, after, dialog, next);
+ // fmt will have been shortened for us already
+ continue;
+ }
+ if (fmt[1] == '!') {
+ // beginning of rich text
+ scanning_rich = true;
+ fmt = fmt.substr(2);
+ ret += from_ascii("{!");
+ continue;
+ }
+ }
+ // we are here if '{' was not followed by % or !.
+ // So it's just a character.
+ ret += thischar;
+ }
+ else if (scanning_rich && thischar == '!'
+ && fmt.size() > 1 && fmt[1] == '}') {
+ // end of rich text
+ scanning_rich = false;
+ fmt = fmt.substr(2);
+ ret += from_ascii("!}");
+ continue;
+ }
+ else if (scanning_key)
+ key += char(thischar);
+ else
+ ret += thischar;
+ fmt = fmt.substr(1);
+ } // for loop
+ if (scanning_key) {
+ LYXERR0("Never found end of key in `" << format << "'!");
+ return _("ERROR!");
+ }
+ if (scanning_rich) {
+ LYXERR0("Never found end of rich text in `" << format << "'!");
+ return _("ERROR!");
+ }
+ return ret;
+}
+
+
+docstring const & BibTeXInfo::getInfo(BibTeXInfo const * const xref,
+ Buffer const & buf, bool richtext) const
+{
+ if (!richtext && !info_.empty())
+ return info_;
+ if (richtext && !info_richtext_.empty())
+ return info_richtext_;
+
+ if (!is_bibtex_) {
+ BibTeXInfo::const_iterator it = find(from_ascii("ref"));
+ info_ = it->second;
+ return info_;
+ }
+
+ CiteEngineType const engine_type = buf.params().citeEngineType();
+ DocumentClass const & dc = buf.params().documentClass();
+ string const & format = dc.getCiteFormat(engine_type, to_utf8(entry_type_));
+ int counter = 0;
+ info_ = expandFormat(format, xref, counter, buf,
+ docstring(), docstring(), docstring(), false);
+
+ if (!info_.empty()) {
+ info_richtext_ = convertLaTeXCommands(processRichtext(info_, true));
+ info_ = convertLaTeXCommands(processRichtext(info_, false));
+ if (richtext)
+ return info_richtext_;
+ }
+ return info_;
+}
+
+
+docstring const BibTeXInfo::getLabel(BibTeXInfo const * const xref,
+ Buffer const & buf, string const & format, bool richtext,
+ docstring before, docstring after, docstring dialog, bool next) const
+{
+ docstring loclabel;
+
+ int counter = 0;
+ loclabel = expandFormat(format, xref, counter, buf,
+ before, after, dialog, next);
+
+ if (!loclabel.empty() && !next) {
+ loclabel = processRichtext(loclabel, richtext);
+ loclabel = convertLaTeXCommands(loclabel);
+ }
+ return loclabel;
+}
+
+
+docstring const & BibTeXInfo::operator[](docstring const & field) const
+{
+ BibTeXInfo::const_iterator it = find(field);
+ if (it != end())
+ return it->second;
+ static docstring const empty_value = docstring();
+ return empty_value;
+}
+
+
+docstring const & BibTeXInfo::operator[](string const & field) const
+{
+ return operator[](from_ascii(field));
+}
+
+
+docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf,
+ docstring const & before, docstring const & after, docstring const & dialog,
+ BibTeXInfo const * const xref) const
+{
+ string key = oldkey;
+ bool cleanit = false;
+ if (prefixIs(oldkey, "clean:")) {
+ key = oldkey.substr(6);
+ cleanit = true;
+ }
+
+ docstring ret = operator[](key);
+ if (ret.empty() && xref)
+ ret = (*xref)[key];
+ if (ret.empty()) {
+ // some special keys
+ // FIXME: dialog, textbefore and textafter have nothing to do with this
+ if (key == "dialog")
+ ret = dialog;
+ else if (key == "entrytype")
+ ret = entry_type_;
+ else if (key == "key")
+ ret = bib_key_;
+ else if (key == "label")
+ ret = label_;
+ else if (key == "modifier" && modifier_ != 0)
+ ret = modifier_;
+ else if (key == "numericallabel")
+ ret = cite_number_;
+ else if (key == "abbrvauthor")
+ // Special key to provide abbreviated author names.
+ ret = getAbbreviatedAuthor(buf, false);
+ else if (key == "shortauthor")
+ // When shortauthor is not defined, jurabib automatically
+ // provides jurabib-style abbreviated author names. We do
+ // this as well.
+ ret = getAbbreviatedAuthor(buf, true);
+ else if (key == "shorttitle") {
+ // When shorttitle is not defined, jurabib uses for `article'
+ // and `periodical' entries the form `journal volume [year]'
+ // and for other types of entries it uses the `title' field.
+ if (entry_type_ == "article" || entry_type_ == "periodical")
+ ret = operator[]("journal") + " " + operator[]("volume")
+ + " [" + operator[]("year") + "]";
+ else
+ ret = operator[]("title");
+ } else if (key == "bibentry") {
+ // Special key to provide the full bibliography entry: see getInfo()
+ CiteEngineType const engine_type = buf.params().citeEngineType();
+ DocumentClass const & dc = buf.params().documentClass();
+ string const & format = dc.getCiteFormat(engine_type, to_utf8(entry_type_));
+ int counter = 0;
+ ret = expandFormat(format, xref, counter, buf,
+ docstring(), docstring(), docstring(), false);
+ } else if (key == "textbefore")
+ ret = before;
+ else if (key == "textafter")
+ ret = after;
+ else if (key == "year")
+ ret = getYear();
+ }
+ if (cleanit)
+ return html::cleanAttr(ret);
+
+ return ret;