1 #include "bibtexparser.h"
2
loadIfModified(const QFileInfo & fi)3 bool BibTeXFileInfo::loadIfModified(const QFileInfo &fi)
4 {
5 QDateTime fileLastModified = fi.lastModified();
6 if (lastModified != fileLastModified) { //load BibTeX iff modified
7 lastModified = fileLastModified;
8 load(fi);
9 return true;
10 }
11 return false;
12 }
13
load(const QFileInfo & fi)14 void BibTeXFileInfo::load(const QFileInfo &fi)
15 {
16 //lastModified=lastModified; see above
17 QFile f(fi.absoluteFilePath());
18 if (!f.open(QFile::ReadOnly)) return; //ups...
19 QByteArray data = f.readAll().trimmed();
20 parse(data);
21 }
22
parse(QByteArray & data)23 void BibTeXFileInfo::parse(QByteArray &data)
24 {
25 ids.clear();
26 linksTo.clear();
27 if (data.startsWith("link ")) {
28 //handle obscure bib tex feature, a just line containing "link fileName"
29 linksTo = QString::fromLatin1(data.constData(), data.count()).mid(5).trimmed();
30 } else {
31 enum BibTeXState {BTS_IN_SPACE, //searches the first @, ignore everything before it
32 BTS_IN_TYPE, //read until bracket ( or { e.g in @article{, reset if @comment
33 BTS_IN_ID, //read everything until bracket close or , and ignore whitespace, reset when = or "
34 BTS_IN_DATA_KEY
35 }; //read balanced bracket until all are closed, then reset
36 enum BibTeXState state = BTS_IN_SPACE;
37 const char *comment = "comment\0";
38 const char *COMMENT = "COMMENT\0";
39 int typeLen = 0;
40 bool commentPossible = false;
41 int bracketBalance = 0;
42 char bracketOpen = 0;
43 char bracketClose = 0;
44 QByteArray curID;
45 for (int j = 0; j < data.count(); j++) {
46 char c = data.at(j);
47 switch (state) {
48 case BTS_IN_SPACE:
49 if (c == '@') {
50 state = BTS_IN_TYPE;
51 commentPossible = true;
52 typeLen = 0;
53 }
54 break;
55 case BTS_IN_TYPE:
56 if (c == '(' || c == '{') {
57 bracketOpen = c;
58 if (c == '(') bracketClose = ')';
59 if (c == '{') bracketClose = '}';
60 bracketBalance = 1;
61 curID = "";
62 state = BTS_IN_ID;
63 } else if (commentPossible && (comment[typeLen] == c || COMMENT[typeLen] == c)) {
64 if (comment[typeLen + 1] == '\0') state = BTS_IN_SPACE; //comment found
65 } else commentPossible = false;
66 typeLen++;
67 break;
68 case BTS_IN_ID:
69 if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
70 if (c == ',' || c == bracketClose) {
71 if (!curID.isEmpty()) {
72 if (codec)
73 ids.insert(codec->toUnicode(curID)); //**found id**
74 else
75 ids.insert(curID);
76 }
77 state = BTS_IN_DATA_KEY;
78 } else if (c == '=' || c == '"')
79 state = BTS_IN_DATA_KEY; //@string or @preamble (don't cite that)
80 else curID += c;
81 }
82 break;
83 case BTS_IN_DATA_KEY:
84 if (c == bracketOpen) bracketBalance++;
85 else if (c == bracketClose) {
86 bracketBalance--;
87 if (bracketBalance <= 0) state = BTS_IN_SPACE;
88 }
89 break;
90 }
91 }
92 }
93 }
94