ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
options.h File Reference

OPTIONS section generator for man pages. More...

Go to the source code of this file.

Functions

char * manpage_content_generate_options (const options_config_t *config)
 Generate OPTIONS section content.
 
void manpage_content_free_options (char *content)
 Free generated options content.
 

Detailed Description

OPTIONS section generator for man pages.

Generates the OPTIONS section from option descriptors in the config.

Definition in file include/ascii-chat/options/manpage/content/options.h.

Function Documentation

◆ manpage_content_free_options()

void manpage_content_free_options ( char *  content)

Free generated options content.

Parameters
[in]contentContent to free (can be NULL)

Definition at line 203 of file lib/options/manpage/content/options.c.

203 {
204 if (content) {
205 SAFE_FREE(content);
206 }
207}
#define SAFE_FREE(ptr)
Definition common.h:376

References SAFE_FREE.

Referenced by options_config_generate_manpage_merged(), and options_config_generate_manpage_template().

◆ manpage_content_generate_options()

char * manpage_content_generate_options ( const options_config_t *  config)

Generate OPTIONS section content.

Creates formatted OPTIONS section from option descriptors, grouped by category with proper groff formatting.

Parameters
[in]configOptions configuration with descriptors
Returns
Newly allocated content string (caller must free)

Definition at line 17 of file lib/options/manpage/content/options.c.

