Add file wrapper

This commit is contained in:
blankie 2023-03-28 23:48:26 +07:00
parent 46389de61f
commit d4e6d72a18
Signed by: blankie
GPG Key ID: CC15FC822C7F61F5
3 changed files with 79 additions and 27 deletions

View File

@ -16,7 +16,7 @@ set(INCLUDES "")
set(SOURCES "")
set(IMGUI_SOURCES "")
set(DEFINITIONS "")
# imgui include because <GH ISSUE LINK HERE>
# imgui include because https://github.com/ocornut/imgui/issues/6184#issuecomment-1439570929
list(APPEND INCLUDES thirdparty thirdparty/imgui /usr/include/SDL2)
list(APPEND SOURCES main.cpp event_loop.cpp logcat_thread.cpp logcat_entry.cpp log.cpp config.cpp filters.cpp misc.cpp pcre2_wrapper.cpp
group_panel.cpp fragments/filters.cpp windows/logs.cpp windows/settings.cpp windows/main.cpp)

View File

@ -1,29 +1,13 @@
#include <cstdlib>
#include <cstring>
#include <sys/stat.h>
#include <string>
#include <nlohmann/json.hpp>
#include "log.h"
#include "file.h"
#include "misc.h"
#include "config.h"
static FILE* fopen_or_raise(const char* __restrict path, const char* __restrict mode, bool ignore_enoent) {
FILE* file = fopen(path, mode);
if (!file && !(ignore_enoent && errno == ENOENT)) {
throw_system_error(std::string("fopen(") + quote(path) + ')');
}
return file;
}
static void fclose_and_log(FILE* file) {
if (!fclose(file)) {
return;
}
log(std::string("Failed to close a file: fclose(): ") + strerror(errno));
}
std::string get_config_folder() {
const char* path;
@ -76,13 +60,15 @@ void from_json(const nlohmann::json& j, Config& config) {
Config load_config() {
std::string config_file_path = get_config_file_path();
std::unique_ptr<FILE, decltype(&fclose_and_log)> config_file(fopen_or_raise(config_file_path.c_str(), "r", true), fclose_and_log);
if (!config_file) {
try {
File config_file(config_file_path.c_str(), "r");
return nlohmann::json::parse(config_file.get());
} catch (const std::system_error& e) {
if (e.code().value() != ENOENT) {
throw;
}
return Config();
}
return nlohmann::json::parse(config_file.get()).get<Config>();
}
@ -98,10 +84,11 @@ void write_config(const Config& config) {
std::string config_file_path = get_config_file_path();
std::string tmp_config_file_path = config_file_path + ".tmp";
std::unique_ptr<FILE, decltype(&fclose_and_log)> config_file(fopen_or_raise(tmp_config_file_path.c_str(), "w", false), fclose_and_log);
std::string str_config = nlohmann::json(config).dump(4);
fwrite(str_config.data(), sizeof(char), str_config.size(), config_file.get());
config_file.reset();
{
File config_file(tmp_config_file_path.c_str(), "w");
std::string str_config = nlohmann::json(config).dump(4);
config_file.write(std::move(str_config));
}
if (!rename(tmp_config_file_path.c_str(), config_file_path.c_str())) {
return;

65
file.h Normal file
View File

@ -0,0 +1,65 @@
#pragma once
#include <cstdio>
#include <string>
#include "../log.h"
#include "../misc.h"
static void try_close(FILE* file);
// Not usable for logcat thread!
class File {
public:
// https://stackoverflow.com/a/2173764
File(const File&) = delete;
File& operator=(const File&) = delete;
inline constexpr File(File&& other) {
try_close(this->_file);
this->_file = other._file;
other._file = nullptr;
}
inline constexpr File& operator=(File&& other) {
if (this == &other) {
return *this;
}
try_close(this->_file);
this->_file = other._file;
other._file = nullptr;
return *this;
}
File(const char* __restrict path, const char* __restrict mode) {
this->_file = fopen(path, mode);
if (!this->_file) {
throw_system_error(std::string("fopen(") + quote(path) + ')');
}
}
~File() {
try_close(this->_file);
}
void write(const char* data, size_t length) {
if (fwrite(data, 1, length, this->_file) != length) {
throw_system_error("fwrite()");
}
}
inline constexpr void write(const std::string& str) {
this->write(str.data(), str.size());
}
inline constexpr FILE* get() const noexcept {
return this->_file;
}
protected:
FILE* _file = nullptr;
};
static void try_close(FILE* file) {
if (file && fclose(file)) {
log(std::string("Failed to close a file: fclose(): ") + strerror(errno));
}
}