#include "Table.h" #include "CellDouble.h" #include "CellInt.h" #include "CellString.h" #include "CellFormula.h" #include #include #include #include #include // TODO: remove // Rough implementation of the grammar // // S -> W"=A",S | W"A",S | WPD,S | WPD.D,S | ,S | epsilon // A -> Aa | Ab | ... | AZ | A0 | A1 | ... | A* | ... | a | b | ... | epsilon // D -> D0 | D1 | ... | D9 | 0 | 1 | ... | 9 // P -> + | - | epsilon // W -> W | epsilon // // over the input file stream void W(std::ifstream& in) { while (in.peek() == ' ') in.get(); } void P(std::ifstream& in, List& buffer) { if (in.peek() == '-' || in.peek() == '+') buffer.add(in.get()); } void D(std::ifstream& in, List& buffer) { while (in.peek() >= '0' && in.peek() <= '9') buffer.add(in.get()); } void A(std::ifstream& in, List& buffer) { while ((in.peek() >= ' ' && in.peek() <= '~') && in.peek() != '"') { if (in.peek() == '\\') in.get(); buffer.add(in.get()); } } void throwException(std::ifstream& inFile, unsigned row) { row++; throw std::logic_error(( (((((String("Error: Invalid character '") += (char)inFile.peek()) += "' at row ") += row) += " and column ") += ((int)inFile.tellg() / row + 1)) ).get_cstr()); } void Table::readFromFile(std::ifstream& inFile) { unsigned row = longestRow = 0; while (inFile.peek() != EOF) { if (cells.get_count() < row + 1) cells.add(List()); if (inFile.peek() == '\n') { row++; inFile.get(); continue; } List buffer; W(inFile); if (inFile.peek() == '"') { // W"=A",S | W"A",S inFile.get(); A(inFile, buffer); buffer.add('\0'); if (inFile.peek() != '"') throwException(inFile, row); inFile.get(); W(inFile); if (inFile.peek() == ',') inFile.get(); else if (inFile.peek() != '\n' && inFile.peek() != EOF) throwException(inFile, row); cells[row].add((buffer[0] == '=') ? (Cell*)new CellFormula(buffer.raw_data(), &cells) : (Cell*)new CellString(buffer.raw_data())); } else if (inFile.peek() == ',') { // ,S inFile.get(); cells[row].add(nullptr); } else { // WPD,S | WPD.D,S P(inFile, buffer); D(inFile, buffer); if (inFile.peek() == '.') { buffer.add(inFile.get()); D(inFile, buffer); buffer.add('\0'); W(inFile); if (inFile.peek() == ',') inFile.get(); else if (inFile.peek() != '\n' && inFile.peek() != EOF) throwException(inFile, row); cells[row].add((Cell*)new CellDouble(buffer.raw_data())); } else { buffer.add('\0'); W(inFile); if (inFile.peek() == ',') inFile.get(); else if (inFile.peek() != '\n' && inFile.peek() != EOF) throwException(inFile, row); cells[row].add((Cell*)new CellInt(buffer.raw_data())); } } if (cells[row].get_count() > longestRow) longestRow = cells[row].get_count(); } } #include Table::Table(const char* filePath) { longestRow = 0; std::ifstream inFile(filePath); if (!inFile.is_open()) throw std::logic_error("Could not open file!"); cells = List>(); readFromFile(inFile); inFile.close(); } Table::~Table() { for (unsigned i = 0; i < cells.get_count(); i++) { for (unsigned j = 0; j < cells[i].get_count(); j++) delete cells[i][j]; } } unsigned Table::get_rows() const { return cells.get_count(); } unsigned Table::get_cols() const { return longestRow; } #define abs(a) ((a < 0) ? -a : a) #define FLOATING_POINT_PRECISION 0.0001f void Table::putCell(unsigned row, unsigned col, const char* rawValue) { Cell* newCell; while (*rawValue == ' ') rawValue++; if (*rawValue == '"') { List buffer; rawValue++; while (*rawValue != '"' && *rawValue != '\0') { if (*rawValue == '\\') rawValue++; buffer.add(*(rawValue++)); } if (*rawValue == '"' && *(rawValue + 1) != '\0') throw std::logic_error("Error: Text after closing (inescaped) brace!"); else if (*rawValue != '"') throw std::logic_error("Error: No closing brace found!"); newCell = (buffer[0] == '=') ? (Cell*)new CellFormula(buffer.raw_data(), &cells) : (Cell*)new CellString(buffer.raw_data()); } else if ((*rawValue == '+' || *rawValue == '-') || (*rawValue >= '0' && *rawValue <= '9')) { double doubleParse = atof(rawValue); unsigned intPart = abs(doubleParse); newCell = (abs(doubleParse) - intPart > FLOATING_POINT_PRECISION) ? (Cell*)new CellDouble(doubleParse) : (Cell*)new CellInt(intPart); } else throw std::logic_error("Error: Could not determine data type."); if (cells[row].get_count() - 1 < col) { while (cells[row].get_count() < col) cells[row].add((Cell*)new CellString()); cells[row].add(newCell); } else { delete cells[row][col]; cells[row][col] = newCell; } } List Table::getAllCells() const { List toRet; for (unsigned i = 0; i < cells.get_count(); i++) { for (unsigned j = 0; j < get_cols(); j++) { if (cells[i].get_count() > j && cells[i][j] != nullptr) toRet.add(cells[i][j]->getValueForPrint()); else toRet.add(""); } } return toRet; } void Table::saveToFile(const char* filePath) const { std::ofstream outFile(filePath); if (!outFile.is_open()) throw std::logic_error("Could not open file!"); for (unsigned i = 0; i < cells.get_count(); i++) { for (unsigned j = 0; j < cells[i].get_count(); j++) { if (cells[i][j] != nullptr) cells[i][j]->writeToFile(outFile); outFile << ','; } outFile << '\n'; } outFile.close(); }