From a4838511ebb1ac7396eee54d4c8a51fe13a3c4b4 Mon Sep 17 00:00:00 2001 From: Camille Chauvet Date: Tue, 3 Oct 2023 15:09:24 +0000 Subject: [PATCH] ex00: init: work but some value qre not right maybe upperbound --- .gitignore | 5 + ex00/Makefile | 26 +++++ ex00/src/BitcoinExchange.cpp | 209 +++++++++++++++++++++++++++++++++++ ex00/src/BitcoinExchange.hpp | 6 + 4 files changed, 246 insertions(+) create mode 100644 .gitignore create mode 100644 ex00/Makefile create mode 100644 ex00/src/BitcoinExchange.cpp create mode 100644 ex00/src/BitcoinExchange.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ca2e5f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +* +!/**/ +!*.* +!/**/Makefile +*.o diff --git a/ex00/Makefile b/ex00/Makefile new file mode 100644 index 0000000..47ad482 --- /dev/null +++ b/ex00/Makefile @@ -0,0 +1,26 @@ +CXX := c++ +CXXFLAGS := -std=c++98 -Wall -Wextra -Werror -g +SRCDIR := src +OBJDIR := obj +NAME := ex00 + +SRCS := $(wildcard $(SRCDIR)/*.cpp) +OBJS := $(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(SRCS)) + +all: $(NAME) + +$(OBJDIR)/%.o: $(SRCDIR)/%.cpp + mkdir -p obj + $(CXX) $(CXXFLAGS) -c $< -o $@ + +$(NAME): $(OBJS) + $(CXX) $(CXXFLAGS) $^ -o $@ + +clean: + rm -rf $(OBJDIR) + +fclean: clean + rm -fr $(NAME) + +re: fclean + @make --no-print-directory all diff --git a/ex00/src/BitcoinExchange.cpp b/ex00/src/BitcoinExchange.cpp new file mode 100644 index 0000000..4d7f92d --- /dev/null +++ b/ex00/src/BitcoinExchange.cpp @@ -0,0 +1,209 @@ +#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 == "date,exchange_rate") + 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->first < line_parsed.first) + 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; +} + +unsigned int 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); + + return 0; +} + +int main(int ac, char** av) +{ + if (ac != 2) + { + std::cout << "error: missing file" << std::endl; + return 1; + } + get_price(std::string(av[1])); + return 0; +} diff --git a/ex00/src/BitcoinExchange.hpp b/ex00/src/BitcoinExchange.hpp new file mode 100644 index 0000000..4614fc9 --- /dev/null +++ b/ex00/src/BitcoinExchange.hpp @@ -0,0 +1,6 @@ +#pragma once + +#define INPUT_PATERN "^[0-9]{4}\\-[0-9]{2}\\-[0-9]{2} \\| [+\\-]*[0-9]*(\\.[0-9]+)?$" +#define DATA_PATERN "^[0-9]{4}\\-[0-9]{2}\\-[0-9]{2},[+\\-]*[0-9]*(\\.[0-9]+)?$" +#define INPUT 0 +#define DATABASE 1