File indexing completed on 2024-05-12 05:10:09

0001 /***************************************************************************
0002     Copyright (C) 2009 Robby Stephenson <robby@periapsis.org>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 #include "csvparser.h"
0026 
0027 #include <QTextStream>
0028 #include <QStringList>
0029 
0030 #include <config.h>
0031 
0032 extern "C" {
0033 #ifdef HAVE_LIBCSV
0034 #include <csv.h>
0035 #else
0036 #include "libcsv/libcsv.h"
0037 #endif
0038 }
0039 
0040 typedef int(*SpaceFunc)(char);
0041 
0042 static void writeToken(void* buffer, size_t len, void* data);
0043 static void writeRow(int buffer, void* data);
0044 static int isSpace(unsigned char c);
0045 static int isSpaceOrTab(unsigned char c);
0046 static int isTab(unsigned char c);
0047 
0048 using Tellico::CSVParser;
0049 
0050 class CSVParser::Private {
0051 public:
0052   Private() : stream(nullptr), done(false) {
0053     csv_init(&parser, 0);
0054   }
0055   ~Private() {
0056     csv_free(&parser);
0057     delete stream;
0058   }
0059 
0060   struct csv_parser parser;
0061   QString str;
0062   QTextStream* stream;
0063   QStringList tokens;
0064   bool done;
0065 };
0066 
0067 CSVParser::CSVParser(QString str) : d(new Private()) {
0068   reset(str);
0069 }
0070 
0071 CSVParser::~CSVParser() {
0072   delete d;
0073 }
0074 
0075 void CSVParser::setDelimiter(const QString& s) {
0076   Q_ASSERT(s.length() == 1);
0077   csv_set_delim(&d->parser, s[0].toLatin1());
0078   if(s[0] == QLatin1Char('\t'))     csv_set_space_func(&d->parser, isSpace);
0079   else if(s[0] == QLatin1Char(' ')) csv_set_space_func(&d->parser, isTab);
0080   else                              csv_set_space_func(&d->parser, isSpaceOrTab);
0081 }
0082 
0083 void CSVParser::reset(QString str) {
0084   delete d->stream;
0085   d->str = str;
0086   d->stream = new QTextStream(&d->str);
0087 }
0088 
0089 bool CSVParser::hasNext() const {
0090   return !d->stream->atEnd();
0091 }
0092 
0093 void CSVParser::skipLine() {
0094   d->stream->readLine();
0095 }
0096 
0097 void CSVParser::addToken(const QString& t) {
0098   d->tokens += t;
0099 }
0100 
0101 void CSVParser::setRowDone(bool b) {
0102   d->done = b;
0103 }
0104 
0105 QStringList CSVParser::nextTokens() {
0106   d->tokens.clear();
0107   d->done = false;
0108   while(hasNext() && !d->done) {
0109     QByteArray line = d->stream->readLine().toUtf8() + '\n'; // need the eol char
0110     csv_parse(&d->parser, line.constData(), line.length(), &writeToken, &writeRow, this);
0111   }
0112   csv_fini(&d->parser, &writeToken, &writeRow, this);
0113   return d->tokens;
0114 }
0115 
0116 static void writeToken(void* buffer, size_t len, void* data) {
0117   CSVParser* p = static_cast<CSVParser*>(data);
0118   p->addToken(QString::fromUtf8((char *)buffer, len));
0119 }
0120 
0121 static void writeRow(int c, void* data) {
0122   Q_UNUSED(c);
0123   CSVParser* p = static_cast<CSVParser*>(data);
0124   p->setRowDone(true);
0125 }
0126 
0127 static int isSpace(unsigned char c) {
0128   if (c == CSV_SPACE) return 1;
0129   return 0;
0130 }
0131 
0132 static int isSpaceOrTab(unsigned char c) {
0133   if (c == CSV_SPACE || c == CSV_TAB) return 1;
0134   return 0;
0135 }
0136 
0137 static int isTab(unsigned char c) {
0138   if (c == CSV_TAB) return 1;
0139   return 0;
0140 }