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