ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
options.c 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)
 
void manpage_content_free_options (char *content)
 

Detailed Description

OPTIONS section generator for man pages.

Definition in file lib/options/manpage/content/options.c.

Function Documentation

◆ manpage_content_free_options()

void manpage_content_free_options ( char *  content)

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

192 {
193 if (content) {
194 SAFE_FREE(content);
195 }
196}

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)

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

17 {
18 if (!config || config->num_descriptors == 0) {
19 char *buffer = SAFE_MALLOC(1, char *);
20 buffer[0] = '\0';
21 return buffer;
22 }
23
24 // Use a growing buffer for dynamic content
25 size_t buffer_capacity = 8192;
26 char *buffer = SAFE_MALLOC(buffer_capacity, char *);
27 size_t offset = 0;
28
29 // Add introductory paragraph explaining mode flags, defaults, and env vars
30 offset +=
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");
59
60 // Build list of unique groups in order of first appearance
61 const char **unique_groups = SAFE_MALLOC(config->num_descriptors * sizeof(const char *), const char **);
62 size_t num_unique_groups = 0;
63
64 for (size_t i = 0; i < config->num_descriptors; i++) {
65 const option_descriptor_t *desc = &config->descriptors[i];
66
67 // Skip hidden options
68 if (desc->hide_from_mode_help || desc->hide_from_binary_help || !desc->group) {
69 continue;
70 }
71
72 // Check if this group is already in the list
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) {
76 group_exists = true;
77 break;
78 }
79 }
80
81 // Add new group to list
82 if (!group_exists && num_unique_groups < config->num_descriptors) {
83 unique_groups[num_unique_groups++] = desc->group;
84 }
85 }
86
87 // Print options grouped by category
88 for (size_t g = 0; g < num_unique_groups; g++) {
89 const char *current_group = unique_groups[g];
90
91 // Add section heading for each group
92 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".SS %s\n", current_group);
93
94 // Print all options in this group
95 for (size_t i = 0; i < config->num_descriptors; i++) {
96 const option_descriptor_t *desc = &config->descriptors[i];
97
98 // Skip if not in current group or if hidden
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;
103 } else {
104 applies_to_mode = !desc->hide_from_mode_help;
105 }
106 if (!applies_to_mode || !desc->group || strcmp(desc->group, current_group) != 0) {
107 continue;
108 }
109
110 // Ensure buffer is large enough
111 if (offset + 512 >= buffer_capacity) {
112 buffer_capacity *= 2;
113 buffer = SAFE_REALLOC(buffer, buffer_capacity, char *);
114 }
115
116 // Start option item
117 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".TP\n");
118
119 // Write option flags
120 if (desc->short_name && desc->short_name != '\0') {
121 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".B \\-%c, \\-\\-%s", desc->short_name,
122 desc->long_name);
123 } else {
124 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ".B \\-\\-%s", desc->long_name);
125 }
126
127 // Add argument placeholder for value-taking options
128 if (desc->type != OPTION_TYPE_ACTION) {
129 // Check for custom placeholder first, fall back to type-based placeholder
130 const char *placeholder =
131 desc->arg_placeholder ? desc->arg_placeholder : options_get_type_placeholder(desc->type);
132 if (placeholder && *placeholder) {
133 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, " \\fI%s\\fR", placeholder);
134 }
135 }
136
137 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "\n");
138
139 // Write help text
140 if (desc->help_text) {
141 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "%s", escape_groff_special(desc->help_text));
142 if (!desc->default_value) {
143 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "\n");
144 } else {
145 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, " ");
146 }
147 } else if (desc->default_value) {
148 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, " ");
149 }
150
151 // Add default value if present
152 if (desc->default_value) {
153 char default_buf[256];
154 memset(default_buf, 0, sizeof(default_buf)); // Initialize buffer to prevent garbage
155 int n = options_format_default_value(desc->type, desc->default_value, default_buf, sizeof(default_buf));
156 // Skip empty strings (like --grep's default of "")
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) {
160 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "%s", escape_groff_special(default_buf));
161 } else {
162 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "%s", default_buf);
163 }
164 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, ")\n");
165 }
166 }
167
168 // Add mode information if applicable
169 const char *mode_str = format_mode_names(desc->mode_bitmask);
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);
173 } else {
174 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "(modes: %s)\n", mode_str);
175 }
176 }
177
178 // Add REQUIRED note if applicable
179 if (desc->required) {
180 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "[REQUIRED]\n");
181 }
182 }
183 }
184
185 SAFE_FREE(unique_groups);
186 offset += safe_snprintf(buffer + offset, buffer_capacity - offset, "\n");
187
188 log_debug("Generated OPTIONS section (%zu bytes)", offset);
189 return buffer;
190}
int options_format_default_value(option_type_t type, const void *default_value, char *buf, size_t bufsize)
const char * options_get_type_placeholder(option_type_t type)
const char * format_mode_names(option_mode_bitmask_t mode_bitmask)
const char * escape_groff_special(const char *str)
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.
Definition system.c:456

References escape_groff_special(), format_mode_names(), options_format_default_value(), options_get_type_placeholder(), and safe_snprintf().

Referenced by options_config_generate_manpage_merged(), and options_config_generate_manpage_template().