18typedef enum : uint8_t {
23typedef enum : uint64_t {
45 if (value ==
nullptr) {
48 if (value[0] !=
'-') {
51 if (
strcmp(flag,
"--from") != 0) {
54 if ((value[1] >=
'0') && (value[1] <=
'9')) {
57 return value[1] ==
'.';
83internal_take_opt(
char** argv,
int argc,
int* i,
const char* flag,
const char** dst,
bool* bad)
85 if ((argv[*i] ==
nullptr) || (
strcmp(argv[*i], flag) != 0)) {
90 if (*dst !=
nullptr) {
120 if ((arg !=
nullptr) && (
strcmp(arg, flag) == 0)) {
184 if ((argv[*i] ==
nullptr) || (
strcmp(argv[*i],
"--verify") != 0)) {
191 if (((*i + 1) < argc) && (argv[*i + 1] !=
nullptr) && (argv[*i + 1][0] !=
'-')) {
222 {
"--config", &a->
cfg},
226 {
"--attr", &a->
attr},
228 {
"--from", &a->
from},
230 {
"--seed", &a->
seed},
233 {
"--pack", &a->
pack},
237 {
"--search", &a->search},
238 {
"--pick", &a->
pick},
239 {
"--proxy", &a->
proxy},
245 for (
size_t k = 0U; k < (
sizeof(opts) /
sizeof(opts[0])); ++k) {
268 if ((arg !=
nullptr) && (arg[0] !=
'-')) {
280 for (
int i = 1; i < argc; ++i) {
290typedef enum : uint64_t {
348 return (value !=
nullptr) ? bit : 0U;
367 return value ? bit : 0U;
417 static const char*
const names[] = {
"invalid",
431 return ((
unsigned)mode < (
sizeof(names) /
sizeof(names[0]))) ? names[mode] : names[0];
451 const char*
const parts[] = {
"mdl: ", message,
"\n"};
497 const size_t tl =
strlen(text);
498 const size_t sl =
strlen(suffix);
502 for (
size_t i = 0U; i < sl; ++i) {
503 char a = text[tl - sl + i];
505 if ((a >=
'A') && (a <=
'Z')) {
506 a = (char)(a + (
'a' -
'A'));
508 if ((b >=
'A') && (b <=
'Z')) {
509 b = (char)(b + (
'a' -
'A'));
535 if (url ==
nullptr) {
538 const size_t path_len = strcspn(url,
"?#");
540 if ((path_len == 0U) || (path_len >=
sizeof(path))) {
543 memcpy(path, url, path_len);
544 path[path_len] =
'\0';
545 static const char*
const suffixes[] =
546 {
".cbt.gz",
".cbt.xz",
".rabook",
".epub",
".cbz",
".cbr",
".cbt",
".jof"};
547 for (
size_t i = 0U; i <
sizeof(suffixes) /
sizeof(suffixes[0]); ++i) {
592 static const struct {
634 for (
size_t i = 0U; i < (
sizeof(names) /
sizeof(names[0])); ++i) {
635 if ((bit & names[i].bit) != 0U) {
636 return names[i].name;
738 uint64_t allowed = 0U;
743 if (disallowed == 0U) {
746 const char*
const parts[] = {
"mdl: ",
776 const bool config_mode =
779 if (config_mode && ((a->
cfg ==
nullptr) || (a->
cfg[0] ==
'\0'))) {
791 "--verify DIR and --out DIR are alternate directory spellings; use one");
820 if ((a->
proxy !=
nullptr) && (a->
socks5 !=
nullptr)) {
834 if ((a ==
nullptr) || (diagnostic ==
nullptr) || (mode ==
nullptr)) {
841 size_t primary_count = 0U;
843 if (primary_count == 0U) {
846 if (primary_count != 1U) {
864 const uint64_t max_bytes = (a->
max_bytes ==
nullptr)
870 .max_response_bytes = max_bytes,
static ra8_err_t internal_cli_invalid(ra8_io_stream_t *diagnostic, const char *message)
Emit one CLI validation diagnostic and return canonical rejection.
static bool internal_take_flag(const char *arg, const char *flag, bool *dst, bool *bad)
Consume one bare Boolean option.
static void internal_parse_positional_or_bad(const char *arg, mdl_args_t *a)
Record a positional URL or reject an unexpected token.
static bool internal_cli_ends_ci(const char *text, const char *suffix)
Test an ASCII suffix without case sensitivity.
static ra8_err_t internal_validate_allowed_args(const mdl_args_t *a, ra8_io_stream_t *diagnostic, mdl_cli_mode_t selected)
Reject option bits that are incompatible with the selected mode.
mdl_cli_arg_bit_t
Bit positions for every CLI spelling, used by mode allowlists.
@ k_arg_page
Positional URL.
@ k_arg_version
--version.
@ k_arg_timeout
--timeout.
@ k_arg_cross_host
--cross-host.
@ k_arg_verify_dir
Optional verify dir.
@ k_arg_cookie
--cookie-file.
@ k_arg_update_all
--update-all.
@ k_arg_separate
--separate.
@ k_arg_refetch
--refetch.
@ k_arg_contact
--contact.
@ k_arg_allow_private
--allow-private.
@ k_arg_ca_file
--ca-file.
@ k_arg_ignore_robots
--ignore-robots.
@ k_arg_cache_dir
--cache-dir.
@ k_arg_max_bytes
--max-bytes.
@ k_arg_chapters
--chapters.
@ k_arg_progress
--progress.
@ k_arg_allow_incomplete
--allow-incomplete.
const char * mdl_cli_mode_name(mdl_cli_mode_t mode)
Stable human-readable command mode name.
static bool internal_cli_artifact_url(const char *url)
Recognise an artifact suffix in a URL path.
ra8_err_t mdl_cli_validate(const mdl_args_t *a, ra8_io_stream_t *diagnostic, mdl_cli_mode_t *mode)
Validate mode selection, required arguments, and per-mode options.
static mdl_cli_mode_t internal_resolve_mode(const mdl_args_t *a, size_t *count)
Resolve primary-mode fields and count their selections.
mdl_cli_cap_t
Default per-response size cap: bound a hostile/broken stream.
@ k_max_response_bytes_def
64 MiB per response.
static bool internal_parse_value_opt(int argc, char **argv, int *i, mdl_args_t *a)
Consume one recognized option that requires a value.
static uint64_t internal_value_bit(const void *value, uint64_t bit)
Convert pointer presence to an option-mask bit.
static ra8_err_t internal_validate_network_args(const mdl_args_t *a, ra8_io_stream_t *diagnostic)
Validate mutually exclusive and required network-policy arguments.
static bool internal_parse_bool_flags(const char *arg, mdl_args_t *a)
Consume any recognised boolean flag at arg.
static uint64_t internal_flag_bit(bool value, uint64_t bit)
Convert a Boolean option to an option-mask bit.
static bool internal_cli_allowed_args(const mdl_args_t *a, mdl_cli_mode_t selected, uint64_t *allowed)
Compute the option mask allowed by one selected mode.
mdl_run_opts_t mdl_cli_run_opts(const mdl_args_t *a)
Fold parsed args into the cross-cutting run options.
static bool internal_is_option_value(const char *flag, const char *value)
Decide whether one token is a value for the matched option.
static uint64_t internal_args_mask(const mdl_args_t *a)
Convert populated CLI fields into one presence mask.
void mdl_cli_parse(int argc, char **argv, mdl_args_t *a)
Parse argv into a; numeric fields stay as strings for main.
mdl_cli_run_parse_t
Radix used when materializing the validated response-size option.
@ k_cli_dec_base
Decimal conversion radix.
static bool internal_parse_verify_opt(int argc, char **argv, int *i, mdl_args_t *a)
Consume the optional --verify DIR argument pair.
static void internal_record_mode(bool condition, mdl_cli_mode_t candidate, mdl_cli_mode_t *mode, size_t *count)
Record one selected primary CLI mode.
static ra8_err_t internal_validate_mode_fields(const mdl_args_t *a, ra8_io_stream_t *diagnostic, mdl_cli_mode_t selected)
Validate required and mutually exclusive fields for one mode.
static const char * internal_option_name(uint64_t bit)
static bool internal_take_opt(char **argv, int argc, int *i, const char *flag, const char **dst, bool *bad)
Consume one value-bearing option at the current argument.
Command-line parsing for the mdl CLI.
mdl_cli_mode_t
Exactly one command mode selected by a valid invocation.
@ k_mdl_cli_mode_verify
Verify tracked state/pages/containers.
@ k_mdl_cli_mode_series
Download or update one configured series.
@ k_mdl_cli_mode_artifact
Download one verified HTTPS artifact.
@ k_mdl_cli_mode_page
Debug-download images from one page URL.
@ k_mdl_cli_mode_invalid
No valid primary mode.
@ k_mdl_cli_mode_search
Search a descriptor and optionally pick.
@ k_mdl_cli_mode_pack
Package a local page-image directory.
@ k_mdl_cli_mode_update_all
Update every tracked local series.
@ k_mdl_cli_mode_help
Print command help without running a mode.
@ k_mdl_cli_mode_list
List tracked local series.
@ k_mdl_cli_mode_remove
Remove one tracked local series.
@ k_mdl_cli_mode_browse
Browse a descriptor and optionally pick.
@ k_mdl_cli_mode_version
Print the program version and exit.
@ k_mdl_cli_mode_init_site
Generate a starter descriptor template.
Private byte-stream helpers shared by mdl CLI units.
ra8_err_t priv_mdl_cli_reject_parts(ra8_io_stream_t *stream, const char *const *parts, size_t count)
Write a rejection diagnostic and return invalid-argument status.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
int strncmp(const char *s1, const char *s2, size_t n)
Compare two strings up to a specified length.
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
size_t strlen(const char *s)
Calculate string length.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
Parsed command-line options in string form (converted by main).
const char * proxy
–proxy URL: HTTP/HTTPS proxy URL.
const char * verify_dir
–verify [DIR]: directory to verify.
bool update
–update: fetch only chapters not already complete.
const char * pack
–pack DIR: package an existing folder, no network.
const char * chapters
–chapters.
const char * cfg
–config path.
const char * timeout
–timeout.
const char * page_url
positional page URL (page mode).
bool allow_incomplete
–allow-incomplete: package a run with failed pages.
bool allow_private
–allow-private: permit loopback/private/link-local peers.
const char * remove_series
–remove: series URL/slug to drop from the library.
const char * socks5
–socks5 URL: SOCKS5 proxy URL.
bool verify
–verify: verify existing downloaded archives/files.
const char * contact
–contact: operator identity for the User-Agent.
bool polite
–polite: raise per-host delays.
const char * ca_file
–ca-file FILE: host composition CA input path.
bool progress
–progress: terminal progress bar during downloads.
bool bad
An unrecognised argument was seen.
bool ignore_robots
–ignore-robots: escape hatch (off by default).
const char * out
–out dir.
const char * init_site_url
–init-site URL: generate site descriptor template.
bool update_all
–update-all: incremental update of every tracked series.
bool help
–help/-h: print usage and exit successfully.
bool list
–list: list tracked series with coverage, then exit.
const char * cookie_file
–cookie-file FILE: host composition input path.
bool version
–version: print version and exit successfully.
bool browse
–browse: list a site's latest-updates page.
const char * max_bytes
–max-bytes: per-response size cap.
const char * cache_dir
–cache-dir: persistent per-host cache root.
bool cross_host
–cross-host: permit cross-host redirects.
bool refetch
–refetch: bypass verified local page reuse.
const char * pick
–pick N: download the Nth discovery hit (1-based).
const char * series
–series URL.
bool separate
–separate: one archive per chapter (default: combine).
const char * from
–from: first chapter NUMBER to fetch (not an index).
const char * format
–format (cbz/cbt/cbt.gz/epub/jof/rabook).
Cross-cutting policy and injected transport threaded into every mode.
Caller-allocated byte-stream handle binding a sink to its context.