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