Cthulhu  0.2.10
Cthulhu compiler collection
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
argparse.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-only
2 
3 #include "common.h"
4 
5 #include "base/panic.h"
6 #include "arena/arena.h"
7 
8 #include "std/map.h"
9 #include "std/str.h"
10 #include "std/typed/vector.h"
11 #include "std/vector.h"
12 
13 #include "config/config.h"
14 
15 // internals
16 
17 static ap_callback_t *ap_callback_new(ap_event_t event, void *data, arena_t *arena)
18 {
19  ap_callback_t *self = ARENA_MALLOC(sizeof(ap_callback_t), "posarg_callback", NULL, arena);
20  self->callback = event;
21  self->data = data;
22  return self;
23 }
24 
25 static void add_pos_callback(ap_t *self, ap_callback_t *cb)
26 {
27  vector_push(&self->posarg_callbacks, cb);
28 }
29 
30 static void add_arg_callback(ap_t *self, const cfg_field_t *param, ap_callback_t *cb)
31 {
32  vector_t *events = map_get(self->event_lookup, param);
33 
34  if (events == NULL)
35  {
36  events = vector_init(cb, self->arena);
37  }
38  else
39  {
40  vector_push(&events, cb);
41  }
42 
43  map_set(self->event_lookup, param, events);
44 }
45 
47 
48 static void add_arg(ap_t *ap, const char *arg, cfg_field_t *field)
49 {
50  const cfg_field_t *existing = map_get(ap->name_lookup, arg);
51  if (existing != NULL)
52  {
53  const cfg_info_t *info = cfg_get_info(field);
54  const cfg_info_t *prev = cfg_get_info(existing);
55  CT_NEVER("a flag `%s` already exists (new: %s, old: %s)", arg, info->name, prev->name);
56  }
57 
58  map_set(ap->name_lookup, arg, field);
59 }
60 
61 static void add_single_field(ap_t *ap, cfg_field_t *field)
62 {
63  CTASSERT(ap != NULL);
64  CTASSERT(field != NULL);
65 
66  const cfg_info_t *info = cfg_get_info(field);
67 
68  cfg_arg_array_t args = info->args;
69  for (size_t i = 0; i < args.count; i++)
70  {
71  cfg_arg_t arg = args.args[i];
72  add_arg(ap, arg.arg, field);
73  }
74 }
75 
76 static void add_config_fields(ap_t *ap, const cfg_group_t *config)
77 {
78  vector_t *fields = cfg_get_fields(config);
79  size_t field_count = vector_len(fields);
80  for (size_t i = 0; i < field_count; i++)
81  {
82  cfg_field_t *field = vector_get(fields, i);
83  add_single_field(ap, field);
84  }
85 
86  typevec_t *groups = cfg_get_groups(config);
87  size_t group_count = typevec_len(groups);
88  for (size_t i = 0; i < group_count; i++)
89  {
90  const cfg_group_t *group = typevec_offset(groups, i);
91  add_config_fields(ap, group);
92  }
93 }
94 
95 // construction
96 
97 ap_t *ap_new(cfg_group_t *config, arena_t *arena)
98 {
99  CTASSERT(config != NULL);
100 
101  ap_t *self = ARENA_MALLOC(sizeof(ap_t), "argparse", config, arena);
102 
103  self->arena = arena;
104  self->config = config;
105 
106  self->name_lookup = map_optimal(256, kTypeInfoString, arena);
107  self->event_lookup = map_optimal(256, kTypeInfoPtr, arena);
108 
109  self->posarg_callbacks = vector_new(16, arena);
110 
111  self->posargs = vector_new(16, arena);
112  self->unknown = vector_new(16, arena);
113  self->errors = vector_new(16, arena);
114  self->count = 0;
115 
116  ARENA_IDENTIFY(self->name_lookup, "name_lookup", self, arena);
117  ARENA_IDENTIFY(self->event_lookup, "event_lookup", self, arena);
118  ARENA_IDENTIFY(self->posarg_callbacks, "posarg_callbacks", self, arena);
119  ARENA_IDENTIFY(self->posargs, "posargs", self, arena);
120  ARENA_IDENTIFY(self->unknown, "unknown", self, arena);
121  ARENA_IDENTIFY(self->errors, "errors", self, arena);
122 
123  add_config_fields(self, config);
124 
125  return self;
126 }
127 
128 void ap_update(ap_t *self)
129 {
130  CTASSERT(self != NULL);
131 
132  // TODO: this is a bit aggressive
133  map_reset(self->name_lookup);
134  map_reset(self->event_lookup);
135 
136  add_config_fields(self, self->config);
137 }
138 
139 void ap_event(ap_t *self, const cfg_field_t *param, ap_event_t callback, void *data)
140 {
141  CTASSERT(self != NULL);
142  CTASSERT(callback != NULL);
143 
144  ap_callback_t *fn = ap_callback_new(callback, data, self->arena);
145  ARENA_REPARENT(fn, self, self->arena);
146 
147  if (param == NULL)
148  {
149  add_pos_callback(self, fn);
150  }
151  else
152  {
153  add_arg_callback(self, param, fn);
154  }
155 }
156 
157 STA_DECL
159 {
160  CTASSERT(self != NULL);
161 
162  return self->posargs;
163 }
164 
165 STA_DECL
167 {
168  CTASSERT(self != NULL);
169 
170  return self->unknown;
171 }
172 
173 STA_DECL
175 {
176  CTASSERT(self != NULL);
177 
178  return self->errors;
179 }
180 
181 size_t ap_count_params(ap_t *self)
182 {
183  CTASSERT(self != NULL);
184 
185  return self->count;
186 }
#define STA_DECL
sal2 annotation on function implementations to copy annotations from the declaration
size_t ap_count_params(ap_t *self)
get the number of processed arguments
Definition: argparse.c:181
STA_DECL vector_t * ap_get_unknown(ap_t *self)
get all unknown arguments
Definition: argparse.c:166
void ap_event(ap_t *self, const cfg_field_t *param, ap_event_t callback, void *data)
add a callback event to a parameter
Definition: argparse.c:139
ap_t * ap_new(cfg_group_t *config, arena_t *arena)
create a new parser instance
Definition: argparse.c:97
void ap_update(ap_t *self)
update the parser with the latest config
Definition: argparse.c:128
STA_DECL vector_t * ap_get_posargs(ap_t *self)
get all positional arguments
Definition: argparse.c:158
bool(* ap_event_t)(ap_t *ap, const cfg_field_t *param, const void *value, void *data)
callback for a parameter event called when a parameter is parsed return true to indicate the event wa...
Definition: argparse.h:44
STA_DECL vector_t * ap_get_errors(ap_t *self)
get all errors
Definition: argparse.c:174
CT_PUREFN CT_CONFIG_API typevec_t * cfg_get_groups(const cfg_group_t *config)
get all subgroups in a configuration group
Definition: reflect.c:30
CT_PUREFN CT_CONFIG_API vector_t * cfg_get_fields(const cfg_group_t *config)
get all fields in a configuration group
Definition: reflect.c:38
CT_PUREFN CT_CONFIG_API const cfg_info_t * cfg_get_info(const cfg_field_t *field)
get the information about a configuration field
Definition: reflect.c:14
CT_NODISCARD CT_STD_API map_t * map_optimal(size_t size, hash_info_t info, arena_t *arena)
create a new map with an optimal size
Definition: optimal.c:85
CT_STD_API void map_reset(map_t *map)
clear all key-value pairs from a map
Definition: map.c:386
CT_STD_API void map_set(map_t *map, const void *key, void *value)
set a key-value pair in a map
Definition: map.c:294
CT_NODISCARD CT_PUREFN CT_STD_API void * map_get(const map_t *map, const void *key)
get a value from a map
Definition: map.c:324
#define ARENA_IDENTIFY(ptr, name, parent, arena)
rename and reparent a pointer in a custom allocator
Definition: arena.h:409
#define ARENA_REPARENT(arena, ptr, parent)
reparent a pointer in a custom allocator
Definition: arena.h:391
#define ARENA_MALLOC(size, name, parent, arena)
allocate memory from a custom allocator
Definition: arena.h:392
#define CT_NEVER(...)
assert that a code path is never reached
Definition: panic.h:136
#define CTASSERT(expr)
assert a condition, prints the condition as a message
Definition: panic.h:130
CT_STD_API const hash_info_t kTypeInfoString
type information for a c style string
Definition: typeinfo.c:35
CT_STD_API const hash_info_t kTypeInfoPtr
type information for a generic pointer this operates on the pointer itself and not the data it points...
Definition: typeinfo.c:41
CT_NODISCARD CT_PUREFN CT_STD_API size_t typevec_len(const typevec_t *vec)
get the length of a vector
Definition: vector.c:120
CT_NODISCARD CT_PUREFN CT_STD_API void * typevec_offset(const typevec_t *vec, size_t index)
get a pointer to the value at the given index
Definition: vector.c:191
CT_NODISCARD CT_PUREFN CT_STD_API void * vector_get(const vector_t *vector, size_t index)
get a value from a vector
Definition: vector.c:134
CT_NODISCARD CT_STD_API vector_t * vector_new(size_t size, arena_t *arena)
create a new vector with an initial capacity
Definition: vector.c:63
CT_STD_API void vector_push(vector_t **vector, void *value)
push a value onto the end of a vector
Definition: vector.c:108
CT_NODISCARD CT_STD_API vector_t * vector_init(void *value, arena_t *arena)
create a new vector with a single initial value
Definition: vector.c:79
CT_NODISCARD CT_PUREFN CT_STD_API size_t vector_len(const vector_t *vector)
get the length of a vector
Definition: vector.c:152
argparse instance
Definition: common.h:26
map_t * name_lookup
a mapping of names to parameters
Definition: common.h:35
an allocator object
Definition: arena.h:86
const cfg_arg_t * args
Definition: config.h:61
size_t count
Definition: config.h:62
const char * arg
Definition: config.h:47
information about a configuration field
Definition: config.h:69
cfg_arg_array_t args
the spellings to use for this field
Definition: config.h:77
STA_FIELD_STRING const char * name
the name of this field
Definition: config.h:71
A vector with a fixed type size.
Definition: vector.h:24
a generic vector of pointers
Definition: vector.c:16