17 {
18 if (!config) {
19 char *buffer = SAFE_MALLOC(1, char *);
20 buffer[0] = '\0';
21 return buffer;
22 }
23
24 if (config->num_descriptors == 0) {
25 // Generate fallback content when no options are defined
26 size_t buffer_capacity = 512;
27 char *buffer = SAFE_MALLOC(buffer_capacity, char *);
28 size_t offset = 0;
29 offset += safe_snprintf(buffer + offset, buffer_capacity - offset,
30 ".PP\nNo command-line options are available for this mode.\n");
31 log_debug("Generated OPTIONS section (fallback - no options found)");
32 return buffer;
33 }
34
35 // Use a growing buffer for dynamic content
36 size_t buffer_capacity = 8192;
37 char *buffer = SAFE_MALLOC(buffer_capacity, char *);
38 size_t offset = 0;
39
40 // Add introductory paragraph explaining mode flags, defaults, and env vars
41 offset +=
42 safe_snprintf(buffer + offset, buffer_capacity - offset, "Each option shows which modes it applies to with\n");
43 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".B (modes: ...)\n");
44 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "notation. Default values are shown with\n");
45 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".B (default: ...).\n");
46 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "See the\n");
47 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".B ENVIRONMENT\n");
48 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "section for environment variable equivalents.\n");
49 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".PP\n");
50 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "Configuration precedence (lowest to highest):\n");
51 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".B config.toml\n");
52 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "(see\n");
53 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".BR ascii-chat (5))\n");
54 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "< environment variables <\n");
55 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".B command-line flags.\n");
56 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "Later values override earlier ones.\n");
57 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".PP\n");
58 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "Options marked\n");
59 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".B global\n");
60 offset += safe_snprintf(buffer + offset, buffer_capacity - offset,
61 "must be passed before any mode and apply to all modes.\n");
62 offset += safe_snprintf(buffer + offset, buffer_capacity - offset,
63 "Mode-specific options are passed after the mode name.\n");
64 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".PP\n");
65 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "The default mode (running\n");
66 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".B ascii-chat\n");
67 offset += safe_snprintf(buffer + offset, buffer_capacity - offset,
68 "with no mode) accepts both global and default mode options with no mode specified.\n");
69 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".PP\n");
70
71 // Build list of unique groups in order of first appearance
72 const char **unique_groups = SAFE_MALLOC(config->num_descriptors * sizeof(const char *), const char **);
73 size_t num_unique_groups = 0;
74
75 for (size_t i = 0; i < config->num_descriptors; i++) {
76 const option_descriptor_t *desc = &config->descriptors[i];
77
78 // Skip hidden options
79 if (desc->hide_from_mode_help || desc->hide_from_binary_help || !desc->group) {
80 continue;
81 }
82
83 // Check if this group is already in the list
84 bool group_exists = false;
85 for (size_t j = 0; j < num_unique_groups; j++) {
86 if (unique_groups[j] && strcmp(unique_groups[j], desc->group) == 0) {
87 group_exists = true;
88 break;
89 }
90 }
91
92 // Add new group to list
93 if (!group_exists && num_unique_groups < config->num_descriptors) {
94 unique_groups[num_unique_groups++] = desc->group;
95 }
96 }
97
98 // Print options grouped by category
99 for (size_t g = 0; g < num_unique_groups; g++) {
100 const char *current_group = unique_groups[g];
101
102 // Add section heading for each group
103 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".SS %s\n", current_group);
104
105 // Print all options in this group
106 for (size_t i = 0; i < config->num_descriptors; i++) {
107 const option_descriptor_t *desc = &config->descriptors[i];
108
109 // Skip if not in current group or if hidden
110 bool is_binary_option = (desc->mode_bitmask & OPTION_MODE_BINARY) != 0;
111 bool applies_to_mode = false;
112 if (is_binary_option) {
113 applies_to_mode = !desc->hide_from_binary_help;
114 } else {
115 applies_to_mode = !desc->hide_from_mode_help;
116 }
117 if (!applies_to_mode || !desc->group || strcmp(desc->group, current_group) != 0) {
118 continue;
119 }
120
121 // Ensure buffer is large enough
122 if (offset + 512 >= buffer_capacity) {
123 buffer_capacity *= 2;
124 buffer = SAFE_REALLOC(buffer, buffer_capacity, char *);
125 }
126
127 // Start option item
128 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".TP\n");
129
130 // Write option flags
131 if (desc->short_name && desc->short_name != '\0') {
132 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".B \\-%c, \\-\\-%s", desc->short_name,
133 desc->long_name);
134 } else {
135 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".B \\-\\-%s", desc->long_name);
136 }
137
138 // Add argument placeholder for value-taking options
139 if (desc->type != OPTION_TYPE_ACTION) {
140 // Check for custom placeholder first, fall back to type-based placeholder
141 const char *placeholder =
143 if (placeholder && *placeholder) {
144 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, " \\fI%s\\fR", placeholder);
145 }
146 }
147
148 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "\n");
149
150 // Write help text
151 if (desc->help_text) {
152 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "%s", escape_groff_special(desc->help_text));
153 if (!desc->default_value) {
154 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "\n");
155 } else {
156 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, " ");
157 }
158 } else if (desc->default_value) {
159 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, " ");
160 }
161
162 // Add default value if present
163 if (desc->default_value) {
164 char default_buf[256];
165 memset(default_buf, 0, sizeof(default_buf)); // Initialize buffer to prevent garbage
166 int n = options_format_default_value(desc->type, desc->default_value, default_buf, sizeof(default_buf));
167 // Skip empty strings (like --grep's default of "")
168 if (n > 0 && default_buf[0] != '\0') {
169 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "(default: ");
170 if (desc->type == OPTION_TYPE_STRING) {
171 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "%s", escape_groff_special(default_buf));
172 } else {
173 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "%s", default_buf);
174 }
175 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ")\n");
176 }
177 }
178
179 // Add mode information if applicable
180 const char *mode_str = format_mode_names(desc->mode_bitmask);
181 if (mode_str && strcmp(mode_str, "all modes") != 0) {
182 if (strcmp(mode_str, "global") == 0) {
183 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "(mode: %s)\n", mode_str);
184 } else {
185 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "(modes: %s)\n", mode_str);
186 }
187 }
188
189 // Add REQUIRED note if applicable
190 if (desc->required) {
191 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "[REQUIRED]\n");
192 }
193 }
194 }
195
196 SAFE_FREE(unique_groups);
197 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "\n");
198
199 log_debug("Generated OPTIONS section (%zu bytes)", offset);
200 return buffer;
201}
@ OPTION_TYPE_STRING
String value (–name foo)
Definition builder.h:164
@ OPTION_TYPE_ACTION
Action that executes and may exit (–list-webcams, etc.)
Definition builder.h:167
#define SAFE_REALLOC(ptr, size, cast)
Definition common.h:284
#define SAFE_MALLOC(size, cast)
Definition common.h:264
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:548
const char * escape_groff_special(const char *str)
Escape special groff/troff characters in text.
const char * format_mode_names(option_mode_bitmask_t mode_bitmask)
Format option mode names as human-readable string.
@ OPTION_MODE_BINARY
Binary-level options (parsed before mode detection)
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.
Definition system.c:148
int options_format_default_value(option_type_t type, const void *default_value, char *buf, size_t bufsize)
Format option default value to string.
const char * options_get_type_placeholder(option_type_t type)
Get placeholder string for option type.
Option descriptor.
Definition builder.h:241
option_mode_bitmask_t mode_bitmask
Which modes this option applies to.
Definition builder.h:278
const char * help_text
Description for –help.
Definition builder.h:251
bool hide_from_mode_help
If true, don't show in mode-specific help (binary-level only)
Definition builder.h:254
bool hide_from_binary_help
If true, don't show in binary-level help (e.g., in release builds)
Definition builder.h:255
const char * arg_placeholder
Custom argument placeholder (e.g., "SHELL [FILE]" instead of "STR")
Definition builder.h:253
const char * group
Group name for help sections (e.g., "NETWORK OPTIONS")
Definition builder.h:252
const void * default_value
Pointer to default value (or NULL if required)
Definition builder.h:258
bool required
If true, option must be provided.
Definition builder.h:259
const char * long_name
Long option name (e.g., "port")
Definition builder.h:243
char short_name
Short option char (e.g., 'p', or '\0' if none)
Definition builder.h:244
option_type_t type
Value type.
Definition builder.h:247
option_descriptor_t * descriptors
Array of option descriptors.
Definition builder.h:402
size_t num_descriptors
Number of descriptors.
Definition builder.h:403

References option_descriptor_t::arg_placeholder, option_descriptor_t::default_value, options_config_t::descriptors, escape_groff_special(), format_mode_names(), option_descriptor_t::group, option_descriptor_t::help_text, option_descriptor_t::hide_from_binary_help, option_descriptor_t::hide_from_mode_help, log_debug, option_descriptor_t::long_name, option_descriptor_t::mode_bitmask, options_config_t::num_descriptors, OPTION_MODE_BINARY, OPTION_TYPE_ACTION, OPTION_TYPE_STRING, options_format_default_value(), options_get_type_placeholder(), option_descriptor_t::required, SAFE_FREE, SAFE_MALLOC, SAFE_REALLOC, safe_snprintf(), option_descriptor_t::short_name, and option_descriptor_t::type.

Referenced by options_config_generate_manpage_merged(), and options_config_generate_manpage_template().