]> git.lyx.org Git - lyx.git/blob - src/frontends/controllers/biblio.C
d878b4d3624609f3d2f154eca95ad6641b914ed3
[lyx.git] / src / frontends / controllers / biblio.C
1 /* This file is part of
2  * ====================================================== 
3  *
4  *           LyX, The Document Processor
5  *
6  *           Copyright 2001 The LyX Team.
7  *
8  * ======================================================
9  *
10  * \file biblio.C
11  * \author Angus Leeming <a.leeming@ic.ac.uk>
12  */
13
14 #include <vector>
15 #include <algorithm>
16
17 #ifdef __GNUG__
18 #pragma implementation
19 #endif
20
21 #include <config.h>
22
23 /*
24 #include "buffer.h"
25 #include "Dialogs.h"
26 #include "LyXView.h"
27 */
28 #include "LString.h"
29 #include "biblio.h"
30 #include "helper_funcs.h"
31 #include "support/lstrings.h"
32 #include "support/LAssert.h"
33 #include "support/LRegex.h"
34
35 using std::find;
36 using std::min;
37 using std::pair;
38 using std::vector;
39 using std::sort;
40
41 namespace biblio 
42 {
43
44
45 // A functor for use with std::sort, leading to case insensitive sorting
46 struct compareNoCase: public std::binary_function<string, string, bool> 
47 {
48         bool operator()(string const & s1, string const & s2) const {
49                 return compare_no_case(s1, s2) < 0;
50         }
51 };
52
53 vector<string> const getKeys(InfoMap const & map)
54 {
55         vector<string> bibkeys;
56
57         typedef std::map<string, string>::value_type InfoMapValue;
58
59         for (InfoMap::const_iterator it = map.begin(); it != map.end(); ++it) {
60                 bibkeys.push_back(it->first);
61         }
62
63         sort(bibkeys.begin(), bibkeys.end(), compareNoCase());
64         return bibkeys;
65 }
66
67
68 string const getInfo(InfoMap const & map, string const & key)
69 {
70         Assert(!map.empty());
71
72         string result;
73
74         InfoMap::const_iterator it = map.find(key);
75         if (it != map.end()) {
76                 // Search for all possible "required" keys
77                 string author = parseBibTeX(it->second, "author");
78                 if (author.empty())
79                         author = parseBibTeX(it->second, "editor");
80
81                 string year       = parseBibTeX(it->second, "year");
82                 string title      = parseBibTeX(it->second, "title");
83                 string booktitle  = parseBibTeX(it->second, "booktitle");
84                 string chapter    = parseBibTeX(it->second, "chapter");
85                 string pages      = parseBibTeX(it->second, "pages");
86
87                 string media      = parseBibTeX(it->second, "journal");
88                 if (media.empty())
89                         media = parseBibTeX(it->second, "publisher");
90                 if (media.empty())
91                         media = parseBibTeX(it->second, "school");
92                 if (media.empty())
93                         media = parseBibTeX(it->second, "institution");
94
95                 result = author;
96                 if (!year.empty())
97                         result += ", " + year;
98                 if (!title.empty())
99                         result += ", " + title;
100                 if (!booktitle.empty())
101                         result += ", in " + booktitle;
102                 if (!chapter.empty())
103                         result += ", Ch. " + chapter;
104                 if (!media.empty())
105                         result += ", " + media;
106                 if (!pages.empty())
107                         result += ", pp. " + pages;
108
109                 if (result.empty()) // not a BibTeX record
110                         result = it->second;
111         }
112
113         return result;
114 }
115  
116
117 vector<string>::const_iterator
118 searchKeys(InfoMap const & theMap,
119            vector<string> const & keys,
120            string const & expr,
121            vector<string>::const_iterator start,
122            Search type,
123            Direction dir,
124            bool caseSensitive)
125 {
126         // Preliminary checks
127         if(start < keys.begin() || start >= keys.end())
128                 return keys.end();
129         
130         string search_expr = frontStrip(strip(expr));
131         if (search_expr.empty())
132                 return start;
133
134         if (type == SIMPLE)
135                 return simpleSearch(theMap, keys, search_expr, start, dir,
136                                     caseSensitive);
137
138         return regexSearch(theMap, keys, search_expr, start, dir);
139 }
140
141
142 vector<string>::const_iterator
143 simpleSearch(InfoMap const & theMap,
144              vector<string> const & keys,
145              string const & expr,
146              vector<string>::const_iterator start,
147              Direction dir,
148              bool caseSensitive)
149 {
150         vector<string> searchwords = getVectorFromString(expr, " ");
151
152         // Loop over all keys from start...
153         for (vector<string>::const_iterator it = start;
154              // End condition is direction-dependent.
155              (dir == FORWARD) ? (it<keys.end()) : (it>=keys.begin());
156              // increment is direction-dependent.
157              (dir == FORWARD) ? (++it) : (--it)) {
158
159                 string data = (*it);
160                 biblio::InfoMap::const_iterator info = theMap.find(*it);
161                 if (info != theMap.end())
162                         data += " " + info->second;
163                 if (!caseSensitive)
164                         data = lowercase(data);
165
166                 bool found = true;
167
168                 // Loop over all search words...
169                 if (caseSensitive) {
170                         for (vector<string>::const_iterator sit=
171                                      searchwords.begin();
172                              sit<searchwords.end(); ++sit) {
173                                 if (data.find(*sit) == string::npos) {
174                                         found = false;
175                                         break;
176                                 }
177                         }
178                 } else {
179                         for (vector<string>::const_iterator sit=
180                                      searchwords.begin();
181                              sit<searchwords.end(); ++sit) {
182                                 if (data.find(lowercase(*sit)) ==
183                                     string::npos) {
184                                         found = false;
185                                         break;
186                                 }
187                         }
188                 }
189                 
190                 if (found) return it;
191         }
192
193         return keys.end();
194 }
195
196
197 vector<string>::const_iterator
198 regexSearch(InfoMap const & theMap,
199             vector<string> const & keys,
200             string const & expr,
201             vector<string>::const_iterator start,
202             Direction dir)
203 {
204         LRegex reg(expr);
205
206         for (vector<string>::const_iterator it = start;
207              // End condition is direction-dependent.
208              (dir == FORWARD) ? (it<keys.end()) : (it>=keys.begin());
209              // increment is direction-dependent.
210              (dir == FORWARD) ? (++it) : (--it)) {
211
212                 string data = (*it);
213                 biblio::InfoMap::const_iterator info = theMap.find(*it);
214                 if (info != theMap.end())
215                         data += " " + info->second;
216
217                 if (reg.exec(data).size() > 0)
218                         return it;
219         }
220
221         return keys.end();
222 }
223
224 string const parseBibTeX(string data, string const & findkey)
225 {
226         string keyvalue;
227         
228         for (string::iterator it=data.begin(); it<data.end(); ++it) {
229                 if ((*it) == '\n' || (*it) == '\t')
230                         (*it)= ' ';
231         }
232         
233         data = frontStrip(data);
234         while (!data.empty() && data[0] != '=' && 
235                (data.find(' ') != string::npos || data.find('=') != string::npos)) {
236
237                 string::size_type keypos = min(data.find(' '), data.find('='));
238                 string key = lowercase(data.substr(0, keypos));
239       
240                 data = data.substr(keypos, data.length()-1);
241                 data = frontStrip(strip(data));
242                 if (data.length() > 1 && data[0]=='=') {
243                         data = frontStrip(data.substr(1, data.length()-1));
244                         if (!data.empty()) {
245                                 keypos = 1;
246                                 string value;
247                                 char enclosing;
248
249                                 if (data[0]=='{') {
250                                         enclosing = '}';
251                                 } else if (data[0]=='"') {
252                                         enclosing = '"';
253                                 } else {
254                                         keypos=0;
255                                         enclosing=' ';
256                                 }
257
258                                 if (keypos &&
259                                     data.find(enclosing)!=string::npos &&
260                                     data.length()>1) {
261                                         string tmp = data.substr(keypos,
262                                                                  data.length()-1);
263                                         while (tmp.find('{') != string::npos &&
264                                                tmp.find('}') != string::npos &&
265                                                tmp.find('{') < tmp.find('}') &&
266                                                tmp.find('{') < tmp.find(enclosing)) {
267
268                                                 keypos += tmp.find('{')+1;
269                                                 tmp = data.substr(keypos,
270                                                                   data.length()-1);
271                                                 keypos += tmp.find('}')+1;
272                                                 tmp = data.substr(keypos,
273                                                                   data.length()-1);
274                                         }
275
276                                         if (tmp.find(enclosing)==string::npos)
277                                                 return keyvalue;
278                                         else {
279                                                 keypos += tmp.find(enclosing);
280                                                 tmp = data.substr(keypos,
281                                                                   data.length()-1);
282                                         }
283
284                                         value = data.substr(1, keypos-1);
285
286                                         if (keypos+1<data.length()-1)
287                                                 data = frontStrip(data.substr(keypos+1, data.length()-1));
288                                         else
289                                                 data = "";
290
291                                 } else if (!keypos &&
292                                            (data.find(' ') ||
293                                             data.find(','))) {
294                                         keypos = data.length()-1;
295                                         if (data.find(' ') != string::npos)
296                                                 keypos = data.find(' ');
297                                         if (data.find(',') != string::npos &&
298                                             keypos > data.find(','))
299                                                 keypos = data.find(',');
300
301                                         value = data.substr(0, keypos);
302                   
303                                         if (keypos+1<data.length()-1)
304                                                 data = frontStrip(data.substr(keypos+1, data.length()-1));
305                                         else
306                                                 data = "";
307                                 }
308                                 else
309                                         return keyvalue;
310
311                                 if (findkey == key) {
312                                         keyvalue = value;
313                                         return keyvalue;
314                                 } 
315
316                                 data = frontStrip(frontStrip(data,','));
317                         }
318                 }
319                 else return keyvalue;
320         }
321         return keyvalue;
322 }
323
324
325 } // namespace biblio 
326