From d098ad65bfd288ef32aed8e9ab4e778f0ba0754f Mon Sep 17 00:00:00 2001 From: "Luna Mira Lage (Desoroxxx)" Date: Mon, 7 Sep 2026 11:52:09 +0200 Subject: [PATCH] ex00 Signed-off-by: Luna Mira Lage (Desoroxxx) --- ex00/Makefile | 4 + ex00/src/BitcoinExchange.cpp | 34 +++++++ ex00/src/BitcoinExchange.hpp | 20 ++++ ex00/src/main.cpp | 171 +++++++++++++++++++++++++++++++++++ 4 files changed, 229 insertions(+) create mode 100644 ex00/Makefile create mode 100644 ex00/src/BitcoinExchange.cpp create mode 100644 ex00/src/BitcoinExchange.hpp create mode 100644 ex00/src/main.cpp diff --git a/ex00/Makefile b/ex00/Makefile new file mode 100644 index 0000000..8bf65f0 --- /dev/null +++ b/ex00/Makefile @@ -0,0 +1,4 @@ +override NAME = btc +override SRC_FILES = main.cpp BitcoinExchange.cpp + +include ../Makefile diff --git a/ex00/src/BitcoinExchange.cpp b/ex00/src/BitcoinExchange.cpp new file mode 100644 index 0000000..161f6cf --- /dev/null +++ b/ex00/src/BitcoinExchange.cpp @@ -0,0 +1,34 @@ +#include + +BitcoinExchange::BitcoinExchange() : data() {} + +BitcoinExchange::BitcoinExchange(const std::map& data) : data(data) {} + +BitcoinExchange::BitcoinExchange(const BitcoinExchange& other) : data(other.data) {} + +BitcoinExchange& BitcoinExchange::operator=(const BitcoinExchange& other) { + if (this == &other) + return *this; + + data = other.data; + + return *this; +} + +double BitcoinExchange::getValue(const std::string& date) const { + std::map::const_iterator it = data.lower_bound(date); + + if (it == data.end()) + return data.rbegin()->second; + + if (it->first == date) + return it->second; + + if (it == data.begin()) + return it->second; + + --it; + return it->second; +} + +BitcoinExchange::~BitcoinExchange() {} diff --git a/ex00/src/BitcoinExchange.hpp b/ex00/src/BitcoinExchange.hpp new file mode 100644 index 0000000..dfa46b6 --- /dev/null +++ b/ex00/src/BitcoinExchange.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +class BitcoinExchange { + public: + BitcoinExchange(); + BitcoinExchange(const std::map& data); + BitcoinExchange(const BitcoinExchange& other); + + BitcoinExchange& operator=(const BitcoinExchange& other); + + double getValue(const std::string& date) const; + + ~BitcoinExchange(); + + private: + std::map data; +}; diff --git a/ex00/src/main.cpp b/ex00/src/main.cpp new file mode 100644 index 0000000..eb4d875 --- /dev/null +++ b/ex00/src/main.cpp @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include + +static std::string trim(const std::string& str) { + std::string result = str; + + result.erase(result.find_last_not_of(" \t\n\r\f\v") + 1); + result.erase(0, result.find_first_not_of(" \t\n\r\f\v")); + + return result; +} + +static bool isLeapYear(int year) { return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); } + +static bool isValidDate(const std::string& date) { + if (date.size() != 10) + return false; + + if (date[4] != '-' || date[7] != '-') + return false; + + for (size_t i = 0; i < date.size(); ++i) { + if (i == 4 || i == 7) + continue; + if (!std::isdigit(static_cast(date[i]))) + return false; + } + + const int year = (date[0] - '0') * 1000 + (date[1] - '0') * 100 + (date[2] - '0') * 10 + (date[3] - '0'); + const int month = (date[5] - '0') * 10 + (date[6] - '0'); + const int day = (date[8] - '0') * 10 + (date[9] - '0'); + + if (year <= 0) + return false; + if (month < 1 || month > 12) + return false; + if (day < 1) + return false; + + static const int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + int maxDay = daysInMonth[month - 1]; + if (month == 2 && isLeapYear(year)) + maxDay = 29; + + return day <= maxDay; +} + +static std::map validateCSV(const std::string& fileName) { + std::ifstream inputFile(fileName.c_str()); + + if (!inputFile.is_open() || !inputFile.good()) + std::cerr << ("Error: could not open file.") << std::endl; + + std::string line; + bool firstLine = true; + static bool input = false; // smelly, pefect + std::map data; + while (std::getline(inputFile, line)) { + std::size_t separator = line.find(','); + if (separator == std::string::npos) { + separator = line.find('|'); // That is not a CSV file... + + if (separator == std::string::npos) { + std::cerr << "Error: bad input => " + line << std::endl; + continue; + } + } + + std::string first = trim(line.substr(0, separator)); + std::string second = trim(line.substr(separator + 1)); + + if (second.empty()) { + std::cerr << "Error: bad input => " + line << std::endl; + continue; + } + + if (firstLine) { + firstLine = false; + + if (first != "date" || (input && second != "value") || (!input && second != "exchange_rate")) { + std::cerr << "Error: bad => " + line << std::endl; + continue; + } + + continue; + } + + if (!isValidDate(first)) { + std::cerr << "Error: bad input => " + first << std::endl; + continue; + } + + bool badSecond = false; + bool dot = false; + bool dash = false; + for (size_t i = 0; i < second.size(); ++i) { + if (std::isdigit(static_cast(second[i]))) + continue; + + if (!dot && second[i] == '.' && i + 1 < second.size()) { + dot = true; + continue; + } + + if (!dash && second[i] == '-' && i == 0 && i + 1 < second.size()) { + dash = true; + continue; + } + + std::cerr << "Error: bad input => " + second << std::endl; + badSecond = true; + break; + } + + if (badSecond) + continue; + + const double value = std::strtod(second.c_str(), NULL); + if (value < 0) { + std::cerr << "Error: not a positive number." << std::endl; + continue; + } else if (input && value > 1000) { + std::cerr << "Error: too large a number." << std::endl; + continue; + } + + const std::pair pair(first, value); + + if (!input && data.find(first) != data.end()) { + std::cerr << "Error: bad input => " + first << std::endl; + continue; + } + + data.insert(pair); + } + + input = true; + + return data; +} + +int main(int argc, char* argv[]) { + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return EXIT_FAILURE; + } + + try { + const std::map data = validateCSV("data.csv"); + + if (data.empty()) + throw std::runtime_error("data file is empty"); + + const BitcoinExchange exchange(data); + + const std::map input = validateCSV(argv[1]); + + for (std::map::const_iterator it = input.begin(); it != input.end(); ++it) { + const double value = exchange.getValue(it->first); + + std::cout << it->first << " => " << it->second << " = " << value * it->second << std::endl; + } + + } catch (const std::exception& exception) { + std::cerr << "Exception caught, cause: " << exception.what() << std::endl; + return EXIT_FAILURE; + } +} -- 2.51.2