3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
15 #include "support/convert.h"
16 #include "support/gettext.h"
17 #include "support/lassert.h"
18 #include "support/lstrings.h"
24 using namespace lyx::support;
28 static int computeHash(docstring const & name,
29 docstring const & email)
31 string const full_author_string = to_utf8(name + email);
32 // Bernstein's hash function
33 unsigned int hash = 5381;
34 for (char c : full_author_string)
35 hash = ((hash << 5) + hash) + (unsigned int)c;
40 Author::Author(docstring const & name, docstring const & email, docstring const & initials)
41 : name_(name), email_(email), initials_(initials), used_(true),
42 buffer_id_(computeHash(name, email))
46 Author::Author(int buffer_id)
47 : name_(convert<docstring>(buffer_id)), email_(docstring()), initials_(docstring()), used_(false),
52 docstring Author::nameAndEmail() const
56 return bformat(_("%1$s[[name]] (%2$s[[email]])"), name(), email());
60 bool Author::valid() const
62 //this cannot be equal if the buffer_id was produced by the hash function.
63 return name_ != convert<docstring>(buffer_id_);
67 bool operator==(Author const & l, Author const & r)
69 return l.name() == r.name() && l.email() == r.email() && l.initials() == r.initials();
73 ostream & operator<<(ostream & os, Author const & a)
76 os << a.buffer_id_ << " \"" << to_utf8(a.name_) << "\"";
77 if (!a.email_.empty())
78 os << " " << to_utf8(a.email_);
84 istream & operator>>(istream & is, Author & a)
90 a.name_ = from_utf8(trim(token(s, '\"', 1)));
91 a.email_ = from_utf8(trim(token(s, '\"', 2)));
96 bool author_smaller(Author const & lhs, Author const & rhs)
98 return lhs.bufferId() < rhs.bufferId();
102 AuthorList::AuthorList()
106 int AuthorList::record(Author const & a)
108 bool const valid = a.valid();
109 // If we record an author which equals the current
110 // author, we copy the buffer_id, so that it will
111 // keep the same id in the file.
112 if (valid && !authors_.empty() && a == authors_[0])
113 authors_[0].setBufferId(a.bufferId());
115 Authors::const_iterator it = authors_.begin();
116 Authors::const_iterator const beg = it;
117 Authors::const_iterator const end = authors_.end();
118 for (; it != end; ++it) {
119 if (valid && *it == a)
121 if (it->bufferId() == a.bufferId()) {
122 int const id = it - beg;
124 // we need to handle the case of a valid author being registered
125 // after an invalid one. For instance, because "buffer-reload"
126 // does not clear the buffer's author list.
132 authors_.push_back(a);
133 return authors_.size() - 1;
137 void AuthorList::record(int id, Author const & a)
139 LBUFERR(unsigned(id) < authors_.size());
144 void AuthorList::recordCurrentAuthor(Author const & a)
146 // current author has id 0
151 Author const & AuthorList::get(int id) const
153 LASSERT(id < (int)authors_.size() , return authors_[0]);
158 AuthorList::Authors::const_iterator AuthorList::begin() const
160 return authors_.begin();
164 AuthorList::Authors::const_iterator AuthorList::end() const
166 return authors_.end();
170 void AuthorList::sort()
172 std::sort(authors_.begin(), authors_.end(), author_smaller);
176 ostream & operator<<(ostream & os, AuthorList const & a)
178 // Copy the authorlist, because we don't want to sort the original
179 AuthorList sorted = a;
181 for (auto const & aut : sorted) {
182 if (aut.used() && aut.valid())
183 os << "\\author " << aut << "\n";