yadro-task/bin/ftsort/tape_config.cpp
erius ad976a5a9e Added using directives to avoid excessive namespaecs
Added explicit include directories to each file, even if an already included header defined them
Removed using directives from header files
2024-10-28 12:32:14 +02:00

148 lines
4.8 KiB
C++

#include "tape_config.h"
#include "tapelib/filetape.h"
#include <bits/getopt_core.h>
#include <chrono>
#include <cstddef>
#include <fstream>
#include <getopt.h>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
using std::string;
using std::chrono::milliseconds;
const static struct std::vector<option> CMD_OPTS{
{.name = "write-delay",
.has_arg = no_argument,
.flag = nullptr,
.val = 'w'},
{.name = "read-delay", .has_arg = no_argument, .flag = nullptr, .val = 'r'},
{.name = "seek-forward-delay",
.has_arg = no_argument,
.flag = nullptr,
.val = 'f'},
{.name = "seek-backwards-delay",
.has_arg = no_argument,
.flag = nullptr,
.val = 'b'},
{.name = "memory-limit",
.has_arg = no_argument,
.flag = nullptr,
.val = 'm'},
{.name = "config-file",
.has_arg = no_argument,
.flag = nullptr,
.val = 'c'},
{.name = "version", .has_arg = no_argument, .flag = nullptr, .val = 'v'},
{.name = "help", .has_arg = no_argument, .flag = nullptr, .val = 'h'},
{.name = nullptr, .has_arg = no_argument, .flag = nullptr, .val = 0}};
milliseconds parse_delay(const string &input) {
int delay_ms = std::stoi(input);
return milliseconds(delay_ms);
}
AppSettings parse_command_line(int argc, char **argv) {
AppSettings settings{
.config_file_path = "",
.input_file_name = "",
.output_file_name = "",
.memory_limit = SIZE_MAX,
.version = false,
.help = false,
.ft_settings = tape::FT_DEFAULT_SETTINGS,
};
int opt_index = 0;
int opt = 0;
// parse [OPTIONS...] using getopt_long
while ((opt = getopt_long(argc, argv, "r:w:f:b:m:c:vh", CMD_OPTS.data(),
&opt_index)) != -1) {
switch (opt) {
case 'r':
settings.ft_settings.read_delay = parse_delay(optarg);
break;
case 'w':
settings.ft_settings.write_delay = parse_delay(optarg);
break;
case 'f':
settings.ft_settings.seek_forward_delay = parse_delay(optarg);
break;
case 'b':
settings.ft_settings.seek_backwards_delay = parse_delay(optarg);
break;
case 'm':
settings.memory_limit = std::stoi(optarg);
break;
case 'c':
settings.config_file_path = optarg;
break;
case 'v':
settings.version = true;
break;
case 'h':
case '?':
default:
settings.help = true;
break;
}
}
// parse positional args INPUT_FILE OUTPUT_FILE
if (argc - optind < 2) {
settings.help = true;
std::cerr << "Not enough positional arguments (Missing INPUT_FILE or "
"OUTPUT_FILE)"
<< std::endl;
return settings;
}
// no linting to disable pointer arithmetic warning
settings.input_file_name = argv[optind]; // NOLINT
settings.output_file_name = argv[optind + 1]; // NOLINT
return settings;
}
const static char CFG_DELIMETER = '=';
bool read_settings_from_file(AppSettings &settings) {
std::ifstream config(settings.config_file_path);
if (!config.is_open()) {
std::cerr << "Failed to read config: file doesn't exist or "
"insufficient permissions"
<< std::endl;
return false;
}
string line;
size_t line_number = 1;
while (std::getline(config, line)) {
size_t delim_index = line.find(CFG_DELIMETER);
if (delim_index >= line.size()) {
continue;
}
string key = line.substr(0, delim_index);
string value = line.substr(delim_index + 1);
try {
if (key == "write-delay") {
settings.ft_settings.write_delay = parse_delay(value);
} else if (key == "read-delay") {
settings.ft_settings.read_delay = parse_delay(value);
} else if (key == "seek-forward-delay") {
settings.ft_settings.seek_forward_delay = parse_delay(value);
} else if (key == "seek-backwards-delay") {
settings.ft_settings.seek_backwards_delay = parse_delay(value);
} else if (key == "memory-limit") {
settings.memory_limit = std::stoi(value);
}
} catch (std::invalid_argument) {
std::cerr << "Failed to parse config at line " << line_number
<< ": value must be a positive integer" << std::endl;
return false;
} catch (std::out_of_range) {
std::cerr << "Failed to parse config at line " << line_number
<< ": value is out of allowed range" << std::endl;
return false;
}
line_number++;
}
return true;
}