1 /* This merely extracts, doesn't do XML or anything. */
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>
17 static char **grab_doc(const char *fname)
22 bool printing = false;
24 file = grab_file(NULL, fname, NULL);
26 err(1, "Reading file %s", fname);
27 lines = strsplit(file, file, "\n", &num);
28 ret = talloc_array(NULL, char *, num+1);
31 for (i = 0; lines[i]; i++) {
32 if (streq(lines[i], "/**")) {
35 talloc_append_string(ret[num-1], "\n");
36 } else if (streq(lines[i], " */"))
39 if (strstarts(lines[i], " * "))
40 ret[num++] = talloc_strdup(ret, lines[i]+3);
41 else if (strstarts(lines[i], " *"))
42 ret[num++] = talloc_strdup(ret, lines[i]+2);
44 errx(1, "Malformed line %s:%u", fname, i);
52 static bool is_blank(const char *line)
54 return line && line[strspn(line, " \t\n")] == '\0';
57 static bool is_section(const char *line, bool maybe_one_liner)
61 len = strcspn(line, " \t\n:");
68 /* If it can be a one-liner, a space is sufficient.*/
69 if (maybe_one_liner && (line[len+1] == ' ' || line[len+1] == '\t'))
72 return line[len] == ':' && is_blank(line+len+1);
75 /* Summary line is form '<identifier> - ' */
76 static bool is_summary_line(const char *line)
80 id_len = strspn(line, IDENT_CHARS);
83 if (!strstarts(line + id_len, " - "))
89 static bool end_section(const char *line)
91 return !line || is_section(line, true) || is_summary_line(line);
94 static unsigned int find_section(char **lines, const char *name,
99 for (i = 0; lines[i]; i++) {
100 if (!is_section(lines[i], maybe_one_liner))
102 if (strncasecmp(lines[i], name, strlen(name)) != 0)
104 if (lines[i][strlen(name)] == ':')
110 /* function is NULL if we don't care. */
111 static unsigned int find_summary(char **lines, const char *function)
115 for (i = 0; lines[i]; i++) {
116 if (!is_summary_line(lines[i]))
119 if (!strstarts(lines[i], function))
121 if (!strstarts(lines[i] + strlen(function), " - "))
130 int main(int argc, char *argv[])
134 const char *function = NULL;
137 errx(1, "Usage: doc_extract [--function=<funcname>] TYPE <file>...\n"
138 "Where TYPE is functions|author|licence|maintainer|summary|description|example|all");
140 if (strstarts(argv[1], "--function=")) {
141 function = argv[1] + strlen("--function=");
147 for (i = 2; i < argc; i++) {
149 char **lines = grab_doc(argv[i]);
152 errx(1, "No documentation in file %s", argv[i]);
155 /* Allow us to trawl multiple files for a function */
156 line = find_summary(lines, function);
160 /* Trim to just this function then. */
162 lines[find_summary(lines+1, NULL)] = NULL;
164 /* Simple one-line fields. */
165 if (streq(type, "author")
166 || streq(type, "maintainer")
167 || streq(type, "licence")) {
168 line = find_section(lines, type, true);
170 const char *p = strchr(lines[line], ':') + 1;
171 p += strspn(p, " \t\n");
173 /* Must be on next line. */
174 if (end_section(lines[line+1]))
175 errx(1, "Malformed %s", type);
180 } else if (streq(type, "summary")) {
181 /* Summary comes after - on first line. */
184 dash = strchr(lines[0], '-');
186 errx(1, "Malformed first line: no -");
187 dash += strspn(dash, "- ");
189 } else if (streq(type, "description")) {
191 while (is_blank(lines[line]))
194 while (!end_section(lines[line]))
196 } else if (streq(type, "example")) {
197 line = find_section(lines, type, false);
202 while (is_blank(lines[line]))
205 /* Examples can be indented. Take cue
206 * from first non-blank line. */
208 strip = strspn(lines[line], " \t");
210 while (!end_section(lines[line])) {
211 if (strspn(lines[line], " \t") >= strip)
212 puts(lines[line] + strip);
218 } else if (streq(type, "functions")) {
219 while (lines[line = find_summary(lines, NULL)]) {
220 const char *dash = strstr(lines[line], " - ");
222 dash - lines[line], lines[line]);
225 } else if (streq(type, "all")) {
226 for (line = 0; lines[line]; line++)
229 errx(1, "Unknown type '%s'", type);