18 if (!config || config->num_descriptors == 0) {
19 char *buffer = SAFE_MALLOC(1,
char *);
25 size_t buffer_capacity = 8192;
26 char *buffer = SAFE_MALLOC(buffer_capacity,
char *);
31 safe_snprintf(buffer + offset, buffer_capacity - offset,
"Each option shows which modes it applies to with\n");
32 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".B (modes: ...)\n");
33 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"notation. Default values are shown with\n");
34 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".B (default: ...).\n");
35 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"See the\n");
36 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".B ENVIRONMENT\n");
37 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"section for environment variable equivalents.\n");
38 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".PP\n");
39 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"Configuration precedence (lowest to highest):\n");
40 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".B config.toml\n");
41 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"(see\n");
42 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".BR ascii-chat (5))\n");
43 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"< environment variables <\n");
44 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".B command-line flags.\n");
45 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"Later values override earlier ones.\n");
46 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".PP\n");
47 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"Options marked\n");
48 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".B global\n");
49 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
50 "must be passed before any mode and apply to all modes.\n");
51 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
52 "Mode-specific options are passed after the mode name.\n");
53 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".PP\n");
54 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"The default mode (running\n");
55 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".B ascii-chat\n");
56 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
57 "with no mode) accepts both global and default mode options with no mode specified.\n");
58 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".PP\n");
61 const char **unique_groups = SAFE_MALLOC(config->num_descriptors *
sizeof(
const char *),
const char **);
62 size_t num_unique_groups = 0;
64 for (
size_t i = 0; i < config->num_descriptors; i++) {
65 const option_descriptor_t *desc = &config->descriptors[i];
68 if (desc->hide_from_mode_help || desc->hide_from_binary_help || !desc->group) {
73 bool group_exists =
false;
74 for (
size_t j = 0; j < num_unique_groups; j++) {
75 if (unique_groups[j] && strcmp(unique_groups[j], desc->group) == 0) {
82 if (!group_exists && num_unique_groups < config->num_descriptors) {
83 unique_groups[num_unique_groups++] = desc->group;
88 for (
size_t g = 0; g < num_unique_groups; g++) {
89 const char *current_group = unique_groups[g];
92 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".SS %s\n", current_group);
95 for (
size_t i = 0; i < config->num_descriptors; i++) {
96 const option_descriptor_t *desc = &config->descriptors[i];
99 bool is_binary_option = (desc->mode_bitmask & OPTION_MODE_BINARY) != 0;
100 bool applies_to_mode =
false;
101 if (is_binary_option) {
102 applies_to_mode = !desc->hide_from_binary_help;
104 applies_to_mode = !desc->hide_from_mode_help;
106 if (!applies_to_mode || !desc->group || strcmp(desc->group, current_group) != 0) {
111 if (offset + 512 >= buffer_capacity) {
112 buffer_capacity *= 2;
113 buffer = SAFE_REALLOC(buffer, buffer_capacity,
char *);
117 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".TP\n");
120 if (desc->short_name && desc->short_name !=
'\0') {
121 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".B \\-%c, \\-\\-%s", desc->short_name,
124 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
".B \\-\\-%s", desc->long_name);
128 if (desc->type != OPTION_TYPE_ACTION) {
130 const char *placeholder =
132 if (placeholder && *placeholder) {
133 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
" \\fI%s\\fR", placeholder);
137 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"\n");
140 if (desc->help_text) {
142 if (!desc->default_value) {
143 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"\n");
145 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
" ");
147 }
else if (desc->default_value) {
148 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
" ");
152 if (desc->default_value) {
153 char default_buf[256];
154 memset(default_buf, 0,
sizeof(default_buf));
157 if (n > 0 && default_buf[0] !=
'\0') {
158 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"(default: ");
159 if (desc->type == OPTION_TYPE_STRING) {
162 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"%s", default_buf);
164 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
")\n");
170 if (mode_str && strcmp(mode_str,
"all modes") != 0) {
171 if (strcmp(mode_str,
"global") == 0) {
172 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"(mode: %s)\n", mode_str);
174 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"(modes: %s)\n", mode_str);
179 if (desc->required) {
180 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"[REQUIRED]\n");
185 SAFE_FREE(unique_groups);
186 offset +=
safe_snprintf(buffer + offset, buffer_capacity - offset,
"\n");
188 log_debug(
"Generated OPTIONS section (%zu bytes)", offset);