X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=tools%2Fdoc_extract.c;h=fb7024a75daccb6baff61b0947ef8876ec24c19b;hb=9965fc25fcc92dc76d1cd4cf9595dc3dc9ebc586;hp=b4ac0d3e6e144e6daa33d188d895baf12b874063;hpb=650c775ff00cccd03fc84e7789a03c51d9839004;p=ccan diff --git a/tools/doc_extract.c b/tools/doc_extract.c index b4ac0d3e..fb7024a7 100644 --- a/tools/doc_extract.c +++ b/tools/doc_extract.c @@ -9,96 +9,168 @@ #include #include #include "talloc/talloc.h" +#include "str/str.h" +#include "str_talloc/str_talloc.h" +#include "grab_file/grab_file.h" -/* Is A == B ? */ -#define streq(a,b) (strcmp((a),(b)) == 0) +static char **grab_doc(const char *fname) +{ + char *file; + char **lines, **ret; + unsigned int i, num; + bool printing = false, printed = false; -/* Does A start with B ? */ -#define strstarts(a,b) (strncmp((a),(b),strlen(b)) == 0) + file = grab_file(NULL, fname, NULL); + if (!file) + err(1, "Reading file %s", fname); + lines = strsplit(file, file, "\n", &num); + ret = talloc_array(NULL, char *, num+1); -/* This version adds one byte (for nul term) */ -static void *grab_file(void *ctx, const char *filename) -{ - unsigned int max = 16384, size = 0; - int ret, fd; - char *buffer; - - if (streq(filename, "-")) - fd = dup(STDIN_FILENO); - else - fd = open(filename, O_RDONLY, 0); - - if (fd < 0) - return NULL; - - buffer = talloc_array(ctx, char, max+1); - while ((ret = read(fd, buffer + size, max - size)) > 0) { - size += ret; - if (size == max) - buffer = talloc_realloc(ctx, buffer, char, max*=2 + 1); + num = 0; + for (i = 0; lines[i]; i++) { + if (streq(lines[i], "/**")) { + printing = true; + if (printed++) + talloc_append_string(ret[num], "\n"); + } else if (streq(lines[i], " */")) + printing = false; + else if (printing) { + if (strstarts(lines[i], " * ")) + ret[num++] = talloc_strdup(ret, lines[i]+3); + else if (strstarts(lines[i], " *")) + ret[num++] = talloc_strdup(ret, lines[i]+2); + else + errx(1, "Malformed line %s:%u", fname, i); + } } - if (ret < 0) { - talloc_free(buffer); - buffer = NULL; - } else - buffer[size] = '\0'; - close(fd); - return buffer; + ret[num] = NULL; + talloc_free(file); + return ret; +} + +static bool is_blank(const char *line) +{ + return line && line[strspn(line, " \t\n")] == '\0'; } -/* This is a dumb one which copies. We could mangle instead. */ -static char **split(const char *text) +static bool is_section(const char *line, bool maybe_one_liner) { - char **lines = NULL; - unsigned int max = 64, num = 0; - - lines = talloc_array(text, char *, max+1); - - while (*text != '\0') { - unsigned int len = strcspn(text, "\n"); - lines[num] = talloc_array(lines, char, len + 1); - memcpy(lines[num], text, len); - lines[num][len] = '\0'; - text += len + 1; - if (++num == max) - lines = talloc_realloc(text, lines, char *, max*=2 + 1); + unsigned int len; + + len = strcspn(line, " \t\n:"); + if (len == 0) + return false; + + if (line[len] != ':') + return false; + + /* If it can be a one-liner, a space is sufficient.*/ + if (maybe_one_liner && (line[len+1] == ' ' || line[len+1] == '\t')) + return true; + + return line[len] == ':' && is_blank(line+len+1); +} + + +static bool end_section(const char *line) +{ + return !line || is_section(line, true); +} + +static unsigned int find_section(char **lines, const char *name, + bool maybe_one_liner) +{ + unsigned int i; + + for (i = 0; lines[i]; i++) { + if (!is_section(lines[i], maybe_one_liner)) + continue; + if (strncasecmp(lines[i], name, strlen(name)) != 0) + continue; + if (lines[i][strlen(name)] == ':') + break; } - lines[num] = NULL; - return lines; + return i; } int main(int argc, char *argv[]) { - unsigned int i, j; - - for (i = 1; i < argc; i++) { - char *file; - char **lines; - bool printing = false, printed = false; - - file = grab_file(NULL, argv[i]); - if (!file) - err(1, "Reading file %s", argv[i]); - lines = split(file); - - for (j = 0; lines[j]; j++) { - if (streq(lines[j], "/**")) { - printing = true; - if (printed++) - puts("\n"); - } else if (streq(lines[j], " */")) - printing = false; - else if (printing) { - if (strstarts(lines[j], " * ")) - puts(lines[j] + 3); - else if (strstarts(lines[j], " *")) - puts(lines[j] + 2); - else - errx(1, "Malformed line %s:%u", - argv[i], j); + unsigned int i; + const char *type; + + if (argc < 3) + errx(1, "Usage: doc_extract TYPE ...\n" + "Where TYPE is author|licence|maintainer|summary|description|example|all"); + + type = argv[1]; + for (i = 2; i < argc; i++) { + unsigned int line; + char **lines = grab_doc(argv[i]); + + if (!lines[0]) + errx(1, "No documentation in file"); + + /* Simple one-line fields. */ + if (streq(type, "author") + || streq(type, "maintainer") + || streq(type, "licence")) { + line = find_section(lines, type, true); + if (lines[line]) { + const char *p = strchr(lines[line], ':') + 1; + p += strspn(p, " \t\n"); + if (p[0] == '\0') { + /* Must be on next line. */ + if (end_section(lines[line+1])) + errx(1, "Malformed %s", type); + puts(lines[line+1]); + } else + puts(p); } - } - talloc_free(file); + } else if (streq(type, "summary")) { + /* Summary comes after - on first line. */ + char *dash; + + dash = strchr(lines[0], '-'); + if (!dash) + errx(1, "Malformed first line: no -"); + dash += strspn(dash, "- "); + puts(dash); + } else if (streq(type, "description")) { + line = 1; + while (is_blank(lines[line])) + line++; + + while (!end_section(lines[line])) + puts(lines[line++]); + } else if (streq(type, "example")) { + line = find_section(lines, type, false); + if (lines[line]) { + unsigned int strip; + line++; + + while (is_blank(lines[line])) + line++; + + /* Examples can be indented. Take cue + * from first non-blank line. */ + if (lines[line]) + strip = strspn(lines[line], " \t"); + + while (!end_section(lines[line])) { + if (strspn(lines[line], " \t") >= strip) + puts(lines[line] + strip); + else + puts(lines[line]); + line++; + } + } + } else if (streq(type, "all")) { + for (line = 0; lines[line]; line++) + puts(lines[line]); + } else + errx(1, "Unknown type '%s'", type); + + talloc_free(lines); } return 0; }