2024-10-27 13:17:16 +00:00
|
|
|
#include "tape_config.h"
|
2024-10-28 10:32:14 +00:00
|
|
|
#include "tapelib/filetape.h"
|
2024-10-27 13:17:16 +00:00
|
|
|
#include <bits/getopt_core.h>
|
2024-10-28 10:32:14 +00:00
|
|
|
#include <chrono>
|
|
|
|
#include <cstddef>
|
2024-10-28 02:23:42 +00:00
|
|
|
#include <fstream>
|
2024-10-27 13:17:16 +00:00
|
|
|
#include <getopt.h>
|
2024-10-28 02:23:42 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <string>
|
2024-10-28 10:32:14 +00:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
using std::string;
|
|
|
|
using std::chrono::milliseconds;
|
2024-10-27 13:17:16 +00:00
|
|
|
|
|
|
|
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}};
|
|
|
|
|
2024-10-28 10:32:14 +00:00
|
|
|
milliseconds parse_delay(const string &input) {
|
2024-10-27 13:17:16 +00:00
|
|
|
int delay_ms = std::stoi(input);
|
2024-10-28 10:32:14 +00:00
|
|
|
return milliseconds(delay_ms);
|
2024-10-27 13:17:16 +00:00
|
|
|
}
|
|
|
|
|
2024-10-27 15:53:34 +00:00
|
|
|
AppSettings parse_command_line(int argc, char **argv) {
|
|
|
|
AppSettings settings{
|
2024-10-27 13:17:16 +00:00
|
|
|
.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,
|
2024-10-27 13:17:16 +00:00
|
|
|
};
|
|
|
|
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);
|
2024-10-27 13:17:16 +00:00
|
|
|
break;
|
|
|
|
case 'w':
|
2024-10-27 15:53:34 +00:00
|
|
|
settings.ft_settings.write_delay = parse_delay(optarg);
|
2024-10-27 13:17:16 +00:00
|
|
|
break;
|
|
|
|
case 'f':
|
2024-10-27 15:53:34 +00:00
|
|
|
settings.ft_settings.seek_forward_delay = parse_delay(optarg);
|
2024-10-27 13:17:16 +00:00
|
|
|
break;
|
|
|
|
case 'b':
|
2024-10-27 15:53:34 +00:00
|
|
|
settings.ft_settings.seek_backwards_delay = parse_delay(optarg);
|
2024-10-27 13:17:16 +00:00
|
|
|
break;
|
|
|
|
case 'm':
|
2024-10-27 15:53:34 +00:00
|
|
|
settings.memory_limit = std::stoi(optarg);
|
2024-10-27 13:17:16 +00:00
|
|
|
break;
|
|
|
|
case 'c':
|
2024-10-27 15:53:34 +00:00
|
|
|
settings.config_file_path = optarg;
|
2024-10-27 13:17:16 +00:00
|
|
|
break;
|
|
|
|
case 'v':
|
2024-10-27 15:53:34 +00:00
|
|
|
settings.version = true;
|
2024-10-27 13:17:16 +00:00
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
case '?':
|
|
|
|
default:
|
2024-10-27 15:53:34 +00:00
|
|
|
settings.help = true;
|
2024-10-27 13:17:16 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// parse positional args INPUT_FILE OUTPUT_FILE
|
|
|
|
if (argc - optind < 2) {
|
2024-10-27 15:53:34 +00:00
|
|
|
settings.help = true;
|
2024-10-28 02:23:42 +00:00
|
|
|
std::cerr << "Not enough positional arguments (Missing INPUT_FILE or "
|
|
|
|
"OUTPUT_FILE)"
|
|
|
|
<< std::endl;
|
2024-10-27 15:53:34 +00:00
|
|
|
return settings;
|
2024-10-27 13:17:16 +00:00
|
|
|
}
|
|
|
|
// 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;
|
2024-10-27 13:17:16 +00:00
|
|
|
}
|
2024-10-28 02:23:42 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2024-10-28 10:32:14 +00:00
|
|
|
string line;
|
2024-10-28 02:23:42 +00:00
|
|
|
size_t line_number = 1;
|
|
|
|
while (std::getline(config, line)) {
|
|
|
|
size_t delim_index = line.find(CFG_DELIMETER);
|
|
|
|
if (delim_index >= line.size()) {
|
|
|
|
continue;
|
|
|
|
}
|
2024-10-28 10:32:14 +00:00
|
|
|
string key = line.substr(0, delim_index);
|
|
|
|
string value = line.substr(delim_index + 1);
|
2024-10-28 02:23:42 +00:00
|
|
|
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;
|
|
|
|
}
|