ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_cli_nums.c
Go to the documentation of this file.
1
9#include <errno.h>
10#include <math.h>
11#include <stdint.h>
12#include <stdlib.h>
13
14#include "mdl_cli.h"
15#include "mdl_cli_internal.h"
16#include "ra8_attributes.h"
17
19typedef enum : uint8_t {
22
24typedef enum : uint32_t {
27
29typedef struct {
30 unsigned long timeout;
31 unsigned long chapters;
32 unsigned long max_imgs;
33 unsigned long pick;
34 uint64_t max_bytes;
36
53RA8_INTERNAL static bool internal_cli_parse_ul(const char* s, unsigned long* out)
54{
55 if (s == nullptr) {
56 return false;
57 }
58 if (s[0] < '0') {
59 return false;
60 }
61 if (s[0] > '9') {
62 return false;
63 }
64 errno = 0;
65 char* end = nullptr;
66 const unsigned long v = strtoul(s, &end, k_cli_dec_base);
67 if (errno != 0) {
68 return false;
69 }
70 if (*end != '\0') {
71 return false;
72 }
73 *out = v;
74 return true;
75}
76
93RA8_INTERNAL static bool internal_cli_parse_u64(const char* s, uint64_t* out)
94{
95 if (s == nullptr) {
96 return false;
97 }
98 if (s[0] < '0') {
99 return false;
100 }
101 if (s[0] > '9') {
102 return false;
103 }
104 errno = 0;
105 char* end = nullptr;
106 const unsigned long long v = strtoull(s, &end, k_cli_dec_base);
107 if (errno != 0) {
108 return false;
109 }
110 if (*end != '\0') {
111 return false;
112 }
113 *out = (uint64_t)v;
114 return true;
115}
116
133RA8_INTERNAL static bool internal_cli_parse_chapter(const char* s, double* out)
134{
135 if ((s == nullptr) || (out == nullptr) || (s[0] == '\0')) {
136 return false;
137 }
138 errno = 0;
139 char* end = nullptr;
140 const double v = strtod(s, &end);
141 if ((errno != 0) || (end == s) || (*end != '\0') || !isfinite(v)) {
142 return false;
143 }
144 *out = v;
145 return true;
146}
147
167internal_cli_reject_integer(ra8_io_stream_t* diagnostic, const char* name, const char* value)
168{
169 const char* const parts[] = {"mdl: --",
170 name,
171 " expects a non-negative integer, got '",
172 value,
173 "'\n"};
174 return priv_mdl_cli_reject_parts(diagnostic, parts, sizeof(parts) / sizeof(parts[0]));
175}
176
197 const char* prefix,
198 uint64_t value,
199 const char* suffix)
200{
201 const char* const first[] = {prefix};
202 ra8_err_t err = priv_mdl_cli_put_parts(diagnostic, first, 1U);
203 if (err == k_ra8_ok) {
204 err = ra8_io_stream_put_u64(diagnostic, value);
205 }
206 if (err == k_ra8_ok) {
207 const char* const last[] = {suffix};
208 err = priv_mdl_cli_reject_parts(diagnostic, last, 1U);
209 }
210 return err;
211}
212
235 const char* name,
236 const char* text,
237 unsigned long dflt,
238 unsigned long* out)
239{
240 if (text == nullptr) {
241 *out = dflt;
242 return k_ra8_ok;
243 }
244 unsigned long candidate = 0UL;
245 if (!internal_cli_parse_ul(text, &candidate)) {
246 return internal_cli_reject_integer(diagnostic, name, text);
247 }
248 *out = candidate;
249 return k_ra8_ok;
250}
251
274 const char* name,
275 const char* text,
276 uint64_t dflt,
277 uint64_t* out)
278{
279 if (text == nullptr) {
280 *out = dflt;
281 return k_ra8_ok;
282 }
283 uint64_t candidate = 0U;
284 if (!internal_cli_parse_u64(text, &candidate)) {
285 return internal_cli_reject_integer(diagnostic, name, text);
286 }
287 *out = candidate;
288 return k_ra8_ok;
289}
290
312 ra8_io_stream_t* diagnostic,
313 mdl_nums_t* out,
315{
316 ra8_err_t err = internal_cli_opt_ul(diagnostic,
317 "timeout",
318 a->timeout,
319 (unsigned long)k_req_timeout_def,
320 &raw->timeout);
321 if (err == k_ra8_ok) {
322 err = internal_cli_opt_ul(diagnostic, "chapters", a->chapters, 1UL, &raw->chapters);
323 }
324 if (err == k_ra8_ok) {
325 err = internal_cli_opt_ul(diagnostic, "max", a->max, 0UL, &raw->max_imgs);
326 }
327 if (err == k_ra8_ok) {
328 err = internal_cli_opt_u64(diagnostic, "seed", a->seed, 1U, &out->seed);
329 }
330 if (err == k_ra8_ok) {
331 err = internal_cli_opt_u64(diagnostic, "max-bytes", a->max_bytes, 0U, &raw->max_bytes);
332 }
333 return err;
334}
335
357 ra8_io_stream_t* diagnostic,
358 mdl_nums_t* out,
360{
361 out->from_present = a->from != nullptr;
362 out->from_num = 0.0;
363 if ((a->from != nullptr) && !internal_cli_parse_chapter(a->from, &out->from_num)) {
364 const char* const parts[] = {"mdl: --from expects a finite chapter number, got '",
365 a->from,
366 "'\n"};
367 return priv_mdl_cli_reject_parts(diagnostic, parts, sizeof(parts) / sizeof(parts[0]));
368 }
369 return internal_cli_opt_ul(diagnostic, "pick", a->pick, 0UL, &raw->pick);
370}
371
392 ra8_io_stream_t* diagnostic,
393 const mdl_cli_raw_nums_t* raw)
394{
395 if ((raw->timeout == 0UL) || (raw->timeout > (unsigned long)UINT32_MAX)) {
396 return internal_cli_reject_limit(diagnostic, "mdl: --timeout must be in 1..", UINT32_MAX, "\n");
397 }
398 if ((raw->chapters == 0UL) || ((uintmax_t)raw->chapters > (uintmax_t)SIZE_MAX)) {
399 return internal_cli_reject_limit(diagnostic,
400 "mdl: --chapters must be in 1..",
401 (uint64_t)SIZE_MAX,
402 "\n");
403 }
404 if (raw->max_imgs > (unsigned long)UINT32_MAX) {
405 return internal_cli_reject_limit(diagnostic, "mdl: --max must not exceed ", UINT32_MAX, "\n");
406 }
407 if ((a->max_bytes != nullptr) && (raw->max_bytes == 0U)) {
408 const char* const parts[] = {"mdl: --max-bytes must be greater than zero\n"};
409 return priv_mdl_cli_reject_parts(diagnostic, parts, 1U);
410 }
411 if ((a->pick != nullptr) &&
412 ((raw->pick == 0UL) || ((uintmax_t)raw->pick > (uintmax_t)SIZE_MAX))) {
413 return internal_cli_reject_limit(diagnostic,
414 "mdl: --pick must be in 1..",
415 (uint64_t)SIZE_MAX,
416 "\n");
417 }
418 return k_ra8_ok;
419}
420
422{
423 if ((a == nullptr) || (diagnostic == nullptr) || (n == nullptr)) {
424 return k_ra8_err_null_ptr;
425 }
426 mdl_nums_t candidate = {};
427 mdl_cli_raw_nums_t raw = {};
428 ra8_err_t err = internal_cli_parse_num_values(a, diagnostic, &candidate, &raw);
429 if (err == k_ra8_ok) {
430 err = internal_cli_parse_chapter_pick(a, diagnostic, &candidate, &raw);
431 }
432 if (err == k_ra8_ok) {
433 err = internal_cli_validate_num_ranges(a, diagnostic, &raw);
434 }
435 if (err == k_ra8_ok) {
436 candidate.timeout = (uint32_t)raw.timeout;
437 candidate.chapters = (size_t)raw.chapters;
438 candidate.max_imgs = (uint32_t)raw.max_imgs;
439 candidate.pick = (size_t)raw.pick;
440 *n = candidate;
441 }
442 return err;
443}
@ k_cli_dec_base
Decimal conversion radix.
Definition mdl_cli.c:19
Command-line parsing for the mdl CLI.
Private byte-stream helpers shared by mdl CLI units.
ra8_err_t priv_mdl_cli_put_parts(ra8_io_stream_t *stream, const char *const *parts, size_t count)
Write a bounded ordered vector of NUL-terminated text fragments.
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.
mdl_cli_timeout_t
Default request time budget when --timeout is absent.
@ k_req_timeout_def
Twenty-five seconds in milliseconds.
static ra8_err_t internal_cli_opt_u64(ra8_io_stream_t *diagnostic, const char *name, const char *text, uint64_t dflt, uint64_t *out)
Parse one optional uint64 option or emit its rejection.
static bool internal_cli_parse_ul(const char *s, unsigned long *out)
Parse one complete unsigned-long decimal value.
static bool internal_cli_parse_u64(const char *s, uint64_t *out)
Parse one complete unsigned 64-bit decimal value.
static bool internal_cli_parse_chapter(const char *s, double *out)
Parse one complete finite decimal chapter number for --from.
static ra8_err_t internal_cli_reject_integer(ra8_io_stream_t *diagnostic, const char *name, const char *value)
Reject one option whose value is not an unsigned decimal integer.
ra8_err_t mdl_cli_parse_nums(const mdl_args_t *a, ra8_io_stream_t *diagnostic, mdl_nums_t *n)
Strictly parse and validate every numeric CLI field.
static ra8_err_t internal_cli_reject_limit(ra8_io_stream_t *diagnostic, const char *prefix, uint64_t value, const char *suffix)
Write a rejection line containing one unsigned limit value.
static ra8_err_t internal_cli_validate_num_ranges(const mdl_args_t *a, ra8_io_stream_t *diagnostic, const mdl_cli_raw_nums_t *raw)
Enforce numeric option ranges after complete spelling conversion.
static ra8_err_t internal_cli_opt_ul(ra8_io_stream_t *diagnostic, const char *name, const char *text, unsigned long dflt, unsigned long *out)
Parse one optional unsigned-long option or emit its rejection.
mdl_cli_parse_t
Radix used by strict unsigned decimal parsing.
static ra8_err_t internal_cli_parse_chapter_pick(const mdl_args_t *a, ra8_io_stream_t *diagnostic, mdl_nums_t *out, mdl_cli_raw_nums_t *raw)
Parse chapter and pick values into the candidate numeric record.
static ra8_err_t internal_cli_parse_num_values(const mdl_args_t *a, ra8_io_stream_t *diagnostic, mdl_nums_t *out, mdl_cli_raw_nums_t *raw)
Parse all numeric spellings into a failure-atomic candidate.
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
ra8_err_t ra8_io_stream_put_u64(ra8_io_stream_t *s, uint64_t value)
Write value as unsigned 64-bit decimal ASCII without leading zeros.
Parsed command-line options in string form (converted by main).
Definition mdl_cli.h:57
const char * chapters
–chapters.
Definition mdl_cli.h:64
const char * timeout
–timeout.
Definition mdl_cli.h:68
const char * max_bytes
–max-bytes: per-response size cap.
Definition mdl_cli.h:72
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 * from
–from: first chapter NUMBER to fetch (not an index).
Definition mdl_cli.h:65
Native-width numeric candidates retained until range validation.
unsigned long max_imgs
Parsed image cap before uint32 narrowing.
unsigned long chapters
Parsed chapter count before size_t use.
unsigned long timeout
Parsed timeout before uint32 narrowing.
unsigned long pick
Parsed discovery selection before size_t.
uint64_t max_bytes
Parsed response byte cap.
The validated numeric CLI scalars, parsed once before any run mode.
Definition mdl_cli.h:162
size_t pick
–pick discovery hit (1-based; 0 = list).
Definition mdl_cli.h:169
bool from_present
Whether –from was supplied.
Definition mdl_cli.h:167
uint32_t timeout
–timeout ms (default k_req_timeout_def).
Definition mdl_cli.h:164
size_t chapters
–chapters window (clamped to >= 1).
Definition mdl_cli.h:165
uint32_t max_imgs
–max page images (0 = all).
Definition mdl_cli.h:166
uint64_t seed
–seed (default 1).
Definition mdl_cli.h:163
double from_num
–from chapter number, including decimals.
Definition mdl_cli.h:168
Caller-allocated byte-stream handle binding a sink to its context.