Simplify -I lines: change includes to ccan/
[ccan] / tools / doc_extract.c
1 /* This merely extracts, doesn't do XML or anything. */
2 #include <err.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <stdbool.h>
11 #include <ccan/talloc/talloc.h>
12 #include <ccan/str/str.h>
13 #include <ccan/str_talloc/str_talloc.h>
14 #include <ccan/grab_file/grab_file.h>
15
16 static char **grab_doc(const char *fname)
17 {
18         char *file;
19         char **lines, **ret;
20         unsigned int i, num;
21         bool printing = false, printed = false;
22
23         file = grab_file(NULL, fname, NULL);
24         if (!file)
25                 err(1, "Reading file %s", fname);
26         lines = strsplit(file, file, "\n", &num);
27         ret = talloc_array(NULL, char *, num+1);
28
29         num = 0;
30         for (i = 0; lines[i]; i++) {
31                 if (streq(lines[i], "/**")) {
32                         printing = true;
33                         if (printed++)
34                                 talloc_append_string(ret[num], "\n");
35                 } else if (streq(lines[i], " */")) 
36                         printing = false;
37                 else if (printing) {
38                         if (strstarts(lines[i], " * "))
39                                 ret[num++] = talloc_strdup(ret, lines[i]+3);
40                         else if (strstarts(lines[i], " *"))
41                                 ret[num++] = talloc_strdup(ret, lines[i]+2);
42                         else
43                                 errx(1, "Malformed line %s:%u", fname, i);
44                 }
45         }
46         ret[num] = NULL;
47         talloc_free(file);
48         return ret;
49 }
50
51 static bool is_blank(const char *line)
52 {
53         return line && line[strspn(line, " \t\n")] == '\0';
54 }
55
56 static bool is_section(const char *line, bool maybe_one_liner)
57 {
58         unsigned int len;
59
60         len = strcspn(line, " \t\n:");
61         if (len == 0)
62                 return false;
63
64         if (line[len] != ':')
65                 return false;
66
67         /* If it can be a one-liner, a space is sufficient.*/
68         if (maybe_one_liner && (line[len+1] == ' ' || line[len+1] == '\t'))
69                 return true;
70
71         return line[len] == ':' && is_blank(line+len+1);
72 }
73
74
75 static bool end_section(const char *line)
76 {
77         return !line || is_section(line, true);
78 }
79
80 static unsigned int find_section(char **lines, const char *name,
81                                  bool maybe_one_liner)
82 {
83         unsigned int i;
84
85         for (i = 0; lines[i]; i++) {
86                 if (!is_section(lines[i], maybe_one_liner))
87                         continue;
88                 if (strncasecmp(lines[i], name, strlen(name)) != 0)
89                         continue;
90                 if (lines[i][strlen(name)] == ':')
91                         break;
92         }
93         return i;
94 }
95
96 int main(int argc, char *argv[])
97 {
98         unsigned int i;
99         const char *type;
100
101         if (argc < 3)
102                 errx(1, "Usage: doc_extract TYPE <file>...\n"
103                      "Where TYPE is author|licence|maintainer|summary|description|example|all");
104
105         type = argv[1];
106         for (i = 2; i < argc; i++) {
107                 unsigned int line;
108                 char **lines = grab_doc(argv[i]);
109
110                 if (!lines[0])
111                         errx(1, "No documentation in file");
112
113                 /* Simple one-line fields. */
114                 if (streq(type, "author")
115                     || streq(type, "maintainer")
116                     || streq(type, "licence")) {
117                         line = find_section(lines, type, true);
118                         if (lines[line]) {
119                                 const char *p = strchr(lines[line], ':') + 1;
120                                 p += strspn(p, " \t\n");
121                                 if (p[0] == '\0') {
122                                         /* Must be on next line. */
123                                         if (end_section(lines[line+1]))
124                                                 errx(1, "Malformed %s", type);
125                                         puts(lines[line+1]);
126                                 } else
127                                         puts(p);
128                         }
129                 } else if (streq(type, "summary")) {
130                         /* Summary comes after - on first line. */
131                         char *dash;
132
133                         dash = strchr(lines[0], '-');
134                         if (!dash)
135                                 errx(1, "Malformed first line: no -");
136                         dash += strspn(dash, "- ");
137                         puts(dash);
138                 } else if (streq(type, "description")) {
139                         line = 1;
140                         while (is_blank(lines[line]))
141                                 line++;
142
143                         while (!end_section(lines[line]))
144                                 puts(lines[line++]);
145                 } else if (streq(type, "example")) {
146                         line = find_section(lines, type, false);
147                         if (lines[line]) {
148                                 unsigned int strip;
149                                 line++;
150
151                                 while (is_blank(lines[line]))
152                                         line++;
153
154                                 /* Examples can be indented.  Take cue
155                                  * from first non-blank line. */
156                                 if (lines[line])
157                                         strip = strspn(lines[line], " \t");
158
159                                 while (!end_section(lines[line])) {
160                                         if (strspn(lines[line], " \t") >= strip)
161                                                 puts(lines[line] + strip);
162                                         else
163                                                 puts(lines[line]);
164                                         line++;
165                                 }
166                         }
167                 } else if (streq(type, "all")) {
168                         for (line = 0; lines[line]; line++)
169                                 puts(lines[line]);
170                 } else
171                         errx(1, "Unknown type '%s'", type);
172                         
173                 talloc_free(lines);
174         }
175         return 0;
176 }
177
178                 
179