summaryrefslogtreecommitdiff
path: root/ept/apt/recordparser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ept/apt/recordparser.cc')
-rw-r--r--ept/apt/recordparser.cc170
1 files changed, 170 insertions, 0 deletions
diff --git a/ept/apt/recordparser.cc b/ept/apt/recordparser.cc
new file mode 100644
index 0000000..3562123
--- /dev/null
+++ b/ept/apt/recordparser.cc
@@ -0,0 +1,170 @@
+/** \file
+ * Parser for APT records
+ */
+
+/*
+ * Copyright (C) 2007 Enrico Zini <enrico@enricozini.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <ept/apt/recordparser.h>
+
+#include <algorithm>
+#include <cctype>
+
+//#include <iostream>
+
+using namespace std;
+
+namespace ept {
+namespace apt {
+
+struct rpcompare
+{
+ const RecordParser& rp;
+ rpcompare(const RecordParser& rp) : rp(rp) {}
+ bool operator()(size_t a, size_t b)
+ {
+ return rp.name(a) < rp.name(b);
+ }
+};
+
+void RecordParser::scan(const std::string& str)
+{
+ buffer = str;
+ ends.clear();
+ sorted.clear();
+
+ //cerr << "PARSE " << endl << buffer << "*****" << endl;
+
+ // Scan the buffer, taking note of all ending offsets of the various fields
+ size_t pos = 0;
+ size_t idx = 0;
+ while (pos < buffer.size() - 1)
+ {
+ //cerr << "PREPOS " << pos << " left: " << buffer.substr(pos, 10) << endl;
+ pos = buffer.find("\n", pos);
+ //cerr << "POSTPOS " << pos << " left: " << (pos == string::npos ? "NONE" : buffer.substr(pos, 10)) << endl;
+
+ // The buffer does not end with a newline
+ if (pos == string::npos)
+ {
+ //cerr << "ENDNOTEOL" << endl;
+ pos = buffer.size();
+ ends.push_back(pos);
+ sorted.push_back(idx++);
+ break;
+ }
+
+ ++pos;
+ //cerr << "POSTPOSINC " << pos << " left: " << buffer.substr(pos, 10) << endl;
+
+ // The buffer ends with a newline
+ if (pos == buffer.size())
+ {
+ //cerr << "ENDEOL" << endl;
+ ends.push_back(pos);
+ sorted.push_back(idx++);
+ break;
+ }
+
+ // Terminate parsing on double newlines
+ if (buffer[pos] == '\n')
+ {
+ //cerr << "ENDDOUBLENL" << endl;
+ ends.push_back(pos);
+ sorted.push_back(idx++);
+ break;
+ }
+
+ // Mark the end of the field if it's not a continuation line
+ if (!isspace(buffer[pos]))
+ {
+ //cerr << "INNERFIELD" << endl;
+ ends.push_back(pos);
+ sorted.push_back(idx++);
+ } //else
+ //cerr << "CONTLINE" << endl;
+ }
+
+ // Sort the sorted array
+ sort(sorted.begin(), sorted.end(), rpcompare(*this));
+
+ //for (size_t i = 0; i < ends.size(); ++i)
+ // cerr << ends[i] << "\t" << name(i) << "\t" << sorted[i] << "\t" << name(sorted[i]) << endl;
+}
+
+std::string RecordParser::field(size_t idx) const
+{
+ if (idx >= ends.size())
+ return string();
+ if (idx == 0)
+ return buffer.substr(0, ends[0]);
+ else
+ return buffer.substr(ends[idx-1], ends[idx]-ends[idx-1]);
+}
+
+std::string RecordParser::name(size_t idx) const
+{
+ string res = field(idx);
+ size_t pos = res.find(":");
+ if (pos == string::npos)
+ return res;
+ return res.substr(0, pos);
+}
+
+std::string RecordParser::lookup(size_t idx) const
+{
+ string res = field(idx);
+ size_t pos = res.find(":");
+ if (pos == string::npos)
+ return res;
+ // Skip initial whitespace after the :
+ for (++pos; pos < res.size() && isspace(res[pos]); ++pos)
+ ;
+ res = res.substr(pos);
+ // Trim spaces at the end
+ while (!res.empty() && isspace(res[res.size() - 1]))
+ res.resize(res.size() - 1);
+ return res;
+}
+
+size_t RecordParser::index(const std::string& str) const
+{
+ int begin, end;
+
+ /* Binary search */
+ begin = -1, end = size();
+ while (end - begin > 1)
+ {
+ int cur = (end + begin) / 2;
+ //cerr << "Test " << cur << " " << str << " < " << name(cur) << endl;
+ if (name(sorted[cur]) > str)
+ end = cur;
+ else
+ begin = cur;
+ }
+
+ if (begin == -1 || name(sorted[begin]) != str)
+ return size();
+ else
+ return sorted[begin];
+}
+
+}
+}
+
+// vim:set ts=4 sw=4: