diff --git a/Makefile b/Makefile index 492dfa5..a633bf4 100644 --- a/Makefile +++ b/Makefile @@ -6,3 +6,9 @@ build: install: build meson install -C build + +check: + cppcheck --language=c++ --enable=all -q \ + --suppress=missingInclude \ + --suppress=missingIncludeSystem \ + src diff --git a/meson.build b/meson.build index 18fc352..b7a72ed 100644 --- a/meson.build +++ b/meson.build @@ -20,6 +20,11 @@ executable( 'mornelune', sources: [ 'src/main.cpp', + + 'src/Game.cpp', + + 'src/logs/Logs.cpp', + 'src/logs/FileLogs.cpp', ], dependencies: [ ], diff --git a/src/Game.cpp b/src/Game.cpp new file mode 100644 index 0000000..1dd6e0c --- /dev/null +++ b/src/Game.cpp @@ -0,0 +1,23 @@ +#include "Game.hpp" + +namespace ml +{ + /*explicit*/ Game::Game(std::shared_ptr logs) + : m_logs { logs } + { + } + + /*virtual*/ Game::~Game() + { + } + + void Game::start() + { + m_logs->log(LEVEL_DEBUG, "game started"); + } + + void Game::stop() + { + m_logs->log(LEVEL_DEBUG, "game stopped"); + } +} diff --git a/src/Game.hpp b/src/Game.hpp new file mode 100644 index 0000000..c77f89c --- /dev/null +++ b/src/Game.hpp @@ -0,0 +1,26 @@ +#ifndef ml_GAME_HPP +#define ml_GAME_HPP + +#include "commons.hpp" +#include "logs/Logs.hpp" + +namespace ml +{ + /** + * Manage services and game state. + **/ + class Game + { + public: + explicit Game(std::shared_ptr logs); + virtual ~Game(); + + void start(); + void stop(); + + private: + std::shared_ptr m_logs; + }; +} + +#endif diff --git a/src/commons.hpp b/src/commons.hpp new file mode 100644 index 0000000..9c2383e --- /dev/null +++ b/src/commons.hpp @@ -0,0 +1,24 @@ +#ifndef ml_COMMONS_HPP +#define ml_COMMONS_HPP + +#include +#include +#include +#include +#include +#include + +#define ML_GEN_ENUM(X) X +#define ML_GEN_STRING(X) #X + +#define ML_ENUM(PREFIX, KINDS) \ + enum PREFIX { KINDS(ML_GEN_ENUM) }; \ + constexpr char const* PREFIX ## Str [] = { KINDS(ML_GEN_STRING) } + +#define ML_ERROR(NAME) \ + struct NAME : public std::runtime_error { \ + explicit NAME (std::string const& what): std::runtime_error { what } \ + {} \ + } + +#endif diff --git a/src/logs/FileLogs.cpp b/src/logs/FileLogs.cpp new file mode 100644 index 0000000..f0fad94 --- /dev/null +++ b/src/logs/FileLogs.cpp @@ -0,0 +1,19 @@ +#include "FileLogs.hpp" + +namespace ml +{ + /*explicit*/ FileLogs::FileLogs(std::filesystem::path const& path) + : Logs { m_file } + { + m_file.open(path, std::ios::app); + + if (!m_file) + { + throw log_error {"cannot open log file '" + path.string() + "'"}; + } + } + + /*virtual*/ FileLogs::~FileLogs() + { + } +} diff --git a/src/logs/FileLogs.hpp b/src/logs/FileLogs.hpp new file mode 100644 index 0000000..0b47416 --- /dev/null +++ b/src/logs/FileLogs.hpp @@ -0,0 +1,24 @@ +#ifndef ml_FILELOGS_HPP +#define ml_FILELOGS_HPP + +#include "../commons.hpp" +#include "Logs.hpp" + +namespace ml +{ + /** + * Logs game activities into a file. + * @see Logs + **/ + class FileLogs: public Logs + { + public: + explicit FileLogs(std::filesystem::path const& path); + virtual ~FileLogs(); + + private: + std::ofstream m_file; + }; +} + +#endif diff --git a/src/logs/Logs.cpp b/src/logs/Logs.cpp new file mode 100644 index 0000000..afc58f2 --- /dev/null +++ b/src/logs/Logs.cpp @@ -0,0 +1,40 @@ +#include "Logs.hpp" + +namespace ml +{ + /*explicit*/ Logs::Logs(std::ostream& out) + : m_out { out } + { + } + + /*virtual*/ Logs::~Logs() + { + } + + void Logs::log(LogLevel level, std::string const& message) + { + std::string level_str = (LogLevelStr[level] + std::strlen("LEVEL_")); + auto now = std::chrono::system_clock::now(); + std::time_t now_t = std::chrono::system_clock::to_time_t(now); + + auto time_str = std::put_time(std::localtime(&now_t), "%F %T"); + + std::string color = ""; + + switch (level) + { + case LEVEL_DEBUG: color = "34"; break; + + default: + throw log_error {std::string("cannot find color for log level '") + + (LogLevelStr[level] + std::strlen("LEVEL_")) + + "'"}; + } + + m_out + << time_str << " " + << ("\033[" + color + "m[" + level_str + "]\033[0m ") + << message + << "\n"; + } +} diff --git a/src/logs/Logs.hpp b/src/logs/Logs.hpp new file mode 100644 index 0000000..9ad59ef --- /dev/null +++ b/src/logs/Logs.hpp @@ -0,0 +1,29 @@ +#ifndef ml_LOGS_HPP +#define ml_LOGS_HPP + +#include "../commons.hpp" + +#define LOG_LEVELS(G) G(LEVEL_DEBUG) + +namespace ml +{ + ML_ENUM(LogLevel, LOG_LEVELS); + ML_ERROR(log_error); + + /** + * Logs game activities into an output stream. + **/ + class Logs + { + public: + explicit Logs(std::ostream& out); + virtual ~Logs(); + + void log(LogLevel level, std::string const& message); + + private: + std::ostream& m_out; + }; +} + +#endif diff --git a/src/main.cpp b/src/main.cpp index 433956e..1ad5efd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,19 @@ +#include #include #include "conf.hpp" +#include "logs/FileLogs.hpp" + +#include "Game.hpp" int main(int, char**) { - std::cout << "Mornelune v" << ML_VERSION << std::endl; + auto logs = std::make_shared + (std::filesystem::temp_directory_path() / "mornelune.log"); + + ml::Game game {logs}; + + game.start(); + game.stop(); + return 0; }