]> git.lyx.org Git - lyx.git/blob - src/frontends/controllers/biblio.C
* Baruch's GuiBC template.
[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 keys.end();
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         string tmp = expr;
151         if (!caseSensitive)
152                 tmp = lowercase(tmp);
153
154         vector<string> searchwords = getVectorFromString(tmp, " ");
155
156         // Loop over all keys from start...
157         for (vector<string>::const_iterator it = start;
158              // End condition is direction-dependent.
159              (dir == FORWARD) ? (it<keys.end()) : (it>=keys.begin());
160              // increment is direction-dependent.
161              (dir == FORWARD) ? (++it) : (--it)) {
162
163                 string data = (*it);
164                 biblio::InfoMap::const_iterator info = theMap.find(*it);
165                 if (info != theMap.end())
166                         data += " " + info->second;
167                 if (!caseSensitive)
168                         data = lowercase(data);
169
170                 bool found = true;
171
172                 // Loop over all search words...
173                 for (vector<string>::const_iterator sit = searchwords.begin();
174                      sit != searchwords.end(); ++sit) {
175                         if (data.find(*sit) == string::npos) {
176                                 found = false;
177                                 break;
178                         }
179                 }
180                 
181                 if (found) return it;
182         }
183
184         return keys.end();
185 }
186
187
188 vector<string>::const_iterator
189 regexSearch(InfoMap const & theMap,
190             vector<string> const & keys,
191             string const & expr,
192             vector<string>::const_iterator start,
193             Direction dir)
194 {
195         LRegex reg(expr);
196
197         for (vector<string>::const_iterator it = start;
198              // End condition is direction-dependent.
199              (dir == FORWARD) ? (it<keys.end()) : (it>=keys.begin());
200              // increment is direction-dependent.
201              (dir == FORWARD) ? (++it) : (--it)) {
202
203                 string data = (*it);
204                 biblio::InfoMap::const_iterator info = theMap.find(*it);
205                 if (info != theMap.end())
206                         data += " " + info->second;
207
208                 if (reg.exec(data).size() > 0)
209                         return it;
210         }
211
212         return keys.end();
213 }
214
215 string const parseBibTeX(string data, string const & findkey)
216 {
217         string keyvalue;
218         
219         for (string::iterator it=data.begin(); it<data.end(); ++it) {
220                 if ((*it) == '\n' || (*it) == '\t')
221                         (*it)= ' ';
222         }
223         
224         data = frontStrip(data);
225         while (!data.empty() && data[0] != '=' && 
226                (data.find(' ') != string::npos || data.find('=') != string::npos)) {
227
228                 string::size_type keypos = min(data.find(' '), data.find('='));
229                 string key = lowercase(data.substr(0, keypos));
230       
231                 data = data.substr(keypos, data.length()-1);
232                 data = frontStrip(strip(data));
233                 if (data.length() > 1 && data[0]=='=') {
234                         data = frontStrip(data.substr(1, data.length()-1));
235                         if (!data.empty()) {
236                                 keypos = 1;
237                                 string value;
238                                 char enclosing;
239
240                                 if (data[0]=='{') {
241                                         enclosing = '}';
242                                 } else if (data[0]=='"') {
243                                         enclosing = '"';
244                                 } else {
245                                         keypos=0;
246                                         enclosing=' ';
247                                 }
248
249                                 if (keypos &&
250                                     data.find(enclosing)!=string::npos &&
251                                     data.length()>1) {
252                                         string tmp = data.substr(keypos,
253                                                                  data.length()-1);
254                                         while (tmp.find('{') != string::npos &&
255                                                tmp.find('}') != string::npos &&
256                                                tmp.find('{') < tmp.find('}') &&
257                                                tmp.find('{') < tmp.find(enclosing)) {
258
259                                                 keypos += tmp.find('{')+1;
260                                                 tmp = data.substr(keypos,
261                                                                   data.length()-1);
262                                                 keypos += tmp.find('}')+1;
263                                                 tmp = data.substr(keypos,
264                                                                   data.length()-1);
265                                         }
266
267                                         if (tmp.find(enclosing)==string::npos)
268                                                 return keyvalue;
269                                         else {
270                                                 keypos += tmp.find(enclosing);
271                                                 tmp = data.substr(keypos,
272                                                                   data.length()-1);
273                                         }
274
275                                         value = data.substr(1, keypos-1);
276
277                                         if (keypos+1<data.length()-1)
278                                                 data = frontStrip(data.substr(keypos+1, data.length()-1));
279                                         else
280                                                 data = "";
281
282                                 } else if (!keypos &&
283                                            (data.find(' ') ||
284                                             data.find(','))) {
285                                         keypos = data.length()-1;
286                                         if (data.find(' ') != string::npos)
287                                                 keypos = data.find(' ');
288                                         if (data.find(',') != string::npos &&
289                                             keypos > data.find(','))
290                                                 keypos = data.find(',');
291
292                                         value = data.substr(0, keypos);
293                   
294                                         if (keypos+1<data.length()-1)
295                                                 data = frontStrip(data.substr(keypos+1, data.length()-1));
296                                         else
297                                                 data = "";
298                                 }
299                                 else
300                                         return keyvalue;
301
302                                 if (findkey == key) {
303                                         keyvalue = value;
304                                         return keyvalue;
305                                 } 
306
307                                 data = frontStrip(frontStrip(data,','));
308                         }
309                 }
310                 else return keyvalue;
311         }
312         return keyvalue;
313 }
314
315
316 } // namespace biblio 
317