opt: fix warnings with gcc and -O.
[ccan] / ccan / opt / usage.c
1 #include <ccan/opt/opt.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <stdint.h>
6 #include "private.h"
7
8 /* We only use this for pointer comparisons. */
9 const char opt_hidden[1];
10
11 static unsigned write_short_options(char *str)
12 {
13         unsigned int i, num = 0;
14         const char *p;
15
16         for (p = first_sopt(&i); p; p = next_sopt(p, &i)) {
17                 if (opt_table[i].desc != opt_hidden)
18                         str[num++] = *p;
19         }
20         return num;
21 }
22
23 #define OPT_SPACE_PAD "                    "
24
25 /* FIXME: Get all purdy. */
26 char *opt_usage(const char *argv0, const char *extra)
27 {
28         unsigned int i, num, len;
29         char *ret, *p;
30
31         /* An overestimate of our length. */
32         len = strlen("Usage: %s ") + strlen(argv0)
33                 + strlen("[-%.*s]") + opt_num_short + 1
34                 + strlen(" ") + strlen(extra)
35                 + strlen("\n");
36
37         for (i = 0; i < opt_count; i++) {
38                 if (opt_table[i].type == OPT_SUBTABLE) {
39                         len += strlen("\n") + strlen(opt_table[i].desc)
40                                 + strlen(":\n");
41                 } else if (opt_table[i].desc != opt_hidden) {
42                         len += strlen(opt_table[i].names) + strlen(" <arg>");
43                         len += strlen(OPT_SPACE_PAD)
44                                 + strlen(opt_table[i].desc) + 1;
45                         if (opt_table[i].show) {
46                                 len += strlen("(default: %s)")
47                                         + OPT_SHOW_LEN + sizeof("...");
48                         }
49                         len += strlen("\n");
50                 }
51         }
52
53         p = ret = malloc(len);
54         if (!ret)
55                 return NULL;
56
57         p += sprintf(p, "Usage: %s", argv0);
58         p += sprintf(p, " [-");
59         num = write_short_options(p);
60         if (num) {
61                 p += num;
62                 p += sprintf(p, "]");
63         } else {
64                 /* Remove start of single-entry options */
65                 p -= 3;
66         }
67         if (extra)
68                 p += sprintf(p, " %s", extra);
69         p += sprintf(p, "\n");
70
71         for (i = 0; i < opt_count; i++) {
72                 if (opt_table[i].desc == opt_hidden)
73                         continue;
74                 if (opt_table[i].type == OPT_SUBTABLE) {
75                         p += sprintf(p, "%s:\n", opt_table[i].desc);
76                         continue;
77                 }
78                 len = sprintf(p, "%s", opt_table[i].names);
79                 if (opt_table[i].type == OPT_HASARG
80                     && !strchr(opt_table[i].names, ' ')
81                     && !strchr(opt_table[i].names, '='))
82                         len += sprintf(p + len, " <arg>");
83                 len += sprintf(p + len, "%.*s",
84                                len < strlen(OPT_SPACE_PAD)
85                                ? strlen(OPT_SPACE_PAD) - len : 1,
86                                OPT_SPACE_PAD);
87
88                 len += sprintf(p + len, "%s", opt_table[i].desc);
89                 if (opt_table[i].show) {
90                         char buf[OPT_SHOW_LEN + sizeof("...")];
91                         strcpy(buf + OPT_SHOW_LEN, "...");
92                         opt_table[i].show(buf, opt_table[i].arg);
93                         len += sprintf(p + len, " (default: %s)", buf);
94                 }
95                 p += len;
96                 p += sprintf(p, "\n");
97         }
98         *p = '\0';
99         return ret;
100 }