diff options
Diffstat (limited to 'winsup/doc/doctool.c')
-rw-r--r-- | winsup/doc/doctool.c | 622 |
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", ×); + + 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; +} |