1 /* This merely extracts, doesn't do XML or anything. */
2 #include <ccan/talloc/talloc.h>
3 #include <ccan/str/str.h>
4 #include <ccan/str_talloc/str_talloc.h>
10 #include <sys/types.h>
15 #include "doc_extract.h"
18 static char **grab_doc(char **lines, unsigned int **linemap,
23 bool printing = false;
25 ret = talloc_array(NULL, char *, talloc_array_length(lines));
26 *linemap = talloc_array(ret, unsigned int, talloc_array_length(lines));
29 for (i = 0; lines[i]; i++) {
30 if (streq(lines[i], "/**")) {
33 ret[num-1] = talloc_append_string(ret[num-1],
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 /* Weird, malformed? */
48 " Expected ' *' in comment.",
52 ret[num++] = talloc_strdup(ret, lines[i]);
53 if (strstr(lines[i], "*/"))
56 (*linemap)[num-1] = i;
63 static bool is_blank(const char *line)
65 return line && line[strspn(line, " \t\n")] == '\0';
68 static char *is_section(const void *ctx, const char *line, char **value)
72 /* Any number of upper case words separated by spaces, ending in : */
73 if (!strreg(ctx, line,
74 "^([A-Z][a-zA-Z0-9_]*( [A-Z][a-zA-Z0-9_]*)*):[ \t\n]*(.*)",
75 &secname, NULL, value))
81 /* Summary line is form '<identifier> - ' (spaces for 'struct foo -') */
82 static unsigned int is_summary_line(const char *line)
86 /* We allow /, because it can be in (nested) module names. */
87 id_len = strspn(line, IDENT_CHARS" /");
90 if (strspn(line, " ") == id_len)
92 if (!strstarts(line + id_len-1, " - "))
97 static bool empty_section(struct doc_section *d)
101 for (i = 0; i < d->num_lines; i++)
102 if (!is_blank(d->lines[i]))
107 static struct doc_section *new_section(struct list_head *list,
108 const char *function,
110 unsigned int srcline)
112 struct doc_section *d;
116 /* If previous section was empty, delete it. */
117 d = list_tail(list, struct doc_section, list);
118 if (d && empty_section(d)) {
123 d = talloc(list, struct doc_section);
124 d->function = function;
125 lowertype = talloc_size(d, strlen(type) + 1);
126 /* Canonicalize type to lower case. */
127 for (i = 0; i < strlen(type)+1; i++)
128 lowertype[i] = tolower(type[i]);
132 d->srcline = srcline;
134 list_add_tail(list, &d->list);
138 static void add_line(struct doc_section *curr, const char *line)
140 curr->lines = talloc_realloc(curr, curr->lines, char *,
142 curr->lines[curr->num_lines++] = talloc_strdup(curr->lines, line);
145 /* We convert tabs to spaces here. */
146 static void add_detabbed_line(struct doc_section *curr, const char *rawline)
148 unsigned int i, eff_i, len, off = 0;
151 /* Worst-case alloc: 8 spaces per tab. */
152 line = talloc_array(curr, char, strlen(rawline) +
153 strcount(rawline, "\t") * 7 + 1);
156 /* We keep track of the *effective* offset of i. */
157 for (i = eff_i = 0; i < strlen(rawline); i++) {
158 if (rawline[i] == '\t') {
162 } while (eff_i % 8 != 0);
164 line[len++] = rawline[i];
165 if (off == 0 && rawline[i] == '*')
172 add_line(curr, line + off);
176 /* Not very efficient: we could track prefix length while doing
177 * add_detabbed_line */
178 static void trim_lines(struct doc_section *curr)
180 unsigned int i, trim = -1;
181 int last_non_empty = -1;
183 /* Get minimum whitespace prefix. */
184 for (i = 0; i < curr->num_lines; i++) {
185 unsigned int prefix = strspn(curr->lines[i], " ");
186 /* Ignore blank lines */
187 if (curr->lines[i][prefix] == '\0')
194 for (i = 0; i < curr->num_lines; i++) {
195 unsigned int prefix = strspn(curr->lines[i], " ");
197 curr->lines[i] += prefix;
199 curr->lines[i] += trim;
201 /* All blank? Potential to trim. */
202 if (curr->lines[i][strspn(curr->lines[i], " \t")] != '\0')
206 /* Remove trailing blank lines. */
207 curr->num_lines = last_non_empty + 1;
210 struct list_head *extract_doc_sections(char **rawlines, const char *file)
212 unsigned int *linemap;
213 char **lines = grab_doc(rawlines, &linemap, file);
214 const char *function = NULL;
215 struct doc_section *curr = NULL;
217 struct list_head *list;
219 list = talloc(NULL, struct list_head);
220 list_head_init(list);
222 for (i = 0; lines[i]; i++) {
226 funclen = is_summary_line(lines[i]);
228 function = talloc_strndup(list, lines[i], funclen);
229 curr = new_section(list, function, "summary",
231 add_line(curr, lines[i] + funclen + 3);
232 curr = new_section(list, function, "description",
234 } else if ((type = is_section(list, lines[i], &extra)) != NULL){
235 curr = new_section(list, function, type, linemap[i]);
236 if (!streq(extra, "")) {
237 add_line(curr, extra);
242 add_detabbed_line(curr, rawlines[linemap[i]]);
246 list_for_each(list, curr, list)