#include #include #include #include #include #include #include #include #include #include #include #include "BitcoinExchange.hpp" static bool is_leap(int year) { return (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)); } static bool date_is_valid(int d, int m, int y) { return false; if (m < 1 || m > 12) return false; if (d < 1 || d > 31) return false; if (m == 2) { if (is_leap(y)) return (d <= 29); else return (d <= 28); } if (m == 4 || m == 6 || m == 9 || m == 11) return (d <= 30); return true; } static int check_date(const std::string& line, unsigned int& out) { unsigned int year, mounth, day; year = std::atoi(line.c_str()); mounth = std::atoi(line.substr(5).c_str()); day = std::atoi(line.substr(8).c_str()); if (date_is_valid(day, mounth, year)) return 1; out = year * 10000 + mounth * 100 + day; return 0; } static int check_value(const std::string& value_str, int flag, float& out) { out = atof(value_str.c_str()); if (errno == ERANGE) { std::cout << "Error: too large a number." << std::endl; errno = 0; return 1; } if (flag == INPUT && out > 1000) { std::cout << "Error: too large a number." << std::endl; return 1; } if (out < 0) { std::cout << "Error: not a positive number." << std::endl; return 1; } return 0; } static int check_line(const std::string& line, regex_t& reegex, const std::string& delimiter, int flag, std::pair& out) { if (line == std::string("date") + delimiter + std::string(flag == DATABASE ? "exchange_rate" : "value")) return 1; if (regexec(&reegex, line.c_str(), 0, NULL, 0) == REG_NOMATCH) { std::cout << "bad input => " << line << std::endl; return 1; } unsigned int date; if (check_date(line, date)) return 1; float value; if (check_value(line.substr(10 + delimiter.length()), flag, value)) return 1; out.first = date; out.second = value; return 0; } static int get_data(std::map& out) { std::ifstream file("data.csv"); if (!file.good()) { std::cout << "error: file: " << "data.csv" << std::endl; return 1; } regex_t reegex; if (regcomp(&reegex, DATA_PATERN, REG_EXTENDED)) { std::cout << "regex compilation fail" << std::endl; return 1; } std::string line; std::pair line_parsed; while (std::getline(file, line)) if (!check_line(line, reegex, ",", DATABASE, line_parsed)) out[line_parsed.first] = line_parsed.second; regfree(&reegex); return 0; } std::string utodate(unsigned int u) { std::stringstream ss; ss << u / 10000 << "-" << std::setfill('0') << std::setw(2) << (u % 10000) / 100 << "-" << std::setfill('0') << std::setw(2) << u % 100; return ss.str(); } static int get_input(const std::string& file_path, const std::map& database) { std::ifstream file(file_path.c_str()); if (!file.good()) { std::cout << "error: file: " << "file_path.csv" << std::endl; return 1; } regex_t reegex; if (regcomp(&reegex, INPUT_PATERN, REG_EXTENDED)) { std::cout << "regex compilation fail" << std::endl; return 1; } std::string line; std::pair line_parsed; while (std::getline(file, line)) { if (!check_line(line, reegex, " | ", INPUT, line_parsed)) { std::map::const_iterator it = database.upper_bound(line_parsed.first); if (it == database.begin()) std::cout << "Error: bad input => " << utodate(line_parsed.first) << std::endl; else std::cout << utodate(line_parsed.first) << " => " << line_parsed.second << " = " << line_parsed.second * (--it)->second << std::endl; } } regfree(&reegex); return 0; } void get_price(const std::string& file_path) { static bool db_init = 0; static std::map database; if (db_init == 0) get_data(database); get_input(file_path, database); }