22 #define COLOUR_ARG eColourWhite
38 static size_t longest_line(
const char *str)
43 for (
size_t i = 0; str[i]; i++)
49 longest =
CT_MAX(longest, current);
54 return CT_MAX(longest, current);
57 static const char *get_arg_prefix(
bool win_style,
arg_style_t style)
65 static bool should_skip_arg(
bool win_style,
arg_style_t style)
67 return (!win_style && style == eArgDOS);
70 static size_t get_arg_length(
const cfg_info_t *info,
bool win_style)
74 for (
size_t i = 0; i < args.
count; i++)
77 if (should_skip_arg(
false, arg.
style))
88 size_t longest_brief = 0;
93 for (
size_t i = 0; i < field_count; i++)
97 size_t len = get_arg_length(info, win_style);
98 largest =
CT_MAX(largest, len);
100 size_t brief_len = longest_line(info->
brief);
102 longest_brief =
CT_MAX(longest_brief, brief_len);
107 .brief_alignment = longest_brief + 1
120 for (
size_t i = 0; i < args.
count; i++)
123 if (should_skip_arg(win_style, arg.
style))
126 const char *prefix = get_arg_prefix(win_style, arg.
style);
135 static void print_range(
io_t *io,
int min,
int max)
158 static const char *get_enum_option(
const cfg_choice_t *choices,
size_t len,
size_t choice)
160 for (
size_t i = 0; i < len; i++)
162 if (choices[i].value == choice)
164 return choices[i].
text;
174 const char *option = get_enum_option(info->options, info->
count, info->
initial);
185 for (
size_t i = 0; i < info->
count; i++)
190 if (i != info->
count - 1)
205 for (
size_t i = 0; i < info->
count; i++)
230 for (
size_t i = 0; i < info->
count; i++)
235 if (i != info->
count - 1)
261 for (
size_t i = 0; i < len; i++)
286 io_printf(options.
io,
"(default: %d)", info->initial);
287 print_range(options.
io, info->min, info->max);
292 case eConfigVector: {
294 print_vector(options.
io, info);
299 case eConfigString: {
310 print_enum_default(options, field);
315 print_flags_default(options, field);
332 print_enum(options, alignment, field);
337 print_flags(options, alignment, field);
352 size_t offset = print_field_args(options, info, win_style);
357 bool needs_second_line =
false;
361 if (first_newline == SIZE_MAX)
369 print_field_default(options, field);
381 print_field_default(options, field);
385 size_t start = first_newline + 1;
387 for (
size_t i = start; info->
brief[i]; i++)
390 if (info->
brief[i] ==
'\n')
392 io_printf(options.
io,
"%s%.*s\n", pad_remaining, (
int)len, info->
brief + start);
400 io_printf(options.
io,
"%s%.*s\n", pad_remaining, (
int)len, info->
brief + start);
403 needs_second_line =
true;
406 return print_field_details(options, alignment, field) || needs_second_line;
421 for (
size_t i = 0; i < field_count; i++)
424 bool needs_second_line = print_field_info(options, alignment, win_style, field);
425 if (needs_second_line && i != field_count - 1)
435 for (
size_t i = 0; i < group_count; i++)
438 print_config_group(options, win_style, group);
446 io_printf(options.
io,
"usage: %s [options] files...\n\n", name);
448 " +--- About --------------------------------------------------------------------------+\n"
449 " | The command line supports both posix and windows flag syntax |\n"
450 " | meaning that any flag that can be prefixed with a single dash |\n"
451 " | can also be prefixed with a forward slash. For example: -h and /h are equivalent. |\n"
452 " | String arguments can be quoted to allow spaces, For example: -o \"output file\" |\n"
453 " | `:`, `=`, or a space can be used to separate the flag from the value |\n"
454 " | -o:output.txt, -o=output.txt, -o output.txt |\n"
455 " | A single flag argument may be specified in multiple parts. |\n"
456 " | For example: /cpp:c++20 /cpp:modules and /cpp:\"c++20,modules\" are all equivilent |\n"
457 " | A leading `-` may be used to disable a flag. For example: /cpp:-modules |\n"
458 " +------------------------------------------------------------------------------------+\n\n"
474 print_usage(format_config, print.
name);
477 print_config_group(format_config, print.
win_style, config);
STA_DECL char * colour_format(format_context_t context, colour_t idx, const char *fmt,...)
#define STA_DECL
sal2 annotation on function implementations to copy annotations from the declaration
CT_NODISCARD CT_PUREFN CT_BASE_API size_t ctu_strlen(const char *str)
get the length of a string not including the null terminator equivalent to strlen but with safety che...
CT_PUREFN CT_CONFIG_API const vector_t * cfg_vector_info(const cfg_field_t *field)
get the information about a vector field
CT_CONSTFN CT_CONFIG_API const char * cfg_arg_prefix(arg_style_t style)
get the prefix for an argument style
CT_PUREFN CT_CONFIG_API bool cfg_bool_info(const cfg_field_t *field)
get the information about a yes/no field
CT_PUREFN CT_CONFIG_API const cfg_info_t * cfg_group_info(const cfg_group_t *config)
get the information about a configuration group
CT_CONSTFN CT_CONFIG_API const char * cfg_type_string(cfg_type_t type)
get the name of a configuration type
CT_PUREFN CT_CONFIG_API typevec_t * cfg_get_groups(const cfg_group_t *config)
get all subgroups in a configuration group
CT_PUREFN CT_CONFIG_API const cfg_int_t * cfg_int_info(const cfg_field_t *field)
get the information about an integer field
CT_PUREFN CT_CONFIG_API const cfg_enum_t * cfg_enum_info(const cfg_field_t *field)
get the information about a choice field
CT_PUREFN CT_CONFIG_API const cfg_enum_t * cfg_flags_info(const cfg_field_t *field)
get the information about a flags field
CT_PUREFN CT_CONFIG_API const char * cfg_string_info(const cfg_field_t *field)
get the information about a string field
CT_PUREFN CT_CONFIG_API vector_t * cfg_get_fields(const cfg_group_t *config)
get all fields in a configuration group
CT_PUREFN CT_CONFIG_API cfg_type_t cfg_get_type(const cfg_field_t *field)
get the type of a configuration field
CT_PUREFN CT_CONFIG_API const cfg_info_t * cfg_get_info(const cfg_field_t *field)
get the information about a configuration field
CT_IO_API size_t io_printf(io_t *io, STA_FORMAT_STRING const char *fmt,...)
printf to an io object
#define CT_NEVER(...)
assert that a code path is never reached
#define CTASSERT(expr)
assert a condition, prints the condition as a message
CT_PUREFN CT_STD_API size_t str_find(const char *str, const char *sub)
find the first instance of a substring in a string
CT_NODISCARD CT_STD_API char * str_repeat(const char *str, size_t times, arena_t *arena)
repeat a string
CT_NODISCARD CT_PUREFN CT_STD_API size_t typevec_len(const typevec_t *vec)
get the length of a vector
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
CT_NODISCARD CT_PUREFN CT_STD_API void * vector_get(const vector_t *vector, size_t index)
get a value from a vector
CT_NODISCARD CT_PUREFN CT_STD_API size_t vector_len(const vector_t *vector)
get the length of a vector
a choice in a set of options
STA_FIELD_STRING const char * text
the name of this choice
size_t value
the value of this choice
a choice from a set of options
size_t initial
the initial choice this must match the value of one of the choices
size_t count
the number of choices in this set
information about a configuration field
STA_FIELD_STRING const char * brief
a brief description of this field
cfg_arg_array_t args
the spellings to use for this field
STA_FIELD_STRING const char * name
the name of this field
arena_t * arena
temporary arena
a formatting context when using colours
const char * name
command line name of this program
print_options_t options
generic print options
bool print_usage
should the command line usage header be printed
bool win_style
which platform to format for if true, all flags will be formatted with a leading slash if false,...
A vector with a fixed type size.
a generic vector of pointers