#include #include #include #include #include "csv.h" using namespace std; const char *csvProblem = NULL; bool loadCsv(const char *fn, vector > *content) { errno = 0; FILE *in = fopen(fn, "r"); if (!in) { csvProblem = errno ? strerror(errno) : "Can't open file for reading."; return false; } content->clear(); bool readAnotherLine = true; while (readAnotherLine) { vector row; bool readAnotherValue = true; bool foundSomething = false; bool atLeastALineBreak = true; while (readAnotherValue) { bool quoted = false; string valueBuilder; bool readAnotherChar = true; bool readUnquoteCandidate = false; int firstCharOfValue = getc(in); switch (firstCharOfValue) { case EOF: if (ferror(in)) { csvProblem = errno ? strerror(errno) : "Error in reading from file."; fclose(in); // If that fails, what can I do? destroyCsv(content); return false; } else { readAnotherChar = false; readAnotherValue = false; readAnotherLine = false; if (!foundSomething) atLeastALineBreak = false; } break; case '\0': csvProblem = "Null character encountered."; fclose(in); // If that fails, what can I do? destroyCsv(content); return false; case ',': foundSomething = true; readAnotherChar = false; break; case '\"': foundSomething = true; quoted = true; break; case '\n': readAnotherChar = false; readAnotherValue = false; break; default: foundSomething = true; valueBuilder.push_back(firstCharOfValue); } while (readAnotherChar) { int charRead = getc(in); switch (charRead) { case EOF: if (ferror(in)) { csvProblem = errno ? strerror(errno) : "Error in reading from file."; fclose(in); // If that fails, what can I do? destroyCsv(content); return false; } else { readAnotherChar = false; readAnotherValue = false; readAnotherLine = false; } readUnquoteCandidate = false; break; case '\0': csvProblem = "Null character encountered."; fclose(in); // If that fails, what can I do? destroyCsv(content); return false; case ',': if (quoted && !readUnquoteCandidate) valueBuilder.push_back(','); else readAnotherChar = false; readUnquoteCandidate = false; break; case '\"': if (quoted && !readUnquoteCandidate) readUnquoteCandidate = true; else { valueBuilder.push_back('\"'); readUnquoteCandidate = false; } break; case '\n': readAnotherChar = false; readAnotherValue = false; readUnquoteCandidate = false; break; default: if (readUnquoteCandidate) quoted = false; valueBuilder.push_back(charRead); readUnquoteCandidate = false; } } if (foundSomething) { const char *copyMe = valueBuilder.c_str(); char *valueRead = (char*)malloc((strlen(copyMe) + 1) * sizeof(char)); if (!valueRead) { csvProblem = "Not enough memory."; fclose(in); // If that fails, what can I do? destroyCsv(content); return false; } strcpy(valueRead, copyMe); row.push_back(valueRead); } } if (atLeastALineBreak) content->push_back(row); } if (fclose(in) == EOF) { csvProblem = errno ? strerror(errno) : "Error in closing file."; destroyCsv(content); return false; } csvProblem = NULL; return true; } bool saveCsv(const char *fn, vector > *content) { errno = 0; FILE *out = fopen(fn, "w"); if (!out) { csvProblem = errno ? strerror(errno) : "Can't open file for writing."; return false; } for (vector >::iterator i = (*content).begin(); i != (*content).end(); i++) { vector::iterator j = (*i).begin(); while (true) { if (strchr(*j, ',') || strchr(*j, '\"') || *j == '\0') { if (putc('\"', out) == EOF) { csvProblem = strerror(errno); fclose(out); // If that fails, what can I do? return false; } for (const char *k = *j; *k != '\0'; k++) if (*k == '\"') { if (putc('\"', out) == EOF || putc('\"', out) == EOF) { csvProblem = strerror(errno); fclose(out); // If that fails, what can I do? return false; } } else if (putc(*k, out) == EOF) { csvProblem = strerror(errno); fclose(out); // If that fails, what can I do? return false; } if (putc('\"', out) == EOF) { csvProblem = strerror(errno); fclose(out); // If that fails, what can I do? return false; } } else if (fputs(*j, out) == EOF) { csvProblem = errno ? strerror(errno) : "Error in writing to file."; fclose(out); // If that fails, what can I do? return false; } j++; if (j == (*i).end()) break; if (putc(',', out) == EOF) { csvProblem = strerror(errno); fclose(out); // If that fails, what can I do? return false; } } if (putc('\n', out) == EOF) { csvProblem = strerror(errno); fclose(out); // If that fails, what can I do? return false; } } if (fclose(out) == EOF) { csvProblem = errno ? strerror(errno) : "Error in closing file."; return false; } csvProblem = NULL; return true; } void destroyCsv(vector > *content) { for (vector >::iterator i = (*content).begin(); i != (*content).end(); i++) for (vector::iterator j = (*i).begin(); j != (*i).end(); j++) free(*j); content->clear(); }