ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_cli.c
Go to the documentation of this file.
1
9#include "mdl_cli.h"
10
11#include <stdlib.h>
12#include <string.h>
13
14#include "mdl_cli_internal.h"
15#include "ra8_attributes.h"
16
18typedef enum : uint8_t {
21
23typedef enum : uint64_t {
24 k_max_response_bytes_def = 64ULL * 1024ULL * 1024ULL,
26
43RA8_INTERNAL static bool internal_is_option_value(const char* flag, const char* value)
44{
45 if (value == nullptr) {
46 return false;
47 }
48 if (value[0] != '-') {
49 return true;
50 }
51 if (strcmp(flag, "--from") != 0) {
52 return false;
53 }
54 if ((value[1] >= '0') && (value[1] <= '9')) {
55 return true;
56 }
57 return value[1] == '.';
58}
59
82RA8_INTERNAL static bool
83internal_take_opt(char** argv, int argc, int* i, const char* flag, const char** dst, bool* bad)
84{
85 if ((argv[*i] == nullptr) || (strcmp(argv[*i], flag) != 0)) {
86 return false;
87 }
88 if (((*i + 1) < argc) && internal_is_option_value(flag, argv[*i + 1])) {
89 *i += 1;
90 if (*dst != nullptr) {
91 *bad = true;
92 }
93 *dst = argv[*i];
94 } else {
95 *bad = true;
96 }
97 return true;
98}
99
118RA8_INTERNAL static bool internal_take_flag(const char* arg, const char* flag, bool* dst, bool* bad)
119{
120 if ((arg != nullptr) && (strcmp(arg, flag) == 0)) {
121 if (*dst) {
122 *bad = true;
123 }
124 *dst = true;
125 return true;
126 }
127 return false;
128}
129
145RA8_INTERNAL static bool internal_parse_bool_flags(const char* arg, mdl_args_t* a)
146{
147 return internal_take_flag(arg, "--help", &a->help, &a->bad) ||
148 internal_take_flag(arg, "-h", &a->help, &a->bad) ||
149 internal_take_flag(arg, "--version", &a->version, &a->bad) ||
150 internal_take_flag(arg, "--separate", &a->separate, &a->bad) ||
151 internal_take_flag(arg, "--update", &a->update, &a->bad) ||
152 internal_take_flag(arg, "--list", &a->list, &a->bad) ||
153 internal_take_flag(arg, "--update-all", &a->update_all, &a->bad) ||
154 internal_take_flag(arg, "--browse", &a->browse, &a->bad) ||
155 internal_take_flag(arg, "--polite", &a->polite, &a->bad) ||
156 internal_take_flag(arg, "--ignore-robots", &a->ignore_robots, &a->bad) ||
157 internal_take_flag(arg, "--allow-private", &a->allow_private, &a->bad) ||
158 internal_take_flag(arg, "--cross-host", &a->cross_host, &a->bad) ||
159 internal_take_flag(arg, "--allow-incomplete", &a->allow_incomplete, &a->bad) ||
160 internal_take_flag(arg, "--progress", &a->progress, &a->bad) ||
161 internal_take_flag(arg, "--refetch", &a->refetch, &a->bad);
162}
163
182RA8_INTERNAL static bool internal_parse_verify_opt(int argc, char** argv, int* i, mdl_args_t* a)
183{
184 if ((argv[*i] == nullptr) || (strcmp(argv[*i], "--verify") != 0)) {
185 return false;
186 }
187 if (a->verify) {
188 a->bad = true;
189 }
190 a->verify = true;
191 if (((*i + 1) < argc) && (argv[*i + 1] != nullptr) && (argv[*i + 1][0] != '-')) {
192 *i += 1;
193 a->verify_dir = argv[*i];
194 }
195 return true;
196}
197
216RA8_INTERNAL static bool internal_parse_value_opt(int argc, char** argv, int* i, mdl_args_t* a)
217{
218 const struct {
219 const char* flag;
220 const char** dst;
221 } opts[] = {
222 {"--config", &a->cfg},
223 {"--series", &a->series},
224 {"--out", &a->out},
225 {"--cache-dir", &a->cache_dir},
226 {"--attr", &a->attr},
227 {"--chapters", &a->chapters},
228 {"--from", &a->from},
229 {"--max", &a->max},
230 {"--seed", &a->seed},
231 {"--timeout", &a->timeout},
232 {"--format", &a->format},
233 {"--pack", &a->pack},
234 {"--contact", &a->contact},
235 {"--max-bytes", &a->max_bytes},
236 {"--remove", &a->remove_series},
237 {"--search", &a->search},
238 {"--pick", &a->pick},
239 {"--proxy", &a->proxy},
240 {"--socks5", &a->socks5},
241 {"--cookie-file", &a->cookie_file},
242 {"--ca-file", &a->ca_file},
243 {"--init-site", &a->init_site_url},
244 };
245 for (size_t k = 0U; k < (sizeof(opts) / sizeof(opts[0])); ++k) {
246 if (internal_take_opt(argv, argc, i, opts[k].flag, opts[k].dst, &a->bad)) {
247 return true;
248 }
249 }
250 return false;
251}
252
267{
268 if ((arg != nullptr) && (arg[0] != '-')) {
269 if (a->page_url != nullptr) {
270 a->bad = true;
271 }
272 a->page_url = arg;
273 return;
274 }
275 a->bad = true;
276}
277
278void mdl_cli_parse(int argc, char** argv, mdl_args_t* a)
279{
280 for (int i = 1; i < argc; ++i) {
281 if (internal_parse_bool_flags(argv[i], a) || internal_parse_verify_opt(argc, argv, &i, a) ||
282 internal_parse_value_opt(argc, argv, &i, a)) {
283 continue;
284 }
286 }
287}
288
290typedef enum : uint64_t {
291 k_arg_cfg = 1ULL << 0U,
292 k_arg_series = 1ULL << 1U,
293 k_arg_page = 1ULL << 2U,
294 k_arg_out = 1ULL << 3U,
295 k_arg_attr = 1ULL << 4U,
296 k_arg_chapters = 1ULL << 5U,
297 k_arg_from = 1ULL << 6U,
298 k_arg_max = 1ULL << 7U,
299 k_arg_seed = 1ULL << 8U,
300 k_arg_timeout = 1ULL << 9U,
301 k_arg_format = 1ULL << 10U,
302 k_arg_pack = 1ULL << 11U,
303 k_arg_contact = 1ULL << 12U,
304 k_arg_max_bytes = 1ULL << 13U,
305 k_arg_remove = 1ULL << 14U,
306 k_arg_search = 1ULL << 15U,
307 k_arg_pick = 1ULL << 16U,
308 k_arg_proxy = 1ULL << 17U,
309 k_arg_socks5 = 1ULL << 18U,
310 k_arg_cookie = 1ULL << 19U,
311 k_arg_verify_dir = 1ULL << 20U,
312 k_arg_init = 1ULL << 21U,
313 k_arg_browse = 1ULL << 22U,
314 k_arg_separate = 1ULL << 23U,
315 k_arg_update = 1ULL << 24U,
316 k_arg_list = 1ULL << 25U,
317 k_arg_update_all = 1ULL << 26U,
318 k_arg_polite = 1ULL << 27U,
319 k_arg_ignore_robots = 1ULL << 28U,
320 k_arg_allow_private = 1ULL << 29U,
321 k_arg_cross_host = 1ULL << 30U,
323 k_arg_progress = 1ULL << 32U,
324 k_arg_refetch = 1ULL << 33U,
325 k_arg_verify = 1ULL << 34U,
326 k_arg_help = 1ULL << 35U,
327 k_arg_version = 1ULL << 36U,
328 k_arg_ca_file = 1ULL << 37U,
329 k_arg_cache_dir = 1ULL << 38U,
331
346RA8_INTERNAL static uint64_t internal_value_bit(const void* value, uint64_t bit)
347{
348 return (value != nullptr) ? bit : 0U;
349}
350
365RA8_INTERNAL static uint64_t internal_flag_bit(bool value, uint64_t bit)
366{
367 return value ? bit : 0U;
368}
369
384{
413}
414
416{
417 static const char* const names[] = {"invalid",
418 "series",
419 "search",
420 "browse",
421 "list",
422 "update-all",
423 "remove",
424 "verify",
425 "init-site",
426 "pack",
427 "artifact",
428 "page",
429 "help",
430 "version"};
431 return ((unsigned)mode < (sizeof(names) / sizeof(names[0]))) ? names[mode] : names[0];
432}
433
449RA8_INTERNAL static ra8_err_t internal_cli_invalid(ra8_io_stream_t* diagnostic, const char* message)
450{
451 const char* const parts[] = {"mdl: ", message, "\n"};
452 return priv_mdl_cli_reject_parts(diagnostic, parts, sizeof(parts) / sizeof(parts[0]));
453}
454
470RA8_INTERNAL static void
471internal_record_mode(bool condition, mdl_cli_mode_t candidate, mdl_cli_mode_t* mode, size_t* count)
472{
473 if (condition) {
474 *mode = candidate;
475 *count += 1U;
476 }
477}
478
495RA8_INTERNAL static bool internal_cli_ends_ci(const char* text, const char* suffix)
496{
497 const size_t tl = strlen(text);
498 const size_t sl = strlen(suffix);
499 if (sl > tl) {
500 return false;
501 }
502 for (size_t i = 0U; i < sl; ++i) {
503 char a = text[tl - sl + i];
504 char b = suffix[i];
505 if ((a >= 'A') && (a <= 'Z')) {
506 a = (char)(a + ('a' - 'A'));
507 }
508 if ((b >= 'A') && (b <= 'Z')) {
509 b = (char)(b + ('a' - 'A'));
510 }
511 if (a != b) {
512 return false;
513 }
514 }
515 return true;
516}
517
533RA8_INTERNAL static bool internal_cli_artifact_url(const char* url)
534{
535 if (url == nullptr) {
536 return false;
537 }
538 const size_t path_len = strcspn(url, "?#");
539 char path[1024];
540 if ((path_len == 0U) || (path_len >= sizeof(path))) {
541 return false;
542 }
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) {
548 if (internal_cli_ends_ci(path, suffixes[i])) {
549 return true;
550 }
551 }
552 return false;
553}
554
571{
573 internal_record_mode(a->series != nullptr, k_mdl_cli_mode_series, &mode, count);
574 internal_record_mode(a->search != nullptr, k_mdl_cli_mode_search, &mode, count);
578 internal_record_mode(a->remove_series != nullptr, k_mdl_cli_mode_remove, &mode, count);
580 internal_record_mode(a->init_site_url != nullptr, k_mdl_cli_mode_init_site, &mode, count);
581 internal_record_mode(a->pack != nullptr, k_mdl_cli_mode_pack, &mode, count);
582 const bool artifact = internal_cli_artifact_url(a->page_url);
583 internal_record_mode((a->page_url != nullptr) && artifact, k_mdl_cli_mode_artifact, &mode, count);
584 internal_record_mode((a->page_url != nullptr) && !artifact, k_mdl_cli_mode_page, &mode, count);
587 return mode;
588}
589
590RA8_INTERNAL static const char* internal_option_name(uint64_t bit)
591{
592 static const struct {
593 uint64_t bit;
594 const char* name;
595 } names[] = {{k_arg_cfg, "--config"},
596 {k_arg_series, "--series"},
597 {k_arg_page, "URL"},
598 {k_arg_out, "--out"},
599 {k_arg_cache_dir, "--cache-dir"},
600 {k_arg_attr, "--attr"},
601 {k_arg_chapters, "--chapters"},
602 {k_arg_from, "--from"},
603 {k_arg_max, "--max"},
604 {k_arg_seed, "--seed"},
605 {k_arg_timeout, "--timeout"},
606 {k_arg_format, "--format"},
607 {k_arg_pack, "--pack"},
608 {k_arg_contact, "--contact"},
609 {k_arg_max_bytes, "--max-bytes"},
610 {k_arg_remove, "--remove"},
611 {k_arg_search, "--search"},
612 {k_arg_pick, "--pick"},
613 {k_arg_proxy, "--proxy"},
614 {k_arg_socks5, "--socks5"},
615 {k_arg_cookie, "--cookie-file"},
616 {k_arg_ca_file, "--ca-file"},
617 {k_arg_verify_dir, "DIR"},
618 {k_arg_init, "--init-site"},
619 {k_arg_browse, "--browse"},
620 {k_arg_separate, "--separate"},
621 {k_arg_update, "--update"},
622 {k_arg_list, "--list"},
623 {k_arg_update_all, "--update-all"},
624 {k_arg_polite, "--polite"},
625 {k_arg_ignore_robots, "--ignore-robots"},
626 {k_arg_allow_private, "--allow-private"},
627 {k_arg_cross_host, "--cross-host"},
628 {k_arg_allow_incomplete, "--allow-incomplete"},
629 {k_arg_progress, "--progress"},
630 {k_arg_refetch, "--refetch"},
631 {k_arg_verify, "--verify"},
632 {k_arg_help, "--help"},
633 {k_arg_version, "--version"}};
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;
637 }
638 }
639 return "option";
640}
641
659RA8_INTERNAL static bool
660internal_cli_allowed_args(const mdl_args_t* a, mdl_cli_mode_t selected, uint64_t* allowed)
661{
665 const uint64_t download = k_arg_out | k_arg_cache_dir | k_arg_chapters | k_arg_from |
668 switch (selected) {
670 *allowed = k_arg_series | k_arg_cfg | net | download;
671 return true;
673 *allowed =
674 k_arg_search | k_arg_cfg | k_arg_pick | net | ((a->pick != nullptr) ? download : 0U);
675 return true;
677 *allowed =
678 k_arg_browse | k_arg_cfg | k_arg_pick | net | ((a->pick != nullptr) ? download : 0U);
679 return true;
681 *allowed = k_arg_list | k_arg_out;
682 return true;
686 return true;
688 *allowed = k_arg_remove | k_arg_out;
689 return true;
692 return true;
694 *allowed = k_arg_init;
695 return true;
697 *allowed = k_arg_pack | k_arg_format;
698 return true;
700 *allowed = k_arg_page | k_arg_out | net;
701 return true;
703 *allowed = k_arg_page | k_arg_out | k_arg_attr | k_arg_max | net;
704 return true;
706 *allowed = k_arg_help;
707 return true;
709 *allowed = k_arg_version;
710 return true;
711 default:
712 return false;
713 }
714}
715
735 ra8_io_stream_t* diagnostic,
736 mdl_cli_mode_t selected)
737{
738 uint64_t allowed = 0U;
739 if (!internal_cli_allowed_args(a, selected, &allowed)) {
740 return internal_cli_invalid(diagnostic, "invalid command mode");
741 }
742 const uint64_t disallowed = internal_args_mask(a) & ~allowed;
743 if (disallowed == 0U) {
744 return k_ra8_ok;
745 }
746 const char* const parts[] = {"mdl: ",
747 internal_option_name(disallowed),
748 " is not valid in ",
749 mdl_cli_mode_name(selected),
750 " mode\n"};
751 return priv_mdl_cli_reject_parts(diagnostic, parts, sizeof(parts) / sizeof(parts[0]));
752}
753
773 ra8_io_stream_t* diagnostic,
774 mdl_cli_mode_t selected)
775{
776 const bool config_mode =
777 (selected == k_mdl_cli_mode_series) || (selected == k_mdl_cli_mode_search) ||
778 (selected == k_mdl_cli_mode_browse) || (selected == k_mdl_cli_mode_update_all);
779 if (config_mode && ((a->cfg == nullptr) || (a->cfg[0] == '\0'))) {
780 return internal_cli_invalid(diagnostic, "this mode requires --config SITE.conf");
781 }
782 if ((selected == k_mdl_cli_mode_search) && (a->search[0] == '\0')) {
783 return internal_cli_invalid(diagnostic, "--search requires a non-empty term");
784 }
785 if ((selected == k_mdl_cli_mode_pack) && (a->format == nullptr)) {
786 return internal_cli_invalid(diagnostic, "--pack requires an explicit --format");
787 }
788 if ((selected == k_mdl_cli_mode_verify) && (a->verify_dir != nullptr) && (a->out != nullptr)) {
790 diagnostic,
791 "--verify DIR and --out DIR are alternate directory spellings; use one");
792 }
793 if ((selected == k_mdl_cli_mode_artifact) &&
794 (strncmp(a->page_url, "https://", strlen("https://")) != 0)) {
795 return internal_cli_invalid(diagnostic, "direct artifact downloads require an https:// URL");
796 }
797 return k_ra8_ok;
798}
799
818 ra8_io_stream_t* diagnostic)
819{
820 if ((a->proxy != nullptr) && (a->socks5 != nullptr)) {
821 return internal_cli_invalid(diagnostic, "--proxy and --socks5 are mutually exclusive");
822 }
823 if (((a->proxy != nullptr) || (a->socks5 != nullptr)) && !a->allow_private) {
824 return internal_cli_invalid(diagnostic, "--proxy/--socks5 requires --allow-private");
825 }
826 if ((a->attr != nullptr) && (strcmp(a->attr, "data-src") != 0) && (strcmp(a->attr, "src") != 0)) {
827 return internal_cli_invalid(diagnostic, "--attr expects data-src or src");
828 }
829 return k_ra8_ok;
830}
831
833{
834 if ((a == nullptr) || (diagnostic == nullptr) || (mode == nullptr)) {
835 return k_ra8_err_null_ptr;
836 }
838 if (a->bad) {
839 return internal_cli_invalid(diagnostic, "unknown, duplicate, or missing-value option");
840 }
841 size_t primary_count = 0U;
842 const mdl_cli_mode_t selected = internal_resolve_mode(a, &primary_count);
843 if (primary_count == 0U) {
844 return internal_cli_invalid(diagnostic, "exactly one command mode is required");
845 }
846 if (primary_count != 1U) {
847 return internal_cli_invalid(diagnostic, "command modes are mutually exclusive");
848 }
849 ra8_err_t err = internal_validate_allowed_args(a, diagnostic, selected);
850 if (err == k_ra8_ok) {
851 err = internal_validate_mode_fields(a, diagnostic, selected);
852 }
853 if (err == k_ra8_ok) {
854 err = internal_validate_network_args(a, diagnostic);
855 }
856 if (err != k_ra8_ok) {
857 return err;
858 }
859 *mode = selected;
860 return k_ra8_ok;
861}
863{
864 const uint64_t max_bytes = (a->max_bytes == nullptr)
865 ? (uint64_t)k_max_response_bytes_def
866 : strtoull(a->max_bytes, nullptr, k_cli_dec_base);
867 return (mdl_run_opts_t){
868 .policy = {.allow_private_hosts = a->allow_private,
869 .allow_cross_host_redirect = a->cross_host,
870 .max_response_bytes = max_bytes,
871 .proxy = a->proxy,
872 .socks5 = a->socks5},
873 .contact = a->contact,
874 .honor_robots = !a->ignore_robots,
875 .polite = a->polite,
876 .allow_incomplete = a->allow_incomplete,
877 .progress = a->progress,
878 .refetch = a->refetch,
879 };
880}
static ra8_err_t internal_cli_invalid(ra8_io_stream_t *diagnostic, const char *message)
Emit one CLI validation diagnostic and return canonical rejection.
Definition mdl_cli.c:449
static bool internal_take_flag(const char *arg, const char *flag, bool *dst, bool *bad)
Consume one bare Boolean option.
Definition mdl_cli.c:118
static void internal_parse_positional_or_bad(const char *arg, mdl_args_t *a)
Record a positional URL or reject an unexpected token.
Definition mdl_cli.c:266
static bool internal_cli_ends_ci(const char *text, const char *suffix)
Test an ASCII suffix without case sensitivity.
Definition mdl_cli.c:495
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.
Definition mdl_cli.c:734
mdl_cli_arg_bit_t
Bit positions for every CLI spelling, used by mode allowlists.
Definition mdl_cli.c:290
@ k_arg_init
--init-site.
Definition mdl_cli.c:312
@ k_arg_page
Positional URL.
Definition mdl_cli.c:293
@ k_arg_version
--version.
Definition mdl_cli.c:327
@ k_arg_cfg
--config.
Definition mdl_cli.c:291
@ k_arg_proxy
--proxy.
Definition mdl_cli.c:308
@ k_arg_list
--list.
Definition mdl_cli.c:316
@ k_arg_format
--format.
Definition mdl_cli.c:301
@ k_arg_max
--max.
Definition mdl_cli.c:298
@ k_arg_verify
--verify.
Definition mdl_cli.c:325
@ k_arg_polite
--polite.
Definition mdl_cli.c:318
@ k_arg_timeout
--timeout.
Definition mdl_cli.c:300
@ k_arg_browse
--browse.
Definition mdl_cli.c:313
@ k_arg_help
--help.
Definition mdl_cli.c:326
@ k_arg_update
--update.
Definition mdl_cli.c:315
@ k_arg_cross_host
--cross-host.
Definition mdl_cli.c:321
@ k_arg_attr
--attr.
Definition mdl_cli.c:295
@ k_arg_verify_dir
Optional verify dir.
Definition mdl_cli.c:311
@ k_arg_cookie
--cookie-file.
Definition mdl_cli.c:310
@ k_arg_update_all
--update-all.
Definition mdl_cli.c:317
@ k_arg_separate
--separate.
Definition mdl_cli.c:314
@ k_arg_refetch
--refetch.
Definition mdl_cli.c:324
@ k_arg_contact
--contact.
Definition mdl_cli.c:303
@ k_arg_pack
--pack.
Definition mdl_cli.c:302
@ k_arg_series
--series.
Definition mdl_cli.c:292
@ k_arg_allow_private
--allow-private.
Definition mdl_cli.c:320
@ k_arg_ca_file
--ca-file.
Definition mdl_cli.c:328
@ k_arg_out
--out.
Definition mdl_cli.c:294
@ k_arg_ignore_robots
--ignore-robots.
Definition mdl_cli.c:319
@ k_arg_pick
--pick.
Definition mdl_cli.c:307
@ k_arg_seed
--seed.
Definition mdl_cli.c:299
@ k_arg_remove
--remove.
Definition mdl_cli.c:305
@ k_arg_socks5
--socks5.
Definition mdl_cli.c:309
@ k_arg_cache_dir
--cache-dir.
Definition mdl_cli.c:329
@ k_arg_max_bytes
--max-bytes.
Definition mdl_cli.c:304
@ k_arg_chapters
--chapters.
Definition mdl_cli.c:296
@ k_arg_progress
--progress.
Definition mdl_cli.c:323
@ k_arg_from
--from.
Definition mdl_cli.c:297
@ k_arg_allow_incomplete
--allow-incomplete.
Definition mdl_cli.c:322
@ k_arg_search
--search.
Definition mdl_cli.c:306
const char * mdl_cli_mode_name(mdl_cli_mode_t mode)
Stable human-readable command mode name.
Definition mdl_cli.c:415
static bool internal_cli_artifact_url(const char *url)
Recognise an artifact suffix in a URL path.
Definition mdl_cli.c:533
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.
Definition mdl_cli.c:832
static mdl_cli_mode_t internal_resolve_mode(const mdl_args_t *a, size_t *count)
Resolve primary-mode fields and count their selections.
Definition mdl_cli.c:570
mdl_cli_cap_t
Default per-response size cap: bound a hostile/broken stream.
Definition mdl_cli.c:23
@ k_max_response_bytes_def
64 MiB per response.
Definition mdl_cli.c:24
static bool internal_parse_value_opt(int argc, char **argv, int *i, mdl_args_t *a)
Consume one recognized option that requires a value.
Definition mdl_cli.c:216
static uint64_t internal_value_bit(const void *value, uint64_t bit)
Convert pointer presence to an option-mask bit.
Definition mdl_cli.c:346
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.
Definition mdl_cli.c:817
static bool internal_parse_bool_flags(const char *arg, mdl_args_t *a)
Consume any recognised boolean flag at arg.
Definition mdl_cli.c:145
static uint64_t internal_flag_bit(bool value, uint64_t bit)
Convert a Boolean option to an option-mask bit.
Definition mdl_cli.c:365
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.
Definition mdl_cli.c:660
mdl_run_opts_t mdl_cli_run_opts(const mdl_args_t *a)
Fold parsed args into the cross-cutting run options.
Definition mdl_cli.c:862
static bool internal_is_option_value(const char *flag, const char *value)
Decide whether one token is a value for the matched option.
Definition mdl_cli.c:43
static uint64_t internal_args_mask(const mdl_args_t *a)
Convert populated CLI fields into one presence mask.
Definition mdl_cli.c:383
void mdl_cli_parse(int argc, char **argv, mdl_args_t *a)
Parse argv into a; numeric fields stay as strings for main.
Definition mdl_cli.c:278
mdl_cli_run_parse_t
Radix used when materializing the validated response-size option.
Definition mdl_cli.c:18
@ k_cli_dec_base
Decimal conversion radix.
Definition mdl_cli.c:19
static bool internal_parse_verify_opt(int argc, char **argv, int *i, mdl_args_t *a)
Consume the optional --verify DIR argument pair.
Definition mdl_cli.c:182
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.
Definition mdl_cli.c:471
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.
Definition mdl_cli.c:772
static const char * internal_option_name(uint64_t bit)
Definition mdl_cli.c:590
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.
Definition mdl_cli.c:83
Command-line parsing for the mdl CLI.
mdl_cli_mode_t
Exactly one command mode selected by a valid invocation.
Definition mdl_cli.h:31
@ k_mdl_cli_mode_verify
Verify tracked state/pages/containers.
Definition mdl_cli.h:39
@ k_mdl_cli_mode_series
Download or update one configured series.
Definition mdl_cli.h:33
@ k_mdl_cli_mode_artifact
Download one verified HTTPS artifact.
Definition mdl_cli.h:42
@ k_mdl_cli_mode_page
Debug-download images from one page URL.
Definition mdl_cli.h:43
@ k_mdl_cli_mode_invalid
No valid primary mode.
Definition mdl_cli.h:32
@ k_mdl_cli_mode_search
Search a descriptor and optionally pick.
Definition mdl_cli.h:34
@ k_mdl_cli_mode_pack
Package a local page-image directory.
Definition mdl_cli.h:41
@ k_mdl_cli_mode_update_all
Update every tracked local series.
Definition mdl_cli.h:37
@ k_mdl_cli_mode_help
Print command help without running a mode.
Definition mdl_cli.h:44
@ k_mdl_cli_mode_list
List tracked local series.
Definition mdl_cli.h:36
@ k_mdl_cli_mode_remove
Remove one tracked local series.
Definition mdl_cli.h:38
@ k_mdl_cli_mode_browse
Browse a descriptor and optionally pick.
Definition mdl_cli.h:35
@ k_mdl_cli_mode_version
Print the program version and exit.
Definition mdl_cli.h:45
@ k_mdl_cli_mode_init_site
Generate a starter descriptor template.
Definition mdl_cli.h:40
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.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
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).
Definition mdl_cli.h:57
const char * proxy
–proxy URL: HTTP/HTTPS proxy URL.
Definition mdl_cli.h:76
const char * verify_dir
–verify [DIR]: directory to verify.
Definition mdl_cli.h:80
bool update
–update: fetch only chapters not already complete.
Definition mdl_cli.h:84
const char * pack
–pack DIR: package an existing folder, no network.
Definition mdl_cli.h:70
const char * chapters
–chapters.
Definition mdl_cli.h:64
const char * cfg
–config path.
Definition mdl_cli.h:58
const char * timeout
–timeout.
Definition mdl_cli.h:68
const char * page_url
positional page URL (page mode).
Definition mdl_cli.h:60
bool allow_incomplete
–allow-incomplete: package a run with failed pages.
Definition mdl_cli.h:91
bool allow_private
–allow-private: permit loopback/private/link-local peers.
Definition mdl_cli.h:89
const char * remove_series
–remove: series URL/slug to drop from the library.
Definition mdl_cli.h:73
const char * socks5
–socks5 URL: SOCKS5 proxy URL.
Definition mdl_cli.h:77
bool verify
–verify: verify existing downloaded archives/files.
Definition mdl_cli.h:94
const char * contact
–contact: operator identity for the User-Agent.
Definition mdl_cli.h:71
bool polite
–polite: raise per-host delays.
Definition mdl_cli.h:87
const char * ca_file
–ca-file FILE: host composition CA input path.
Definition mdl_cli.h:79
bool progress
–progress: terminal progress bar during downloads.
Definition mdl_cli.h:92
bool bad
An unrecognised argument was seen.
Definition mdl_cli.h:97
bool ignore_robots
–ignore-robots: escape hatch (off by default).
Definition mdl_cli.h:88
const char * out
–out dir.
Definition mdl_cli.h:61
const char * init_site_url
–init-site URL: generate site descriptor template.
Definition mdl_cli.h:81
bool update_all
–update-all: incremental update of every tracked series.
Definition mdl_cli.h:86
bool help
–help/-h: print usage and exit successfully.
Definition mdl_cli.h:95
bool list
–list: list tracked series with coverage, then exit.
Definition mdl_cli.h:85
const char * attr
–attr.
Definition mdl_cli.h:63
const char * cookie_file
–cookie-file FILE: host composition input path.
Definition mdl_cli.h:78
bool version
–version: print version and exit successfully.
Definition mdl_cli.h:96
bool browse
–browse: list a site's latest-updates page.
Definition mdl_cli.h:82
const char * max_bytes
–max-bytes: per-response size cap.
Definition mdl_cli.h:72
const char * cache_dir
–cache-dir: persistent per-host cache root.
Definition mdl_cli.h:62
bool cross_host
–cross-host: permit cross-host redirects.
Definition mdl_cli.h:90
bool refetch
–refetch: bypass verified local page reuse.
Definition mdl_cli.h:93
const char * seed
–seed.
Definition mdl_cli.h:67
const char * max
–max.
Definition mdl_cli.h:66
const char * pick
–pick N: download the Nth discovery hit (1-based).
Definition mdl_cli.h:75
const char * series
–series URL.
Definition mdl_cli.h:59
bool separate
–separate: one archive per chapter (default: combine).
Definition mdl_cli.h:83
const char * from
–from: first chapter NUMBER to fetch (not an index).
Definition mdl_cli.h:65
const char * format
–format (cbz/cbt/cbt.gz/epub/jof/rabook).
Definition mdl_cli.h:69
Cross-cutting policy and injected transport threaded into every mode.
Definition mdl_app.h:73
Caller-allocated byte-stream handle binding a sink to its context.