aboutsummaryrefslogtreecommitdiff
path: root/winsup/doc/doctool.c
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/doc/doctool.c')
-rw-r--r--winsup/doc/doctool.c622
1 files changed, 622 insertions, 0 deletions
diff --git a/winsup/doc/doctool.c b/winsup/doc/doctool.c
new file mode 100644
index 0000000..26e7666
--- /dev/null
+++ b/winsup/doc/doctool.c
@@ -0,0 +1,622 @@
+/* doctool.c
+
+ Copyright 1998 Cygnus Solutions.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <utime.h>
+
+/* Building native in a cross-built directory is tricky. Be careful,
+and beware that you don't have the full portability stuff available to
+you (like libiberty) */
+
+/*****************************************************************************/
+
+/* The list of extensions that may contain SGML snippets. We check
+ both cases in case the file system isn't case sensitive enough. */
+
+struct {
+ char *upper;
+ char *lower;
+ int is_sgml;
+} extensions[] = {
+ { ".C", ".c", 0 },
+ { ".CC", ".cc", 0 },
+ { ".H", ".h", 0 },
+ { ".SGML", ".sgml", 1 },
+ { 0, 0, 0 }
+};
+
+/*****************************************************************************/
+
+void
+show_help()
+{
+ printf("Usage: doctool [-m] [-i] [-d dir] [-o outfile] [-s prefix] \\\n");
+ printf(" [-b book_id] infile\n");
+ printf(" -m means to adjust Makefile to include new dependencies\n");
+ printf(" -i means to include internal snippets\n");
+ printf(" -d means to recursively scan directory for snippets\n");
+ printf(" -o means to output to file (else stdout)\n");
+ printf(" -s means to suppress source dir prefix\n");
+ printf(" -b means to change the <book id=\"book_id\">\n");
+ printf("\n");
+ printf("doctool looks for DOCTOOL-START and DOCTOOL-END lines in source,\n");
+ printf("saves <foo id=\"bar\"> blocks, and looks for DOCTOOL-INSERT-bar\n");
+ printf("commands to insert selected sections. IDs starting with int-\n");
+ printf("are internal only, add- are added at the end of relevant sections\n");
+ printf("or add-int- for both. Inserted sections are chosen by prefix,\n");
+ printf("and sorted when inserted.\n");
+ exit(1);
+}
+
+/*****************************************************************************/
+
+typedef struct Section {
+ struct Section *next;
+ struct OneFile *file;
+ char *name;
+ char internal;
+ char addend;
+ char used;
+ char **lines;
+ int num_lines;
+ int max_lines;
+} Section;
+
+typedef struct OneFile {
+ struct OneFile *next;
+ char *filename;
+ int enable_scan;
+ int used;
+ Section *sections;
+} OneFile;
+
+OneFile *file_list = 0;
+
+char *output_name = 0;
+FILE *output_file = 0;
+
+char *source_dir_prefix = "";
+char *book_id = 0;
+
+int internal_flag = 0;
+
+/*****************************************************************************/
+
+char *
+has_string(char *line, char *string)
+{
+ int i;
+ while (*line)
+ {
+ for (i=0; line[i]; i++)
+ {
+ if (!string[i])
+ return line;
+ if (line[i] != string[i])
+ break;
+ }
+ line++;
+ }
+ return 0;
+}
+
+int
+starts_with(char *line, char *string)
+{
+ int i=0;
+ while (1)
+ {
+ if (!string[i])
+ return 1;
+ if (!line[i] || line[i] != string[i])
+ return 0;
+ i++;
+ }
+}
+
+/*****************************************************************************/
+
+#ifdef S_ISLNK
+#define STAT lstat
+#else
+#define STAT stat
+#endif
+
+void
+scan_directory(dirname)
+ char *dirname;
+{
+ struct stat st;
+ char *name;
+ struct dirent *de;
+ DIR *dir = opendir(dirname);
+ if (!dir)
+ return;
+ while (de = readdir(dir))
+ {
+ if (strcmp(de->d_name, ".") == 0
+ || strcmp(de->d_name, "..") == 0)
+ continue;
+
+ name = (char *)malloc(strlen(dirname)+strlen(de->d_name)+3);
+ strcpy(name, dirname);
+ strcat(name, "/");
+ strcat(name, de->d_name);
+
+ STAT(name, &st);
+
+ if (S_ISDIR(st.st_mode))
+ {
+ scan_directory(name);
+ }
+
+ else if (S_ISREG(st.st_mode))
+ {
+ char *dot = strrchr(de->d_name, '.');
+ int i;
+
+ if (dot)
+ {
+ for (i=0; extensions[i].upper; i++)
+ if (strcmp(dot, extensions[i].upper) == 0
+ || strcmp(dot, extensions[i].lower) == 0)
+ {
+ OneFile *one = (OneFile *)malloc(sizeof(OneFile));
+ one->next = file_list;
+ file_list = one;
+ one->filename = name;
+ one->enable_scan = ! extensions[i].is_sgml;
+ one->used = 0;
+ one->sections = 0;
+ }
+ }
+ }
+ }
+ closedir (dir);
+}
+
+/*****************************************************************************/
+
+void
+scan_file(OneFile *one)
+{
+ FILE *f = fopen(one->filename, "r");
+ int enabled = ! one->enable_scan;
+ char line[1000], *tag=0, *id=0, *tmp;
+ int taglen = 0;
+ Section *section = 0;
+ Section **prev_section_ptr = &(one->sections);
+
+ if (!f)
+ {
+ perror(one->filename);
+ return;
+ }
+
+ while (fgets(line, 1000, f))
+ {
+ if (one->enable_scan)
+ {
+ /* source files have comment-embedded docs, check for them */
+ if (has_string(line, "DOCTOOL-START"))
+ enabled = 1;
+ if (has_string(line, "DOCTOOL-END"))
+ enabled = 0;
+ }
+ if (!enabled)
+ continue;
+
+ /* DOCTOOL-START
+
+<sect1 id="dt-tags">
+this is the doctool tags section.
+</sect1>
+
+ DOCTOOL-END */
+
+ if (!tag && line[0] == '<')
+ {
+ tag = (char *)malloc(strlen(line)+1);
+ id = (char *)malloc(strlen(line)+1);
+ if (sscanf(line, "<%s id=\"%[^\"]\">", tag, id) == 2)
+ {
+ if (strcmp(tag, "book") == 0 || strcmp(tag, "BOOK") == 0)
+ {
+ /* Don't want to "scan" these */
+ return;
+ }
+ taglen = strlen(tag);
+ section = (Section *)malloc(sizeof(Section));
+ /* We want chunks within single files to appear in that order */
+ section->next = 0;
+ section->file = one;
+ *prev_section_ptr = section;
+ prev_section_ptr = &(section->next);
+ section->internal = 0;
+ section->addend = 0;
+ section->used = 0;
+ section->name = id;
+ if (starts_with(section->name, "add-"))
+ {
+ section->addend = 1;
+ section->name += 4;
+ }
+ if (starts_with(section->name, "int-"))
+ {
+ section->internal = 1;
+ section->name += 4;
+ }
+ section->lines = (char **)malloc(10*sizeof(char *));
+ section->num_lines = 0;
+ section->max_lines = 10;
+ }
+ else
+ {
+ free(tag);
+ free(id);
+ tag = id = 0;
+ }
+ }
+
+ if (tag && section)
+ {
+ if (section->num_lines >= section->max_lines)
+ {
+ section->max_lines += 10;
+ section->lines = (char **)realloc(section->lines,
+ section->max_lines * sizeof (char *));
+ }
+ section->lines[section->num_lines] = (char *)malloc(strlen(line)+1);
+ strcpy(section->lines[section->num_lines], line);
+ section->num_lines++;
+
+ if (line[0] == '<' && line[1] == '/'
+ && memcmp(line+2, tag, taglen) == 0
+ && (isspace(line[2+taglen]) || line[2+taglen] == '>'))
+ {
+ /* last line! */
+ tag = 0;
+ }
+ }
+ }
+ fclose(f);
+}
+
+/*****************************************************************************/
+
+Section **
+enumerate_matching_sections(char *name_prefix, int internal, int addend, int *count_ret)
+{
+ Section **rv = (Section **)malloc(12*sizeof(Section *));
+ int count = 0, max=10, prefix_len = strlen(name_prefix);
+ OneFile *one;
+ int wildcard = 0;
+
+ if (name_prefix[strlen(name_prefix)-1] == '-')
+ wildcard = 1;
+
+ for (one=file_list; one; one=one->next)
+ {
+ Section *s;
+ for (s=one->sections; s; s=s->next)
+ {
+ int matches = 0;
+ if (wildcard)
+ {
+ if (starts_with(s->name, name_prefix))
+ matches = 1;
+ }
+ else
+ {
+ if (strcmp(s->name, name_prefix) == 0)
+ matches = 1;
+ }
+ if (s->internal <= internal
+ && s->addend == addend
+ && matches
+ && ! s->used)
+ {
+ s->used = 1;
+ if (count >= max)
+ {
+ max += 10;
+ rv = (Section **)realloc(rv, max*sizeof(Section *));
+ }
+ rv[count++] = s;
+ rv[count] = 0;
+ }
+ }
+ }
+ if (count_ret)
+ *count_ret = count;
+ return rv;
+}
+
+/*****************************************************************************/
+
+#define ID_CHARS "~@$%&()_-+[]{}:."
+
+void include_section(char *name, int addend);
+
+char *
+unprefix(char *fn)
+{
+ int l = strlen(source_dir_prefix);
+ if (memcmp(fn, source_dir_prefix, l) == 0)
+ {
+ fn += l;
+ while (*fn == '/' || *fn == '\\')
+ fn++;
+ return fn;
+ }
+ return fn;
+}
+
+void
+parse_line(char *line, char *filename)
+{
+ char *cmd = has_string(line, "DOCTOOL-INSERT-");
+ char *sname, *send, *id, *save;
+ if (!cmd)
+ {
+ if (book_id
+ && (starts_with(line, "<book") || starts_with(line, "<BOOK")))
+ {
+ cmd = strchr(line, '>');
+ if (cmd)
+ {
+ cmd++;
+ fprintf(output_file, "<book id=\"%s\">", book_id);
+ fputs(cmd, output_file);
+ return;
+ }
+ }
+ fputs(line, output_file);
+ return;
+ }
+ if (cmd != line)
+ fwrite(line, cmd-line, 1, output_file);
+ save = (char *)malloc(strlen(line)+1);
+ strcpy(save, line);
+ line = save;
+
+ sname = cmd + 15; /* strlen("DOCTOOL-INSERT-") */
+ for (send = sname;
+ *send && isalnum(*send) || strchr(ID_CHARS, *send);
+ send++);
+ id = (char *)malloc(send-sname+2);
+ memcpy(id, sname, send-sname);
+ id[send-sname] = 0;
+ include_section(id, 0);
+
+ fprintf(output_file, "<!-- %s -->\n", unprefix(filename));
+
+ fputs(send, output_file);
+ free(save);
+}
+
+int
+section_sort(const void *va, const void *vb)
+{
+ Section *a = *(Section **)va;
+ Section *b = *(Section **)vb;
+ int rv = strcmp(a->name, b->name);
+ if (rv)
+ return rv;
+ return a->internal - b->internal;
+}
+
+void
+include_section(char *name, int addend)
+{
+ Section **sections, *s;
+ int count, i, l;
+
+ sections = enumerate_matching_sections(name, internal_flag, addend, &count);
+
+ qsort(sections, count, sizeof(sections[0]), section_sort);
+ for (i=0; i<count; i++)
+ {
+ s = sections[i];
+ s->file->used = 1;
+ fprintf(output_file, "<!-- %s -->\n", unprefix(s->file->filename));
+ for (l=addend; l<s->num_lines-1; l++)
+ parse_line(s->lines[l], s->file->filename);
+ if (!addend)
+ {
+ include_section(s->name, 1);
+ parse_line(s->lines[l], s->file->filename);
+ }
+ }
+
+ free(sections);
+}
+
+void
+parse_sgml(FILE *in, char *input_name)
+{
+ static char line[1000];
+ while (fgets(line, 1000, in))
+ {
+ parse_line(line, input_name);
+ }
+}
+
+/*****************************************************************************/
+
+void
+fix_makefile(char *output_name)
+{
+ FILE *in, *out;
+ char line[1000];
+ int oname_len = strlen(output_name);
+ OneFile *one;
+ int used_something = 0;
+ struct stat st;
+ struct utimbuf times;
+
+ stat("Makefile", &st);
+
+ in = fopen("Makefile", "r");
+ if (!in)
+ {
+ perror("Makefile");
+ return;
+ }
+
+ out = fopen("Makefile.new", "w");
+ if (!out)
+ {
+ perror("Makefile.new");
+ return;
+ }
+
+ while (fgets(line, 1000, in))
+ {
+ if (starts_with(line, output_name)
+ && strcmp(line+oname_len, ": \\\n") == 0)
+ {
+ /* this is the old dependency */
+ while (fgets(line, 1000, in))
+ {
+ if (strcmp(line+strlen(line)-2, "\\\n"))
+ break;
+ }
+ }
+ else
+ fputs(line, out);
+ }
+ fclose(in);
+
+ for (one=file_list; one; one=one->next)
+ if (one->used)
+ {
+ used_something = 1;
+ break;
+ }
+
+ if (used_something)
+ {
+ fprintf(out, "%s:", output_name);
+ for (one=file_list; one; one=one->next)
+ if (one->used)
+ fprintf(out, " \\\n\t%s", one->filename);
+ fprintf(out, "\n");
+ }
+
+ fclose(out);
+
+ times.actime = st.st_atime;
+ times.modtime = st.st_mtime;
+ utime("Makefile.new", &times);
+
+ if (rename("Makefile", "Makefile.old"))
+ return;
+ if (rename("Makefile.new", "Makefile"))
+ rename("Makefile.old", "Makefile");
+}
+
+/*****************************************************************************/
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+ OneFile *one;
+ FILE *input_file;
+ int fix_makefile_flag = 0;
+
+ while (argc > 1 && argv[1][0] == '-')
+ {
+ if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)
+ {
+ show_help();
+ }
+ else if (strcmp(argv[1], "-i") == 0)
+ {
+ internal_flag = 1;
+ }
+ else if (strcmp(argv[1], "-m") == 0)
+ {
+ fix_makefile_flag = 1;
+ }
+ else if (strcmp(argv[1], "-d") == 0 && argc > 2)
+ {
+ scan_directory(argv[2]);
+ argc--;
+ argv++;
+ }
+ else if (strcmp(argv[1], "-o") == 0 && argc > 2)
+ {
+ output_name = argv[2];
+ argc--;
+ argv++;
+ }
+ else if (strcmp(argv[1], "-s") == 0 && argc > 2)
+ {
+ source_dir_prefix = argv[2];
+ argc--;
+ argv++;
+ }
+ else if (strcmp(argv[1], "-b") == 0 && argc > 2)
+ {
+ book_id = argv[2];
+ argc--;
+ argv++;
+ }
+
+ argc--;
+ argv++;
+ }
+
+ for (one=file_list; one; one=one->next)
+ {
+ scan_file(one);
+ }
+
+ input_file = fopen(argv[1], "r");
+ if (!input_file)
+ {
+ perror(argv[1]);
+ return 1;
+ }
+
+ if (output_name)
+ {
+ output_file = fopen(output_name, "w");
+ if (!output_file)
+ {
+ perror(output_name);
+ return 1;
+ }
+ }
+ else
+ {
+ output_file = stdout;
+ output_name = "<stdout>";
+ }
+
+ parse_sgml(input_file, argv[1]);
+
+ if (output_file != stdout)
+ fclose(output_file);
+
+ if (fix_makefile_flag)
+ fix_makefile(output_name);
+
+ return 0;
+}