summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Client/CMakeLists.txt2
-rw-r--r--src/Client/UserListCommands.cpp268
-rw-r--r--src/Client/UserListCommands.h12
-rw-r--r--src/Client/XLSReader.cpp89
-rw-r--r--src/Client/XLSReader.h57
-rw-r--r--src/Client/XLSSheet.cpp109
-rw-r--r--src/Client/XLSSheet.h91
-rw-r--r--src/madc.cpp2
8 files changed, 571 insertions, 59 deletions
diff --git a/src/Client/CMakeLists.txt b/src/Client/CMakeLists.txt
index 4e83c4e..30fb722 100644
--- a/src/Client/CMakeLists.txt
+++ b/src/Client/CMakeLists.txt
@@ -22,5 +22,7 @@ mad_library(Client
SystemCommands.cpp SystemCommands.h
UserCommands.cpp UserCommands.h
UserListCommands.cpp UserListCommands.h
+ XLSReader.cpp XLSReader.h
+ XLSSheet.cpp XLSSheet.h
)
target_link_libraries(Client Common Net Core)
diff --git a/src/Client/UserListCommands.cpp b/src/Client/UserListCommands.cpp
index ad0c2d0..7774240 100644
--- a/src/Client/UserListCommands.cpp
+++ b/src/Client/UserListCommands.cpp
@@ -19,6 +19,8 @@
#include "UserListCommands.h"
#include "Application.h"
+#include "XLSReader.h"
+#include "XLSSheet.h"
#include "Requests/UserLists/UserListListRequest.h"
#include "Requests/UserLists/UserListDownloadRequest.h"
#include "Requests/UserLists/UserListDiffListRequest.h"
@@ -36,6 +38,7 @@ const UserListCommands::Command UserListCommands::commands[] = {
{{"help", "?", 0}, "help [command]", "Display usage information about user list commands", "Display usage information about a user list command. If no command is given, display a list of all available user list commands.", &UserListCommands::helpCommand},
{{"list", "ls", 0}, "list", "List the stored user lists", "List the stored user lists.", &UserListCommands::listCommand},
{{"show_list", "sl", 0}, "show_list list", "Displays a user list", "Displays a user list.", &UserListCommands::showListCommand},
+ {{"import", "im", 0}, "import filename", "Imports a user list file", "Imports a user list file. At the moment, this supports only XLS files.", &UserListCommands::importCommand},
{{0}, 0, 0, 0, 0}
};
@@ -173,90 +176,239 @@ void UserListCommands::showListCommand(CommandParser *commandParser, const std::
std::cout << "s";
std::cout << "." << std::endl << std::endl;
- std::map<std::string, unsigned> lengths;
+ printUserList(*userList);
+ }
- static const std::string USER_NAME("User name");
- lengths.insert(std::make_pair(USER_NAME, USER_NAME.length()));
- static const std::string GROUP_NAME("Group name");
- lengths.insert(std::make_pair(GROUP_NAME, GROUP_NAME.length()));
+ std::cout << std::endl;
+ }
+ else {
+ std::cerr << args[0] << " " << args[1] << ": Too many arguments." << std::endl;
+ printUsage("show_list");
+ return;
+ }
+}
- std::set<std::string> details = userList->getDetails();
- for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
- lengths.insert(std::make_pair(*detail, detail->length()));
+void UserListCommands::importCommand(CommandParser* /*commandParser*/, const std::vector<std::string> &args) {
+ if(args.size() < 3) {
+ std::cerr << args[0] << " " << args[1] << ": No filename given." << std::endl;
+ printUsage("import");
+ return;
+ }
+ else if(args.size() == 3) {
+ try {
+ XLSReader reader(args[2]);
+ const std::list<boost::shared_ptr<XLSSheet> > &sheets = reader.getSheets();
+
+ if(sheets.empty()) {
+ std::cerr << "There aren't any worksheets in the file." << std::endl;
+ return;
}
- for(Common::UserLists::UserList::iterator user = userList->begin(); user != userList->end(); ++user) {
- std::map<std::string, unsigned>::iterator it = lengths.find(USER_NAME);
- if(user->getName().length() > it->second)
- it->second = user->getName().length();
+ unsigned long sheetNum = 1;
+
+ if(sheets.size() > 1) {
+ std::cout << "There is more than one worksheet in the file. Which one do you want to import?" << std::endl << std::endl;
+
+ while(true) {
+ int i = 1;
+ for(std::list<boost::shared_ptr<XLSSheet> >::const_iterator sheet = sheets.begin(); sheet != sheets.end(); ++sheet, ++i) {
+ std::cout << " " << i << ") " << (*sheet)->getTitle() << std::endl;
+ }
- it = lengths.find(GROUP_NAME);
- if(user->getGroup().length() > it->second)
- it->second = user->getGroup().length();
+ std::cout << std::endl;
+ std::cout << "Worksheet number: " << std::flush;
- for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
- it = lengths.find(*detail);
- std::string detailStr = user->getDetail(*detail);
- if(detailStr.length() > it->second)
- it->second = detailStr.length();
+ std::string input;
+ std::getline(std::cin, input);
+ sheetNum = std::strtoul(input.c_str(), 0, 10);
+
+ if(sheetNum > 0 && sheetNum <= sheets.size())
+ break;
+
+ std::cout << "Invalid selection. Please choose one of:" << std::endl << std::endl;
}
}
- std::cout << " ";
- printPadded(USER_NAME, lengths.find(USER_NAME)->second);
- std::cout << " ";
- printPadded(GROUP_NAME, lengths.find(GROUP_NAME)->second);
- for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
- std::cout << " ";
- printPadded(*detail, lengths.find(*detail)->second);
- }
- std::cout << std::endl;
-
- std::cout << "-";
- printDelimiter(lengths.find(USER_NAME)->second);
- std::cout << "- -";
- printDelimiter(lengths.find(GROUP_NAME)->second);
- for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
- std::cout << "- -";
- printDelimiter(lengths.find(*detail)->second);
- }
- std::cout << "-" << std::endl;
+ std::list<boost::shared_ptr<XLSSheet> >::const_iterator sheet = sheets.begin();
+ std::advance(sheet, sheetNum-1);
- for(Common::UserLists::UserList::iterator user = userList->begin(); user != userList->end(); ++user) {
- static const std::string UNSET("<unset>");
+ std::cout << "Imported worksheet:" << std::endl;
+ printSheet(**sheet, 10);
- std::cout << " ";
+ std::cout << std::endl << std::endl;
+ std::cout << "Does the first line of the worksheet contain the column names? (Y/n) " << std::flush;
- if(!user->getName().empty())
- printPadded(user->getName(), lengths.find(USER_NAME)->second);
- else
- printPadded(UNSET, lengths.find(USER_NAME)->second);
+ std::string input;
+ std::getline(std::cin, input);
+ if(input.empty() || (input[0] != 'n' && input[0] != 'N')) {
+ (*sheet)->useFirstRowAsColumnNames(true);
+ }
+
+ std::cout << std::endl << std ::endl;
+ printSheet(**sheet, 10);
+ std::cout << std::endl << std ::endl;
+
+ Common::UserLists::UserList userList;
+ const std::vector<XLSSheet::RowType> &rows = (*sheet)->getRows();
+ unsigned id = 1;
- std::cout << " ";
+ for(std::vector<XLSSheet::RowType>::const_iterator rowIt = rows.begin(); rowIt != rows.end(); ++rowIt, ++id) {
+ const std::vector<std::string> &row = **rowIt;
+ Common::UserLists::UserListEntry entry;
- if(!user->getGroup().empty())
- printPadded(user->getGroup(), lengths.find(GROUP_NAME)->second);
- else
- printPadded(UNSET, lengths.find(GROUP_NAME)->second);
+ std::ostringstream stream;
+ stream << id;
+ entry.setName(stream.str());
- for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
- std::cout << " ";
- printPadded(user->getDetail(*detail), lengths.find(*detail)->second);
+ for(unsigned col = 0; col < (*sheet)->getColumnCount(); ++col) {
+ entry.setDetail((*sheet)->getColumnName(col), row[col]);
}
- std::cout << std::endl;
+ userList.addUser(entry);
}
- }
- std::cout << std::endl;
+ printUserList(userList);
+ std::cout << std::endl << std ::endl;
+ }
+ catch(Core::Exception e) {
+ std::cerr << "The file can't be read: " << e.what() << "." << std::endl;
+ }
}
else {
std::cerr << args[0] << " " << args[1] << ": Too many arguments." << std::endl;
- printUsage("show_list");
+ printUsage("import");
return;
}
}
+
+void UserListCommands::printUserList(const Common::UserLists::UserList &list) {
+ std::map<std::string, unsigned> lengths;
+
+ static const std::string USER_NAME = "User name";
+ static const std::string GROUP_NAME = "Group name";
+
+ lengths.insert(std::make_pair(USER_NAME, USER_NAME.length()));
+ lengths.insert(std::make_pair(GROUP_NAME, GROUP_NAME.length()));
+
+ std::set<std::string> details = list.getDetails();
+ for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
+ lengths.insert(std::make_pair(*detail, detail->length()));
+ }
+
+ for(Common::UserLists::UserList::const_iterator user = list.begin(); user != list.end(); ++user) {
+ std::map<std::string, unsigned>::iterator it = lengths.find(USER_NAME);
+ if(user->getName().length() > it->second)
+ it->second = user->getName().length();
+
+ it = lengths.find(GROUP_NAME);
+ if(user->getGroup().length() > it->second)
+ it->second = user->getGroup().length();
+
+ for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
+ it = lengths.find(*detail);
+ std::string detailStr = user->getDetail(*detail);
+ if(detailStr.length() > it->second)
+ it->second = detailStr.length();
+ }
+ }
+
+ std::cout << " ";
+ printPadded(USER_NAME, lengths.find(USER_NAME)->second);
+ std::cout << " ";
+ printPadded(GROUP_NAME, lengths.find(GROUP_NAME)->second);
+ for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
+ std::cout << " ";
+ printPadded(*detail, lengths.find(*detail)->second);
+ }
+ std::cout << std::endl;
+
+ std::cout << "-";
+ printDelimiter(lengths.find(USER_NAME)->second);
+ std::cout << "- -";
+ printDelimiter(lengths.find(GROUP_NAME)->second);
+ for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
+ std::cout << "- -";
+ printDelimiter(lengths.find(*detail)->second);
+ }
+ std::cout << "-" << std::endl;
+
+ for(Common::UserLists::UserList::const_iterator user = list.begin(); user != list.end(); ++user) {
+ static const std::string UNSET("<unset>");
+
+ std::cout << " ";
+
+ if(!user->getName().empty())
+ printPadded(user->getName(), lengths.find(USER_NAME)->second);
+ else
+ printPadded(UNSET, lengths.find(USER_NAME)->second);
+
+ std::cout << " ";
+
+ if(!user->getGroup().empty())
+ printPadded(user->getGroup(), lengths.find(GROUP_NAME)->second);
+ else
+ printPadded(UNSET, lengths.find(GROUP_NAME)->second);
+
+ for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
+ std::cout << " ";
+ printPadded(user->getDetail(*detail), lengths.find(*detail)->second);
+ }
+
+ std::cout << std::endl;
+ }
+}
+
+void UserListCommands::printSheet(const XLSSheet &sheet, unsigned rowCount) {
+ const std::vector<XLSSheet::RowType> &rows = sheet.getRows();
+ std::vector<unsigned> lengths(sheet.getColumnCount());
+
+ for(unsigned col = 0; col < sheet.getColumnCount(); ++col) {
+ lengths[col] = sheet.getColumnName(col).size();
+ }
+
+ for(std::vector<XLSSheet::RowType>::const_iterator rowIt = rows.begin(); rowIt != rows.end() && (rowCount == 0 || rowIt != rows.begin()+rowCount); ++rowIt) {
+ const std::vector<std::string> &row = **rowIt;
+
+ for(unsigned col = 0; col < sheet.getColumnCount(); ++col) {
+ if(row[col].size() > lengths[col])
+ lengths[col] = row[col].size();
+ }
+ }
+
+ for(unsigned col = 0; col < sheet.getColumnCount(); ++col) {
+ std::cout << " ";
+ printPadded(sheet.getColumnName(col), lengths[col]);
+ }
+ std::cout << std::endl;
+
+ std::cout << " ";
+ for(unsigned col = 0; col < sheet.getColumnCount(); ++col) {
+ std::cout << " -";
+ printDelimiter(lengths[col]);
+ std::cout << "-";
+ }
+ std::cout << std::endl;
+
+ for(std::vector<XLSSheet::RowType>::const_iterator rowIt = rows.begin(); rowIt != rows.end() && (rowCount == 0 || rowIt != rows.begin()+rowCount); ++rowIt) {
+ const std::vector<std::string> &row = **rowIt;
+
+ for(unsigned col = 0; col < sheet.getColumnCount(); ++col) {
+ std::cout << " ";
+ printPadded(row[col], lengths[col]);
+ }
+
+ std::cout << std::endl;
+ }
+
+ if(rowCount > 0 && rows.size() > rowCount) {
+ for(unsigned col = 0; col < sheet.getColumnCount(); ++col) {
+ std::cout << " ";
+ printPadded("...", lengths[col]);
+ }
+ }
+}
+
void UserListCommands::printPadded(const std::string &str, unsigned length) {
std::cout << str;
if(str.length() < length)
diff --git a/src/Client/UserListCommands.h b/src/Client/UserListCommands.h
index 51a714b..8c77e7f 100644
--- a/src/Client/UserListCommands.h
+++ b/src/Client/UserListCommands.h
@@ -25,8 +25,17 @@
#include "CommandParser.h"
namespace Mad {
+
+namespace Common {
+namespace UserLists {
+class UserList;
+}
+}
+
namespace Client {
+class XLSSheet;
+
class MAD_CLIENT_EXPORT UserListCommands {
private:
typedef CommandParser::Command Command;
@@ -41,7 +50,10 @@ class MAD_CLIENT_EXPORT UserListCommands {
static void helpCommand(CommandParser *commandParser, const std::vector<std::string> &args);
static void listCommand(CommandParser *commandParser, const std::vector<std::string> &args);
static void showListCommand(CommandParser *commandParser, const std::vector<std::string> &args);
+ static void importCommand(CommandParser *commandParser, const std::vector<std::string> &args);
+ static void printUserList(const Common::UserLists::UserList &list);
+ static void printSheet(const XLSSheet &sheet, unsigned rowCount = 0);
static void printPadded(const std::string &str, unsigned length);
static void printDelimiter(unsigned length);
diff --git a/src/Client/XLSReader.cpp b/src/Client/XLSReader.cpp
new file mode 100644
index 0000000..9bd9dda
--- /dev/null
+++ b/src/Client/XLSReader.cpp
@@ -0,0 +1,89 @@
+/*
+ * XLSReader.cpp
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "XLSReader.h"
+#include "XLSSheet.h"
+
+#include <cstdio>
+#include <boost/filesystem.hpp>
+#include <boost/regex.hpp>
+
+namespace Mad {
+namespace Client {
+
+xmlNodePtr XLSReader::findNode(xmlNodePtr parent, const std::string &name) {
+ if(!parent)
+ return 0;
+
+ for(xmlNodePtr entry = parent->children; entry != 0; entry = entry->next) {
+ if(entry->type == XML_ELEMENT_NODE && !xmlStrcmp(entry->name, (xmlChar*)name.c_str())) {
+ return entry;
+ }
+ }
+
+ return 0;
+}
+
+XLSReader::XLSReader(const std::string &filename) throw (Core::Exception) {
+ static const std::string XLHTML_EXEC = "xlhtml -xml";
+ static const boost::regex r("'");
+
+ if(!boost::filesystem::exists(filename))
+ throw Core::Exception(Core::Exception::NOT_FOUND);
+
+ std::string escapedFilename = boost::regex_replace(filename, r, "\\\\'", boost::match_default);
+
+ std::FILE *stream = popen((XLHTML_EXEC + " '" + escapedFilename + "' 2>&1").c_str(), "r");
+
+ std::string data;
+
+ while(!std::feof(stream)) {
+ char buffer[1024];
+
+ size_t bytes = std::fread(buffer, 1, sizeof(buffer), stream);
+ if(!bytes)
+ break;
+
+ data += std::string(buffer, bytes);
+ }
+
+ int ret = pclose(stream);
+ if(!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) {
+ throw Core::Exception(Core::Exception::INVALID_INPUT);
+ }
+
+ doc.reset(xmlParseMemory(data.c_str(), data.length()), xmlFreeDoc);
+ if(!doc) {
+ throw Core::Exception(Core::Exception::NOT_AVAILABLE);
+ }
+
+ xmlNodePtr sheetsNode = findNode(xmlDocGetRootElement(doc.get()), "sheets");
+
+ if(!sheetsNode) {
+ throw Core::Exception(Core::Exception::NOT_AVAILABLE);
+ }
+
+ for(xmlNodePtr entry = sheetsNode->children; entry != 0; entry = entry->next) {
+ if(entry->type == XML_ELEMENT_NODE && !xmlStrcmp(entry->name, (xmlChar*)"sheet"))
+ sheets.push_back(boost::shared_ptr<XLSSheet>(new XLSSheet(doc, entry)));
+ }
+}
+
+}
+}
diff --git a/src/Client/XLSReader.h b/src/Client/XLSReader.h
new file mode 100644
index 0000000..8c7b11a
--- /dev/null
+++ b/src/Client/XLSReader.h
@@ -0,0 +1,57 @@
+/*
+ * XLSReader.h
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CLIENT_XLSREADER_H_
+#define MAD_CLIENT_XLSREADER_H_
+
+#include "export.h"
+
+#include <Core/Exception.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <list>
+#include <libxml/parser.h>
+
+namespace Mad {
+namespace Client {
+
+class XLSSheet;
+
+class MAD_CLIENT_EXPORT XLSReader : private boost::noncopyable {
+ private:
+ friend class XLSSheet;
+
+ boost::shared_ptr<xmlDoc> doc;
+ std::list<boost::shared_ptr<XLSSheet> > sheets;
+
+ static xmlNodePtr findNode(xmlNodePtr parent, const std::string &name);
+
+ public:
+ XLSReader(const std::string &filename) throw (Core::Exception);
+
+ const std::list<boost::shared_ptr<XLSSheet> >& getSheets() const {
+ return sheets;
+ }
+};
+
+}
+}
+
+#endif /* MAD_CLIENT_XLSREADER_H_ */
diff --git a/src/Client/XLSSheet.cpp b/src/Client/XLSSheet.cpp
new file mode 100644
index 0000000..915234f
--- /dev/null
+++ b/src/Client/XLSSheet.cpp
@@ -0,0 +1,109 @@
+/*
+ * XLSSheet.cpp
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "XLSSheet.h"
+#include "XLSReader.h"
+
+#include <cstdlib>
+#include <sstream>
+
+namespace Mad {
+namespace Client {
+
+std::string XLSSheet::getSheetLevelField(const std::string &name) const {
+ xmlNodePtr entry = XLSReader::findNode(node, name);
+ if(entry)
+ return std::string((char*)xmlNodeGetContent(entry));
+ else
+ return std::string();
+}
+
+void XLSSheet::readRows() {
+ rows.clear();
+
+ xmlNodePtr rowsNode = XLSReader::findNode(node, "rows");
+
+ xmlNodePtr rowEntry = rowsNode->children;
+
+ if(firstRowColNames) {
+ for(; rowEntry != 0; rowEntry = rowEntry->next) {
+ if(rowEntry->type != XML_ELEMENT_NODE || xmlStrcmp(rowEntry->name, (xmlChar*)"row"))
+ continue;
+
+ for(xmlNodePtr cellEntry = rowEntry->children; cellEntry != 0; cellEntry = cellEntry->next) {
+ if(cellEntry->type != XML_ELEMENT_NODE || xmlStrcmp(cellEntry->name, (xmlChar*)"cell"))
+ continue;
+
+ xmlChar *colStr = xmlGetProp(cellEntry, (xmlChar*)"col");
+ if(!colStr)
+ continue;
+
+ unsigned long col = strtoul((char*)colStr, 0, 10);
+ if(col >= colCount)
+ continue;
+
+ colNames[col] = (char*)xmlNodeGetContent(cellEntry);
+ }
+
+ // Skip the first row
+ rowEntry = rowEntry->next;
+ break;
+ }
+ }
+
+ for(; rowEntry != 0; rowEntry = rowEntry->next) {
+ if(rowEntry->type != XML_ELEMENT_NODE || xmlStrcmp(rowEntry->name, (xmlChar*)"row"))
+ continue;
+
+ boost::shared_ptr<std::vector<std::string> > rowVector(new std::vector<std::string>(colCount));
+ rows.push_back(rowVector);
+
+ for(xmlNodePtr cellEntry = rowEntry->children; cellEntry != 0; cellEntry = cellEntry->next) {
+ if(cellEntry->type != XML_ELEMENT_NODE || xmlStrcmp(cellEntry->name, (xmlChar*)"cell"))
+ continue;
+
+ xmlChar *colStr = xmlGetProp(cellEntry, (xmlChar*)"col");
+ if(!colStr)
+ continue;
+
+ unsigned long col = strtoul((char*)colStr, 0, 10);
+ if(col >= colCount)
+ continue;
+
+ (*rowVector)[col] = (char*)xmlNodeGetContent(cellEntry);
+ }
+ }
+}
+
+XLSSheet::XLSSheet(boost::shared_ptr<xmlDoc> doc0, xmlNodePtr node0) : doc(doc0), node(node0), firstRowColNames(false) {
+ title = getSheetLevelField("pagetitle");
+ colCount = std::strtoul(getSheetLevelField("lastcol").c_str(), 0, 10)+1-std::strtoul(getSheetLevelField("firstcol").c_str(), 0, 10);
+
+ for(unsigned col = 0; col < colCount; ++col) {
+ std::ostringstream stream;
+ stream << col;
+
+ colNames.push_back(stream.str());
+ }
+
+ readRows();
+}
+
+}
+}
diff --git a/src/Client/XLSSheet.h b/src/Client/XLSSheet.h
new file mode 100644
index 0000000..3038fdc
--- /dev/null
+++ b/src/Client/XLSSheet.h
@@ -0,0 +1,91 @@
+/*
+ * XLSSheet.h
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CLIENT_XLSSHEET_H_
+#define MAD_CLIENT_XLSSHEET_H_
+
+#include "export.h"
+
+#include <string>
+#include <vector>
+
+#include <boost/noncopyable.hpp>
+#include <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
+#include <libxml/parser.h>
+
+namespace Mad {
+namespace Client {
+
+class XLSReader;
+
+class MAD_CLIENT_EXPORT XLSSheet : private boost::noncopyable {
+ public:
+ typedef boost::shared_ptr<const std::vector<std::string> > RowType;
+
+ private:
+ friend class XLSReader;
+
+ boost::shared_ptr<xmlDoc> doc;
+ xmlNodePtr node;
+
+ std::string title;
+ size_t colCount;
+
+ std::vector<RowType> rows;
+ std::vector<std::string> colNames;
+
+ bool firstRowColNames;
+
+ XLSSheet(boost::shared_ptr<xmlDoc> doc0, xmlNodePtr node0);
+
+ std::string getSheetLevelField(const std::string &name) const;
+
+ void readRows();
+
+ public:
+ void useFirstRowAsColumnNames(bool useFirstRowColNames) {
+ if(firstRowColNames == useFirstRowColNames)
+ return;
+
+ firstRowColNames = useFirstRowColNames;
+ readRows();
+ }
+
+ const std::string& getTitle() const {
+ return title;
+ }
+
+ size_t getColumnCount() const {
+ return colCount;
+ }
+
+ const std::string& getColumnName(unsigned col) const {
+ return colNames[col];
+ }
+
+ const std::vector<RowType>& getRows() const {
+ return rows;
+ }
+};
+
+}
+}
+
+#endif /* MAD_CLIENT_XLSSHEET_H_ */
diff --git a/src/madc.cpp b/src/madc.cpp
index fc95266..eaa1613 100644
--- a/src/madc.cpp
+++ b/src/madc.cpp
@@ -127,7 +127,7 @@ int main(int argc, char *argv[]) {
EditLine *el = el_init(argv[0], stdin, stdout, stderr);
- el_set(el, EL_EDITOR, "emacs");
+ el_set(el, EL_EDITOR, "vi");
el_set(el, EL_PROMPT, &prompt);
HistEvent histEv;