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