GCC Code Coverage Report


Directory: lib/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 96.6% 201 / 0 / 208
Functions: 100.0% 10 / 0 / 10
Branches: 91.6% 218 / 0 / 238

format_manpage.c
Line Branch Exec Source
1 #include <stdlib.h>
2
3 #include "ap_internal.h"
4
5 5122 static const char *metavar_for(const ap_arg_def *def) {
6 static char fallback[64];
7 size_t i;
8
9
3/4
✓ Branch 0 taken 2070 times.
✓ Branch 1 taken 3052 times.
✓ Branch 2 taken 2070 times.
✗ Branch 3 not taken.
5122 if (def->opts.metavar && def->opts.metavar[0] != '\0') {
10 2070 return def->opts.metavar;
11 }
12
13
3/4
✓ Branch 0 taken 22950 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19898 times.
✓ Branch 3 taken 3052 times.
22950 for (i = 0; i < sizeof(fallback) - 1 && def->dest[i] != '\0'; i++) {
14 19898 char c = def->dest[i];
15
3/4
✓ Branch 0 taken 18630 times.
✓ Branch 1 taken 1268 times.
✓ Branch 2 taken 18630 times.
✗ Branch 3 not taken.
19898 if (c >= 'a' && c <= 'z') {
16 18630 fallback[i] = (char)(c - 'a' + 'A');
17
2/2
✓ Branch 0 taken 1264 times.
✓ Branch 1 taken 4 times.
1268 } else if (c == '_') {
18 1264 fallback[i] = '-';
19 } else {
20 4 fallback[i] = c;
21 }
22 }
23 3052 fallback[i] = '\0';
24 3052 return fallback;
25 }
26
27 15008 static int ap_sb_append_roff_text(ap_string_builder *sb, const char *text) {
28 size_t i;
29
30
3/4
✓ Branch 0 taken 15008 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 15002 times.
15008 if (!text || text[0] == '\0') {
31 6 return 0;
32 }
33
34
2/2
✓ Branch 0 taken 117420 times.
✓ Branch 1 taken 14310 times.
131730 for (i = 0; text[i] != '\0'; i++) {
35 117420 char c = text[i];
36
37
8/8
✓ Branch 0 taken 102418 times.
✓ Branch 1 taken 15002 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 102386 times.
✓ Branch 4 taken 15012 times.
✓ Branch 5 taken 22 times.
✓ Branch 6 taken 18 times.
✓ Branch 7 taken 14994 times.
117420 if ((i == 0 || text[i - 1] == '\n') && (c == '.' || c == '\'')) {
38
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 if (ap_sb_appendf(sb, "\\&") != 0) {
39 return -1;
40 }
41 }
42
43
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 117402 times.
117420 if (c == '\\') {
44
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
18 if (ap_sb_appendf(sb, "\\\\") != 0) {
45 return -1;
46 }
47
2/2
✓ Branch 0 taken 8034 times.
✓ Branch 1 taken 109368 times.
117402 } else if (c == '-') {
48
2/2
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 7994 times.
8034 if (ap_sb_appendf(sb, "\\-") != 0) {
49 40 return -1;
50 }
51
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 109336 times.
109368 } else if (c == '\n') {
52
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
32 if (ap_sb_appendf(sb, "\n") != 0) {
53 return -1;
54 }
55
2/2
✓ Branch 1 taken 652 times.
✓ Branch 2 taken 108684 times.
109336 } else if (ap_sb_appendf(sb, "%c", c) != 0) {
56 652 return -1;
57 }
58 }
59
60 14310 return 0;
61 }
62
63 4496 static int append_nargs_suffix(ap_string_builder *sb, const ap_arg_def *def) {
64 4496 const char *mv = metavar_for(def);
65 int i;
66
67
2/2
✓ Branch 0 taken 1790 times.
✓ Branch 1 taken 2706 times.
4496 if (def->opts.action != AP_ACTION_STORE &&
68
1/2
✓ Branch 0 taken 1790 times.
✗ Branch 1 not taken.
1790 def->opts.action != AP_ACTION_APPEND) {
69 1790 return 0;
70 }
71
72
5/6
✓ Branch 0 taken 2660 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
2706 switch (def->opts.nargs) {
73 2660 case AP_NARGS_ONE:
74 2660 return ap_sb_appendf(sb, " %s", mv);
75 12 case AP_NARGS_OPTIONAL:
76 12 return ap_sb_appendf(sb, " [%s]", mv);
77 12 case AP_NARGS_ZERO_OR_MORE:
78 12 return ap_sb_appendf(sb, " [%s ...]", mv);
79 8 case AP_NARGS_ONE_OR_MORE:
80 8 return ap_sb_appendf(sb, " %s [%s ...]", mv, mv);
81 14 case AP_NARGS_FIXED:
82
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 14 times.
46 for (i = 0; i < def->opts.nargs_count; i++) {
83
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
32 if (ap_sb_appendf(sb, " %s", mv) != 0) {
84 return -1;
85 }
86 }
87 14 return 0;
88 }
89
90 return 0;
91 }
92
93 1284 static int append_usage_synopsis(ap_string_builder *sb,
94 const ap_parser *parser) {
95 int i;
96
97
4/4
✓ Branch 1 taken 1274 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 108 times.
✓ Branch 4 taken 1166 times.
2558 if (ap_sb_appendf(sb, ".B ") != 0 ||
98 1274 ap_sb_append_roff_text(sb, parser->prog) != 0) {
99 118 return -1;
100 }
101
102
2/2
✓ Branch 0 taken 3134 times.
✓ Branch 1 taken 1072 times.
4206 for (i = 0; i < parser->defs_count; i++) {
103 3134 const ap_arg_def *def = &parser->defs[i];
104
105
2/2
✓ Branch 0 taken 2506 times.
✓ Branch 1 taken 628 times.
3134 if (def->is_optional) {
106
2/2
✓ Branch 0 taken 662 times.
✓ Branch 1 taken 1844 times.
2506 if (def->opts.required) {
107
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 660 times.
662 if (ap_sb_appendf(sb, " ") != 0) {
108 2 return -1;
109 }
110
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 1832 times.
1844 } else if (ap_sb_appendf(sb, " [") != 0) {
111 12 return -1;
112 }
113
114
4/4
✓ Branch 1 taken 2452 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 2448 times.
4944 if (ap_sb_append_roff_text(sb, def->flags[0]) != 0 ||
115 2452 append_nargs_suffix(sb, def) != 0) {
116 44 return -1;
117 }
118
119
4/4
✓ Branch 0 taken 1794 times.
✓ Branch 1 taken 654 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 1782 times.
2448 if (!def->opts.required && ap_sb_appendf(sb, "]") != 0) {
120 12 return -1;
121 }
122 } else {
123
4/4
✓ Branch 1 taken 626 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 606 times.
✓ Branch 4 taken 20 times.
1254 if (ap_sb_appendf(sb, " ") != 0 ||
124
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 604 times.
1232 ap_sb_append_roff_text(sb, metavar_for(def)) != 0 ||
125 606 append_nargs_suffix(sb, def) != 0) {
126 24 return -1;
127 }
128 }
129 }
130
131
4/4
✓ Branch 0 taken 926 times.
✓ Branch 1 taken 146 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 920 times.
1998 if (parser->subcommands_count > 0 &&
132 926 ap_sb_appendf(sb, " [SUBCOMMAND]") != 0) {
133 6 return -1;
134 }
135
136 1066 return ap_sb_appendf(sb, "\n");
137 }
138
139 1508 static int append_option_signature(ap_string_builder *sb,
140 const ap_arg_def *def) {
141 int i;
142
143
2/2
✓ Branch 0 taken 2638 times.
✓ Branch 1 taken 1438 times.
4076 for (i = 0; i < def->flags_count; i++) {
144
4/4
✓ Branch 0 taken 1130 times.
✓ Branch 1 taken 1508 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 1124 times.
2638 if (i > 0 && ap_sb_appendf(sb, ", ") != 0) {
145 6 return -1;
146 }
147
2/2
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 2568 times.
2632 if (ap_sb_append_roff_text(sb, def->flags[i]) != 0) {
148 64 return -1;
149 }
150 }
151
152 1438 return append_nargs_suffix(sb, def);
153 }
154
155 1584 static int append_field_line(ap_string_builder *sb, const char *label,
156 const char *value) {
157
3/4
✓ Branch 0 taken 758 times.
✓ Branch 1 taken 826 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 758 times.
1584 if (!value || value[0] == '\0') {
158 826 return 0;
159 }
160
161
6/6
✓ Branch 1 taken 754 times.
✓ Branch 2 taken 4 times.
✓ Branch 4 taken 724 times.
✓ Branch 5 taken 30 times.
✓ Branch 6 taken 720 times.
✓ Branch 7 taken 4 times.
1482 if (ap_sb_appendf(sb, "\n") != 0 || ap_sb_append_roff_text(sb, label) != 0 ||
162
2/2
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 706 times.
1444 ap_sb_appendf(sb, ": ") != 0 || ap_sb_append_roff_text(sb, value) != 0) {
163 52 return -1;
164 }
165
166 706 return 0;
167 }
168
169 1236 static int append_choices_line(ap_string_builder *sb,
170 const ap_choices *choices) {
171 int i;
172
173
4/6
✓ Branch 0 taken 1236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 410 times.
✓ Branch 3 taken 826 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 410 times.
1236 if (!choices || !choices->items || choices->count <= 0) {
174 826 return 0;
175 }
176
177
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 408 times.
410 if (ap_sb_appendf(sb, "\nchoices: ") != 0) {
178 2 return -1;
179 }
180
181
2/2
✓ Branch 0 taken 820 times.
✓ Branch 1 taken 390 times.
1210 for (i = 0; i < choices->count; i++) {
182
4/4
✓ Branch 0 taken 412 times.
✓ Branch 1 taken 408 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 410 times.
820 if (i > 0 && ap_sb_appendf(sb, ", ") != 0) {
183 2 return -1;
184 }
185
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 802 times.
818 if (ap_sb_append_roff_text(sb, choices->items[i]) != 0) {
186 16 return -1;
187 }
188 }
189
190 390 return 0;
191 }
192
193 682 static int append_options_section(ap_string_builder *sb,
194 const ap_parser *parser, bool *has_options) {
195 int i;
196 682 bool emitted = false;
197
198
2/2
✓ Branch 0 taken 1804 times.
✓ Branch 1 taken 318 times.
2122 for (i = 0; i < parser->defs_count; i++) {
199 1804 const ap_arg_def *def = &parser->defs[i];
200
201
2/2
✓ Branch 0 taken 284 times.
✓ Branch 1 taken 1520 times.
1804 if (!def->is_optional) {
202 284 continue;
203 }
204
205
2/2
✓ Branch 0 taken 682 times.
✓ Branch 1 taken 838 times.
1520 if (!emitted) {
206
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 678 times.
682 if (ap_sb_appendf(sb, ".SH OPTIONS\n") != 0) {
207 4 return -1;
208 }
209 678 emitted = true;
210 }
211
212
4/4
✓ Branch 1 taken 1508 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 1434 times.
✓ Branch 4 taken 74 times.
3024 if (ap_sb_appendf(sb, ".TP\n.B ") != 0 ||
213
2/2
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 1426 times.
2942 append_option_signature(sb, def) != 0 || ap_sb_appendf(sb, "\n") != 0) {
214 90 return -1;
215 }
216
217
5/6
✓ Branch 0 taken 1416 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 1416 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 190 times.
✓ Branch 5 taken 1226 times.
2842 if (def->opts.help && def->opts.help[0] != '\0' &&
218 1416 ap_sb_append_roff_text(sb, def->opts.help) != 0) {
219 190 return -1;
220 }
221
4/4
✓ Branch 1 taken 1216 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 1190 times.
✓ Branch 4 taken 26 times.
2452 if (append_choices_line(sb, &def->opts.choices) != 0 ||
222 1216 append_field_line(sb, "default", def->opts.default_value) != 0 ||
223
4/4
✓ Branch 0 taken 368 times.
✓ Branch 1 taken 822 times.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 342 times.
1190 (def->opts.required && append_field_line(sb, "required", "yes") != 0)) {
224 72 return -1;
225 }
226
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1156 times.
1164 if (ap_sb_appendf(sb, "\n") != 0) {
227 8 return -1;
228 }
229 }
230
231 318 *has_options = emitted;
232 318 return 0;
233 }
234
235 600 static int append_subcommand_entry(ap_string_builder *sb,
236 const ap_subcommand_def *subcommand,
237 int depth) {
238 int i;
239
240
2/2
✓ Branch 0 taken 424 times.
✓ Branch 1 taken 594 times.
1018 for (i = 0; i < depth; i++) {
241
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 418 times.
424 if (ap_sb_appendf(sb, ".RS\n") != 0) {
242 6 return -1;
243 }
244 }
245
246
4/4
✓ Branch 1 taken 588 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 562 times.
✓ Branch 4 taken 26 times.
1182 if (ap_sb_appendf(sb, ".TP\n.B ") != 0 ||
247
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 556 times.
1150 ap_sb_append_roff_text(sb, subcommand->name) != 0 ||
248 562 ap_sb_appendf(sb, "\n") != 0) {
249 38 return -1;
250 }
251
252
4/6
✓ Branch 0 taken 556 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 556 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 86 times.
✓ Branch 5 taken 470 times.
1112 if (subcommand->help && subcommand->help[0] != '\0' &&
253 556 ap_sb_append_roff_text(sb, subcommand->help) != 0) {
254 86 return -1;
255 }
256
257
1/2
✓ Branch 0 taken 470 times.
✗ Branch 1 not taken.
470 if (subcommand->parser) {
258
4/4
✓ Branch 1 taken 464 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 132 times.
✓ Branch 4 taken 332 times.
934 if (ap_sb_appendf(sb, "\n") != 0 ||
259 464 append_usage_synopsis(sb, subcommand->parser) != 0) {
260 138 return -1;
261 }
262
263
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 54 times.
362 for (i = 0; i < subcommand->parser->subcommands_count; i++) {
264
2/2
✓ Branch 1 taken 278 times.
✓ Branch 2 taken 30 times.
308 if (append_subcommand_entry(sb, &subcommand->parser->subcommands[i],
265 depth + 1) != 0) {
266 278 return -1;
267 }
268 }
269 }
270
271
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 48 times.
106 for (i = 0; i < depth; i++) {
272
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 52 times.
58 if (ap_sb_appendf(sb, ".RE\n") != 0) {
273 6 return -1;
274 }
275 }
276
277 48 return 0;
278 }
279
280 910 char *ap_manpage_build(const ap_parser *parser) {
281 ap_string_builder sb;
282 910 bool has_options = false;
283 int i;
284
285
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 908 times.
910 if (!parser) {
286 2 return NULL;
287 }
288
289 908 ap_sb_init(&sb);
290
291
4/4
✓ Branch 1 taken 904 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 886 times.
✓ Branch 4 taken 18 times.
1812 if (ap_sb_appendf(&sb, ".TH ") != 0 ||
292
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 882 times.
1790 ap_sb_append_roff_text(&sb, parser->prog) != 0 ||
293 886 ap_sb_appendf(&sb, " 1\n") != 0) {
294 26 ap_sb_free(&sb);
295 26 return NULL;
296 }
297
298
4/4
✓ Branch 1 taken 878 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 862 times.
1760 if (ap_sb_appendf(&sb, ".SH NAME\n") != 0 ||
299 878 ap_sb_append_roff_text(&sb, parser->prog) != 0) {
300 20 ap_sb_free(&sb);
301 20 return NULL;
302 }
303
2/2
✓ Branch 0 taken 734 times.
✓ Branch 1 taken 128 times.
862 if (parser->description[0] != '\0') {
304
4/4
✓ Branch 1 taken 732 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 32 times.
✓ Branch 4 taken 700 times.
1466 if (ap_sb_appendf(&sb, " \\- ") != 0 ||
305 732 ap_sb_append_roff_text(&sb, parser->description) != 0) {
306 34 ap_sb_free(&sb);
307 34 return NULL;
308 }
309 }
310
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 824 times.
828 if (ap_sb_appendf(&sb, "\n") != 0) {
311 4 ap_sb_free(&sb);
312 4 return NULL;
313 }
314
315
4/4
✓ Branch 1 taken 820 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 96 times.
✓ Branch 4 taken 724 times.
1644 if (ap_sb_appendf(&sb, ".SH SYNOPSIS\n") != 0 ||
316 820 append_usage_synopsis(&sb, parser) != 0) {
317 100 ap_sb_free(&sb);
318 100 return NULL;
319 }
320
321
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 720 times.
724 if (ap_sb_appendf(&sb, ".SH DESCRIPTION\n") != 0) {
322 4 ap_sb_free(&sb);
323 4 return NULL;
324 }
325
2/2
✓ Branch 0 taken 618 times.
✓ Branch 1 taken 102 times.
720 if (parser->description[0] != '\0') {
326
2/2
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 586 times.
618 if (ap_sb_append_roff_text(&sb, parser->description) != 0) {
327 32 ap_sb_free(&sb);
328 32 return NULL;
329 }
330
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 100 times.
102 } else if (ap_sb_appendf(
331 &sb, "Command line interface generated by argparse\\-c.") !=
332 0) {
333 2 ap_sb_free(&sb);
334 2 return NULL;
335 }
336
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 682 times.
686 if (ap_sb_appendf(&sb, "\n") != 0) {
337 4 ap_sb_free(&sb);
338 4 return NULL;
339 }
340
341
2/2
✓ Branch 1 taken 364 times.
✓ Branch 2 taken 318 times.
682 if (append_options_section(&sb, parser, &has_options) != 0) {
342 364 ap_sb_free(&sb);
343 364 return NULL;
344 }
345
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 318 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
318 if (!has_options && ap_sb_appendf(&sb, ".SH OPTIONS\nNone.\n") != 0) {
346 ap_sb_free(&sb);
347 return NULL;
348 }
349
350
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 314 times.
318 if (ap_sb_appendf(&sb, ".SH SUBCOMMANDS\n") != 0) {
351 4 ap_sb_free(&sb);
352 4 return NULL;
353 }
354
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 292 times.
314 if (parser->subcommands_count == 0) {
355
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 20 times.
22 if (ap_sb_appendf(&sb, "This command does not define subcommands.\n") !=
356 0) {
357 2 ap_sb_free(&sb);
358 2 return NULL;
359 }
360 } else {
361
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 18 times.
310 for (i = 0; i < parser->subcommands_count; i++) {
362
2/2
✓ Branch 1 taken 274 times.
✓ Branch 2 taken 18 times.
292 if (append_subcommand_entry(&sb, &parser->subcommands[i], 0) != 0) {
363 274 ap_sb_free(&sb);
364 274 return NULL;
365 }
366 }
367 }
368
369
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 34 times.
38 if (ap_sb_appendf(
370 &sb, ".SH EXIT STATUS\n"
371 ".TP\n.B 0\n"
372 "The command completed successfully.\n"
373 ".TP\n.B non\\-zero\n"
374 "Argument parsing, validation, or command dispatch failed.\n"
375 ".SH ERRORS\n"
376 "Typical failures include unknown options, missing values, "
377 "invalid choices, required argument violations, and unexpected "
378 "positional arguments.\n") != 0) {
379 4 ap_sb_free(&sb);
380 4 return NULL;
381 }
382
383 34 return sb.data;
384 }
385