1/* @title: Command Line */
2#pragma once
3#include <compiler.h>
4#include <linker/symbols.h>
5#include <stdbool.h>
6#include <stddef.h>
7#include <types/type_enum.h>
8
9struct cmdline_entry;
10
11enum cmdline_entry_status {
12 CMDLINE_ENTRY_NOT_FOUND = 0,
13 CMDLINE_ENTRY_DEFAULTED,
14 CMDLINE_ENTRY_FOUND,
15};
16
17enum cmdline_entry_flags {
18 CMDLINE_ENTRY_FLAGS_NONE = 0,
19 CMDLINE_ENTRY_SYMBOLIC = 1, /* This entry serves parenting purposes,
20 * however itself cannot be set to a value */
21 CMDLINE_ENTRY_REQUIRED = 1 << 1,
22};
23
24typedef void (*cmdline_callback)(const char *value, struct cmdline_entry *ent);
25
26/* The idea with parent-child relationships:
27 *
28 * The dot is used as a namespace. With a given cmdline_entry, we trace
29 * its lineage to build out what name it *really* has.
30 *
31 * For instance, if we have
32 *
33 * apple->parent = orange
34 * orange->parent = pineapple
35 * pineapple->parent = NULL
36 *
37 * the "functional name" of apple is
38 *
39 * pineapple.orange.apple */
40struct cmdline_entry {
41 const char *name;
42 const char *desc; /* human readable description */
43 const char *arg; /* value format hint e.g. "<hex bytes>", "<device>" */
44 cmdline_callback callback;
45 char **value;
46 const char *default_val;
47
48 enum cmdline_entry_flags flags;
49 enum cmdline_entry_status status;
50
51 struct cmdline_entry *parent;
52
53 /* Regarding the variable to write to */
54 enum type_enum type;
55 void *write_to;
56 enum errno (*parse)(void *write_to, const char *text);
57
58 void *private;
59
60 /* NOTE: we could keep track of children, but that's not at all mandatory */
61};
62
63#define CMDLINE_ENTRY_DECLARE(n, ...) \
64 LINKER_SECTION_OBJECT(struct cmdline_entry, cmdline_entries) \
65 __cmdline_##n = {.name = #n, \
66 .status = CMDLINE_ENTRY_NOT_FOUND, \
67 .type = TYPE_NONE, \
68 __VA_ARGS__}
69
70#define CMDLINE_ENTRY_DECLARE_TYPED(n, var, ...) \
71 LINKER_SECTION_OBJECT(struct cmdline_entry, cmdline_entries) \
72 __cmdline_##n = {.name = #n, \
73 .status = CMDLINE_ENTRY_NOT_FOUND, \
74 .write_to = &var, \
75 .type = TYPE_TO_ENUM((var)), \
76 __VA_ARGS__}
77
78#define CMDLINE_ENTRY_DECLARE_TYPED_CUSTOM(n, var, pars, ...) \
79 LINKER_SECTION_OBJECT(struct cmdline_entry, cmdline_entries) \
80 __cmdline_##n = {.name = #n, \
81 .status = CMDLINE_ENTRY_NOT_FOUND, \
82 .write_to = &var, \
83 .parse = pars, \
84 .type = TYPE_NONE, \
85 __VA_ARGS__}
86
87#define CMDLINE_ENTRY_DEFINE(n) extern struct cmdline_entry __cmdline_##n
88
89#define CMDLINE_ENTRY(n, ...) &__cmdline_##n
90
91#define CMDLINE_ENTRY_NAME_LEN_MAX 256
92
93LINKER_SECTION_DEFINE(struct cmdline_entry, cmdline_entries);
94
95extern enum errno (*cmdline_parse_table[TYPE_MAX])(void *write_to,
96 const char *text);
97
98enum errno cmdline_parse_fx(void *write_to, const char *text);
99
100/* Returns true if the str matches a 'yes' string, and false if it is a 'no',
101 * although it's a bit more nuanced than that and matches a lot of things.
102 *
103 * panics if neither match */
104bool cmdline_is_enabled(const char *str);
105void cmdline_parse(const char *input);
106bool cmdline_wants_help(const char *input);
107__noreturn void cmdline_dump_help(void);
108