yadro-task/bin/ftsort/tape_config.cpp

149 lines
4.8 KiB
C++
Raw Permalink Normal View History

#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);
}
2024-10-27 15:53:34 +00:00
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,
2024-10-27 15:53:34 +00:00
.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':
2024-10-27 15:53:34 +00:00
settings.ft_settings.read_delay = parse_delay(optarg);
break;
case 'w':
2024-10-27 15:53:34 +00:00
settings.ft_settings.write_delay = parse_delay(optarg);
break;
case 'f':
2024-10-27 15:53:34 +00:00
settings.ft_settings.seek_forward_delay = parse_delay(optarg);
break;
case 'b':
2024-10-27 15:53:34 +00:00
settings.ft_settings.seek_backwards_delay = parse_delay(optarg);
break;
case 'm':
2024-10-27 15:53:34 +00:00
settings.memory_limit = std::stoi(optarg);
break;
case 'c':
2024-10-27 15:53:34 +00:00
settings.config_file_path = optarg;
break;
case 'v':
2024-10-27 15:53:34 +00:00
settings.version = true;
break;
case 'h':
case '?':
default:
2024-10-27 15:53:34 +00:00
settings.help = true;
break;
}
}
// parse positional args INPUT_FILE OUTPUT_FILE
if (argc - optind < 2) {
2024-10-27 15:53:34 +00:00
settings.help = true;
std::cerr << "Not enough positional arguments (Missing INPUT_FILE or "
"OUTPUT_FILE)"
<< std::endl;
2024-10-27 15:53:34 +00:00
return settings;
}
// no linting to disable pointer arithmetic warning
2024-10-27 15:53:34 +00:00
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;
}