Initial commit

This commit is contained in:
Martino Ferrari committed 2026-10-01 15:42:48 +02:00
commit 8059b90de7
29 files changed
+7893

No files matched your search

+100
View File
@@ -0,0 +1,100 @@
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2026 Martino Ferrari
#include "config.hpp"
#include <cstdio>
#include <cstdlib>
#include <stdexcept>
#include <string>
namespace udpscope {
namespace {
[[noreturn]] void fail(const std::string& what) { throw std::runtime_error(what); }
/// `--name=value` / `--name value`; returns the value and advances `i` past both
/// spellings. `argv[i]` must start with `--name`.
std::string value_of(int argc, char** argv, int& i, const char* name) {
const std::string arg = argv[i];
const std::string prefix = std::string(name) + "=";
if (arg.rfind(prefix, 0) == 0) return arg.substr(prefix.size());
if (i + 1 >= argc) fail(std::string("missing value for ") + name);
return argv[++i];
}
double parse_double(const char* name, const std::string& v) {
try {
std::size_t used = 0;
const double d = std::stod(v, &used);
if (used != v.size()) fail(std::string("not a number: ") + name + " " + v);
return d;
} catch (const std::exception&) {
fail(std::string("not a number: ") + name + " " + v);
}
}
} // namespace
void print_usage(std::FILE* out, const char* argv0) {
std::fprintf(out,
"usage: %s --server ADDR --port PORT [options]\n"
"\n"
" --server ADDR stream source IPv4 address (default 127.0.0.1)\n"
" --port PORT UDP port (unicast) or TCP port (multicast) (default 8000)\n"
" --multicast GROUP join GROUP for DATA instead of unicast\n"
" --interface ADDR local IPv4 of the interface to join on\n"
" --buffer-mb MB size of each of the two sample buffers (default 200)\n"
" --max-window SEC largest time window the toolbar offers (default 600)\n"
" --holdoff SEC default trigger hold-off (default 0.010)\n"
" --recv-buffer BYTES SO_RCVBUF for the receiver socket (default 8388608)\n"
" --plots N initial number of stacked plots, 1..4 (default 1)\n"
" -h, --help this text\n",
argv0);
}
Config parse_args(int argc, char** argv) {
Config c;
for (int i = 1; i < argc; ++i) {
const std::string a = argv[i];
if (a == "-h" || a == "--help") {
print_usage(stdout, argv[0]);
std::exit(0);
} else if (a == "--server" || a.rfind("--server=", 0) == 0) {
c.server = value_of(argc, argv, i, "--server");
} else if (a == "--port" || a.rfind("--port=", 0) == 0) {
const std::string v = value_of(argc, argv, i, "--port");
const long p = std::strtol(v.c_str(), nullptr, 10);
if (p <= 0 || p > 65535) fail("port out of range: " + v);
c.port = static_cast<std::uint16_t>(p);
} else if (a == "--multicast" || a.rfind("--multicast=", 0) == 0) {
c.multicast = value_of(argc, argv, i, "--multicast");
} else if (a == "--interface" || a.rfind("--interface=", 0) == 0) {
c.interface_addr = value_of(argc, argv, i, "--interface");
} else if (a == "--buffer-mb" || a.rfind("--buffer-mb=", 0) == 0) {
c.buffer_mb = parse_double("--buffer-mb", value_of(argc, argv, i, "--buffer-mb"));
if (c.buffer_mb < 1.0) fail("--buffer-mb must be at least 1");
} else if (a == "--max-window" || a.rfind("--max-window=", 0) == 0) {
c.max_window_s = parse_double("--max-window", value_of(argc, argv, i, "--max-window"));
if (c.max_window_s <= 0.0) fail("--max-window must be positive");
} else if (a == "--holdoff" || a.rfind("--holdoff=", 0) == 0) {
c.trigger_holdoff_s = parse_double("--holdoff", value_of(argc, argv, i, "--holdoff"));
if (c.trigger_holdoff_s < 0.0) fail("--holdoff must not be negative");
} else if (a == "--recv-buffer" || a.rfind("--recv-buffer=", 0) == 0) {
const std::string v = value_of(argc, argv, i, "--recv-buffer");
const long n = std::strtol(v.c_str(), nullptr, 10);
if (n <= 0) fail("--recv-buffer must be positive: " + v);
c.recv_buffer_bytes = static_cast<int>(n);
} else if (a == "--plots" || a.rfind("--plots=", 0) == 0) {
const std::string v = value_of(argc, argv, i, "--plots");
const long n = std::strtol(v.c_str(), nullptr, 10);
if (n < 1 || n > 4) fail("--plots must be 1..4: " + v);
c.plots = static_cast<int>(n);
} else {
fail("unknown argument: " + a);
}
}
return c;
}
} // namespace udpscope