]> git.lyx.org Git - lyx.git/blob - src/Author.cpp
bd9d12d06a87b23e7c351296d9d7e45acf7b235a
[lyx.git] / src / Author.cpp
1 /**
2  * \file Author.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "Author.h"
14
15 #include "support/convert.h"
16 #include "support/lassert.h"
17 #include "support/lstrings.h"
18
19 #include <algorithm>
20 #include <istream>
21
22 using namespace std;
23 using namespace lyx::support;
24
25 namespace lyx {
26
27 static int computeHash(docstring const & name,
28         docstring const & email)
29 {
30         string const full_author_string = to_utf8(name + email);
31         // Bernstein's hash function
32         unsigned int hash = 5381;
33         for (unsigned int i = 0; i < full_author_string.length(); ++i)
34                 hash = ((hash << 5) + hash) + (unsigned int)(full_author_string[i]);
35         return int(hash);
36 }
37
38
39 Author::Author(docstring const & name, docstring const & email)
40         : name_(name), email_(email), used_(true),
41           buffer_id_(computeHash(name, email))
42 {}
43
44
45 Author::Author(int buffer_id)
46         : name_(convert<docstring>(buffer_id)), email_(docstring()), used_(false),
47           buffer_id_(buffer_id)
48 {}
49
50
51 bool Author::valid() const
52 {
53         //this cannot be equal if the buffer_id was produced by the hash function.
54         return name_ != convert<docstring>(buffer_id_);
55 }
56
57
58 bool operator==(Author const & l, Author const & r)
59 {
60         return l.name() == r.name() && l.email() == r.email();
61 }
62
63
64 ostream & operator<<(ostream & os, Author const & a)
65 {
66         // FIXME UNICODE
67         os << a.buffer_id_ << " \"" << to_utf8(a.name_) << "\"";
68         if (!a.email_.empty())
69                 os << " " << to_utf8(a.email_);
70
71         return os;
72 }
73
74
75 istream & operator>>(istream & is, Author & a)
76 {
77         string s;
78         is >> a.buffer_id_;
79         getline(is, s);
80         // FIXME UNICODE
81         a.name_ = from_utf8(trim(token(s, '\"', 1)));
82         a.email_ = from_utf8(trim(token(s, '\"', 2)));
83         return is;
84 }
85
86
87 bool author_smaller(Author const & lhs, Author const & rhs)
88 {
89         return lhs.bufferId() < rhs.bufferId();
90 }
91
92
93 AuthorList::AuthorList()
94 {}
95
96
97 int AuthorList::record(Author const & a)
98 {
99         bool const valid = a.valid();
100         // If we record an author which equals the current
101         // author, we copy the buffer_id, so that it will
102         // keep the same id in the file.
103         if (valid && !authors_.empty() && a == authors_[0])
104                 authors_[0].setBufferId(a.bufferId());
105
106         Authors::const_iterator it = authors_.begin();
107         Authors::const_iterator const beg = it;
108         Authors::const_iterator const end = authors_.end();
109         for (; it != end; ++it) {
110                 if (valid && *it == a)
111                         return it - beg;
112                 if (it->bufferId() == a.bufferId()) {
113                         int id = it - beg;
114                         if (!it->valid())
115                                 // we need to handle the case of a valid author being registred
116                                 // after an invalid one. For instance, because "buffer-reload"
117                                 // does not clear the buffer's author list.
118                                 record(id, a);
119                         return id;
120                 }
121         }
122         authors_.push_back(a);
123         return authors_.size() - 1;
124 }
125
126
127 void AuthorList::record(int id, Author const & a)
128 {
129         LBUFERR(unsigned(id) < authors_.size());
130         authors_[id] = a;
131 }
132
133
134 void AuthorList::recordCurrentAuthor(Author const & a)
135 {
136         // current author has id 0
137         record(0, a);
138 }
139
140
141 Author const & AuthorList::get(int id) const
142 {
143         LASSERT(id < (int)authors_.size() , return authors_[0]);
144         return authors_[id];
145 }
146
147
148 AuthorList::Authors::const_iterator AuthorList::begin() const
149 {
150         return authors_.begin();
151 }
152
153
154 AuthorList::Authors::const_iterator AuthorList::end() const
155 {
156         return authors_.end();
157 }
158
159
160 void AuthorList::sort()
161 {
162         std::sort(authors_.begin(), authors_.end(), author_smaller);
163 }
164
165
166 ostream & operator<<(ostream & os, AuthorList const & a)
167 {
168         // Copy the authorlist, because we don't want to sort the original
169         AuthorList sorted = a;
170         sorted.sort();
171
172         AuthorList::Authors::const_iterator a_it = sorted.begin();
173         AuthorList::Authors::const_iterator const a_end = sorted.end();
174
175         for (; a_it != a_end; ++a_it) {
176                 if (a_it->used() && a_it->valid())
177                         os << "\\author " << *a_it << "\n";     
178         }
179         return os;
180 }
181
182
183 } // namespace lyx