From 36193beec108924ce9ac5a4c8058552ecd84fea2 Mon Sep 17 00:00:00 2001 From: Michael Sweet Date: Fri, 31 Mar 2017 13:38:20 -0400 Subject: [PATCH] Add first part of EPUB output code - XHTML content. --- mxmldoc.c | 585 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 486 insertions(+), 99 deletions(-) diff --git a/mxmldoc.c b/mxmldoc.c index f454df6..7a9dad1 100644 --- a/mxmldoc.c +++ b/mxmldoc.c @@ -32,6 +32,14 @@ extern char **environ; #endif /* __APPLE__ */ +#ifdef HAVE_ARCHIVE_H +# include +# include +#elif defined(__APPLE__) /* Use archive 2.8.3 headers for macOS */ +# include "xcode/archive.h" +# include "xcode/archive_entry.h" +#endif /* HAVE_ARCHIVE_H */ + /* * This program scans source and header files and produces public API @@ -39,11 +47,11 @@ extern char **environ; * Management Plan (CMP) coding standards. Please see the following web * page for details: * - * http://www.cups.org/cmp.html + * https://www.cups.org/doc/spec-cmp.html * * Using Mini-XML, this program creates and maintains an XML representation - * of the public API code documentation which can then be converted to HTML - * as desired. The following is a poor-man's schema: + * of the public API code documentation which can then be converted to HTML, + * man pages, or EPUB as desired. The following is a poor-man's schema: * * * value.text.whitespace) putc(' ', out); - if (mode == OUTPUT_HTML && + if ((mode == OUTPUT_HTML || mode == OUTPUT_EPUB) && (mxmlFindElement(doc, doc, "class", "name", node->value.text.string, MXML_DESCEND) || mxmlFindElement(doc, doc, "enumeration", "name", @@ -2960,6 +2973,351 @@ write_element(FILE *out, /* I - Output file */ } +/* + * 'write_epub()' - Write documentation as an EPUB file. + */ + +static void +write_epub(const char *section, /* I - Section */ + const char *title, /* I - Title */ + const char *footerfile, /* I - Footer file */ + const char *headerfile, /* I - Header file */ + const char *introfile, /* I - Intro file */ + const char *cssfile, /* I - Stylesheet file */ + const char *epubfile, /* I - EPUB file (output) */ + mxml_node_t *doc) /* I - XML documentation */ +{ + FILE *out; /* Output file */ + mxml_node_t *function, /* Current function */ + *scut, /* Struct/class/union/typedef */ + *arg, /* Current argument */ + *description, /* Description of function/var */ + *type; /* Type for argument */ + const char *name, /* Name of function/type */ + *defval; /* Default value */ +// *basename; /* Base filename for framed output */ +// char filename[1024]; /* Current output filename */ + + + out = fopen(epubfile, "w"); /* TODO: Update to write archive once the XHTML output is good... */ + + /* + * Standard header... + */ + + write_html_head(out, 1, section, title, cssfile); + + fputs("
\n", out); + + /* + * Header... + */ + + if (headerfile) + { + /* + * Use custom header... + */ + + write_file(out, headerfile); + } + else + { + /* + * Use standard header... + */ + + fputs("

", out); + write_string(out, title, OUTPUT_HTML); + fputs("

\n", out); + } + + /* + * Table of contents... + */ + + write_toc(out, doc, introfile, NULL, 0); + + /* + * Intro... + */ + + if (introfile) + write_file(out, introfile); + + /* + * List of classes... + */ + + if ((scut = find_public(doc, doc, "class")) != NULL) + { + fputs("

Classes

\n", out); + + while (scut) + { + write_scu(out, 1, doc, scut); + + scut = find_public(scut, doc, "class"); + } + } + + /* + * List of functions... + */ + + if ((function = find_public(doc, doc, "function")) != NULL) + { + fputs("

Functions

\n", out); + + while (function) + { + write_function(out, 1, doc, function, 3); + + function = find_public(function, doc, "function"); + } + } + + /* + * List of types... + */ + + if ((scut = find_public(doc, doc, "typedef")) != NULL) + { + fputs("

Data Types

\n", out); + + while (scut) + { + name = mxmlElementGetAttr(scut, "name"); + description = mxmlFindElement(scut, scut, "description", NULL, + NULL, MXML_DESCEND_FIRST); + fprintf(out, "

%s%s

\n", name, get_comment_info(description), name); + + if (description) + write_description(out, description, "p", 1); + + fputs("

\n" + "typedef ", out); + + type = mxmlFindElement(scut, scut, "type", NULL, NULL, + MXML_DESCEND_FIRST); + + for (type = type->child; type; type = type->next) + if (!strcmp(type->value.text.string, "(")) + break; + else + { + if (type->value.text.whitespace) + putc(' ', out); + + if (mxmlFindElement(doc, doc, "class", "name", + type->value.text.string, MXML_DESCEND) || + mxmlFindElement(doc, doc, "enumeration", "name", + type->value.text.string, MXML_DESCEND) || + mxmlFindElement(doc, doc, "struct", "name", + type->value.text.string, MXML_DESCEND) || + mxmlFindElement(doc, doc, "typedef", "name", + type->value.text.string, MXML_DESCEND) || + mxmlFindElement(doc, doc, "union", "name", + type->value.text.string, MXML_DESCEND)) + { + fputs("value.text.string, OUTPUT_HTML); + fputs("\">", out); + write_string(out, type->value.text.string, OUTPUT_HTML); + fputs("", out); + } + else + write_string(out, type->value.text.string, OUTPUT_HTML); + } + + if (type) + { + /* + * Output function type... + */ + + if (type->prev && type->prev->value.text.string[0] != '*') + putc(' ', out); + + fprintf(out, "(*%s", name); + + for (type = type->next->next; type; type = type->next) + { + if (type->value.text.whitespace) + putc(' ', out); + + if (mxmlFindElement(doc, doc, "class", "name", + type->value.text.string, MXML_DESCEND) || + mxmlFindElement(doc, doc, "enumeration", "name", + type->value.text.string, MXML_DESCEND) || + mxmlFindElement(doc, doc, "struct", "name", + type->value.text.string, MXML_DESCEND) || + mxmlFindElement(doc, doc, "typedef", "name", + type->value.text.string, MXML_DESCEND) || + mxmlFindElement(doc, doc, "union", "name", + type->value.text.string, MXML_DESCEND)) + { + fputs("value.text.string, OUTPUT_HTML); + fputs("\">", out); + write_string(out, type->value.text.string, OUTPUT_HTML); + fputs("", out); + } + else + write_string(out, type->value.text.string, OUTPUT_HTML); + } + + fputs(";\n", out); + } + else + { + type = mxmlFindElement(scut, scut, "type", NULL, NULL, + MXML_DESCEND_FIRST); + if (type->last_child->value.text.string[0] != '*') + putc(' ', out); + + fprintf(out, "%s;\n", name); + } + + fputs("

\n", out); + + scut = find_public(scut, doc, "typedef"); + } + } + + /* + * List of structures... + */ + + if ((scut = find_public(doc, doc, "struct")) != NULL) + { + fputs("

Structures

\n", + out); + + while (scut) + { + write_scu(out, 1, doc, scut); + + scut = find_public(scut, doc, "struct"); + } + } + + /* + * List of unions... + */ + + if ((scut = find_public(doc, doc, "union")) != NULL) + { + fputs("

Unions

\n", out); + + while (scut) + { + write_scu(out, 1, doc, scut); + + scut = find_public(scut, doc, "union"); + } + } + + /* + * Variables... + */ + + if ((arg = find_public(doc, doc, "variable")) != NULL) + { + fputs("

Variables

\n", + out); + + while (arg) + { + name = mxmlElementGetAttr(arg, "name"); + description = mxmlFindElement(arg, arg, "description", NULL, + NULL, MXML_DESCEND_FIRST); + fprintf(out, "

%s%s

\n", name, get_comment_info(description), name); + + if (description) + write_description(out, description, "p", 1); + + fputs("

", out); + + write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL, + NULL, MXML_DESCEND_FIRST), + OUTPUT_EPUB); + fputs(mxmlElementGetAttr(arg, "name"), out); + if ((defval = mxmlElementGetAttr(arg, "default")) != NULL) + fprintf(out, " %s", defval); + fputs(";

\n", out); + + arg = find_public(arg, doc, "variable"); + } + } + + /* + * List of enumerations... + */ + + if ((scut = find_public(doc, doc, "enumeration")) != NULL) + { + fputs("

Constants

\n", out); + + while (scut) + { + name = mxmlElementGetAttr(scut, "name"); + description = mxmlFindElement(scut, scut, "description", NULL, + NULL, MXML_DESCEND_FIRST); + fprintf(out, "

%s%s

\n", name, get_comment_info(description), name); + + if (description) + write_description(out, description, "p", 1); + + fputs("

Constants

\n" + "
\n", out); + + for (arg = mxmlFindElement(scut, scut, "constant", NULL, NULL, + MXML_DESCEND_FIRST); + arg; + arg = mxmlFindElement(arg, scut, "constant", NULL, NULL, + MXML_NO_DESCEND)) + { + description = mxmlFindElement(arg, arg, "description", NULL, + NULL, MXML_DESCEND_FIRST); + fprintf(out, "
%s %s
\n", + mxmlElementGetAttr(arg, "name"), get_comment_info(description)); + + write_description(out, description, "dd", 1); + write_description(out, description, "dd", 0); + } + + fputs("
\n", out); + + scut = find_public(scut, doc, "enumeration"); + } + } + + /* + * Footer... + */ + + if (footerfile) + { + /* + * Use custom footer... + */ + + write_file(out, footerfile); + } + + fputs("
\n" + "\n" + "\n", out); + + /* + * Close output file as needed... + */ + + fclose(out); +} + + /* * 'write_file()' - Copy a file to the output. */ @@ -2992,6 +3350,7 @@ write_file(FILE *out, /* I - Output file */ static void write_function(FILE *out, /* I - Output file */ + int xhtml, /* I - XHTML output? */ mxml_node_t *doc, /* I - Document */ mxml_node_t *function, /* I - Function */ int level) /* I - Base heading level */ @@ -3005,15 +3364,15 @@ write_function(FILE *out, /* I - Output file */ *defval; /* Default value */ char prefix; /* Prefix character */ char *sep; /* Newline separator */ + const char *br = xhtml ? "
" : "
"; + /* Break sequence */ name = mxmlElementGetAttr(function, "name"); description = mxmlFindElement(function, function, "description", NULL, NULL, MXML_DESCEND_FIRST); - fprintf(out, "%s%s\n", - level, level == 3 ? "function" : "method", - get_comment_info(description), name, name, level); + fprintf(out, "%s%s\n", level, level == 3 ? "function" : "method", get_comment_info(description), name, name, level); if (description) write_description(out, description, "p", 1); @@ -3040,7 +3399,7 @@ write_function(FILE *out, /* I - Output file */ type = mxmlFindElement(arg, arg, "type", NULL, NULL, MXML_DESCEND_FIRST); - fprintf(out, "%c
\n    ", prefix); + fprintf(out, "%c%s\n    ", prefix, br); if (type->child) write_element(out, doc, type, OUTPUT_HTML); @@ -3054,9 +3413,9 @@ write_function(FILE *out, /* I - Output file */ else { fprintf(out, - "
\n);

\n" + "%s\n);

\n" "Parameters\n" - "
\n", level + 1, level + 1); + "
\n", br, level + 1, level + 1); for (arg = mxmlFindElement(function, function, "argument", NULL, NULL, MXML_DESCEND_FIRST); @@ -3155,8 +3514,7 @@ write_html(const char *section, /* I - Section */ basename = framefile; if (strstr(basename, ".html")) - fputs("mxmldoc: Frame base name should not contain .html extension!\n", - stderr); + fputs("mxmldoc: Frame base name should not contain .html extension.\n", stderr); /* * Create the container HTML file for the frames... @@ -3171,10 +3529,9 @@ write_html(const char *section, /* I - Section */ return; } - fputs("\n" - "\n" - "\n" + fputs("\n" + "\n" + "\n" "\t", out); write_string(out, title, OUTPUT_HTML); fputs("\n", out); @@ -3184,7 +3541,7 @@ write_html(const char *section, /* I - Section */ fputs("\t\n" - "\t\n" + "\t\n" "\n", out); fputs("\n", out); @@ -3217,7 +3574,7 @@ write_html(const char *section, /* I - Section */ return; } - write_html_head(out, section, title, cssfile); + write_html_head(out, 0, section, title, cssfile); snprintf(filename, sizeof(filename), "%s-body.html", basename); @@ -3425,8 +3782,7 @@ write_html(const char *section, /* I - Section */ } #else - fputs("mxmldoc: Xcode documentation sets can only be created on " - "Mac OS X.\n", stderr); + fputs("mxmldoc: Xcode documentation sets can only be created on macOS.\n", stderr); return; #endif /* __APPLE__ */ } @@ -3437,7 +3793,7 @@ write_html(const char *section, /* I - Section */ * Standard header... */ - write_html_head(out, section, title, cssfile); + write_html_head(out, 0, section, title, cssfile); fputs("
\n", out); @@ -3484,11 +3840,11 @@ write_html(const char *section, /* I - Section */ if ((scut = find_public(doc, doc, "class")) != NULL) { - fputs("

Classes

\n", out); + fputs("

Classes

\n", out); while (scut) { - write_scu(out, doc, scut); + write_scu(out, 0, doc, scut); scut = find_public(scut, doc, "class"); } @@ -3500,11 +3856,11 @@ write_html(const char *section, /* I - Section */ if ((function = find_public(doc, doc, "function")) != NULL) { - fputs("

Functions

\n", out); + fputs("

Functions

\n", out); while (function) { - write_function(out, doc, function, 3); + write_function(out, 0, doc, function, 3); function = find_public(function, doc, "function"); } @@ -3516,14 +3872,14 @@ write_html(const char *section, /* I - Section */ if ((scut = find_public(doc, doc, "typedef")) != NULL) { - fputs("

Data Types

\n", out); + fputs("

Data Types

\n", out); while (scut) { name = mxmlElementGetAttr(scut, "name"); description = mxmlFindElement(scut, scut, "description", NULL, NULL, MXML_DESCEND_FIRST); - fprintf(out, "

%s%s

\n", + fprintf(out, "

%s%s

\n", get_comment_info(description), name, name); if (description) @@ -3625,12 +3981,12 @@ write_html(const char *section, /* I - Section */ if ((scut = find_public(doc, doc, "struct")) != NULL) { - fputs("

Structures

\n", + fputs("

Structures

\n", out); while (scut) { - write_scu(out, doc, scut); + write_scu(out, 0, doc, scut); scut = find_public(scut, doc, "struct"); } @@ -3642,11 +3998,11 @@ write_html(const char *section, /* I - Section */ if ((scut = find_public(doc, doc, "union")) != NULL) { - fputs("

Unions

\n", out); + fputs("

Unions

\n", out); while (scut) { - write_scu(out, doc, scut); + write_scu(out, 0, doc, scut); scut = find_public(scut, doc, "union"); } @@ -3658,7 +4014,7 @@ write_html(const char *section, /* I - Section */ if ((arg = find_public(doc, doc, "variable")) != NULL) { - fputs("

Variables

\n", + fputs("

Variables

\n", out); while (arg) @@ -3666,7 +4022,7 @@ write_html(const char *section, /* I - Section */ name = mxmlElementGetAttr(arg, "name"); description = mxmlFindElement(arg, arg, "description", NULL, NULL, MXML_DESCEND_FIRST); - fprintf(out, "

%s%s

\n", + fprintf(out, "

%s%s

\n", get_comment_info(description), name, name); if (description) @@ -3692,7 +4048,7 @@ write_html(const char *section, /* I - Section */ if ((scut = find_public(doc, doc, "enumeration")) != NULL) { - fputs("

Constants

\n", + fputs("

Constants

\n", out); while (scut) @@ -3700,7 +4056,7 @@ write_html(const char *section, /* I - Section */ name = mxmlElementGetAttr(scut, "name"); description = mxmlFindElement(scut, scut, "description", NULL, NULL, MXML_DESCEND_FIRST); - fprintf(out, "

%s%s

\n", + fprintf(out, "

%s%s

\n", get_comment_info(description), name, name); if (description) @@ -3817,13 +4173,20 @@ write_html(const char *section, /* I - Section */ static void write_html_head(FILE *out, /* I - Output file */ + int xhtml, /* I - XHTML output? */ const char *section, /* I - Section */ const char *title, /* I - Title */ const char *cssfile) /* I - Stylesheet */ { - fputs("\n" - "\n", out); + if (xhtml) + fputs("\n" + "\n" + "\n", out); + else + fputs("\n" + "\n", out); if (section) fprintf(out, "\n", section); @@ -3833,13 +4196,20 @@ write_html_head(FILE *out, /* I - Output file */ write_string(out, title, OUTPUT_HTML); fputs("\t\n", out); - if (section) - fprintf(out, "\t\n", section); + if (xhtml) + { + fputs("\t\n" - "\n" + if (xhtml) + fputs("]]>\n", out); + else + fputs("-->\n", out); + + fputs("\n" "\n", out); } @@ -4523,6 +4897,7 @@ write_man(const char *man_name, /* I - Name of manpage */ static void write_scu(FILE *out, /* I - Output file */ + int xhtml, /* I - XHTML output? */ mxml_node_t *doc, /* I - Document */ mxml_node_t *scut) /* I - Structure, class, or union */ { @@ -4539,6 +4914,8 @@ write_scu(FILE *out, /* I - Output file */ int inscope, /* Variable/method scope */ maxscope; /* Maximum scope */ char prefix; /* Prefix character */ + const char *br = xhtml ? "
" : "
"; + /* Break sequence */ static const char * const scopes[] = /* Scope strings */ { "private", @@ -4551,9 +4928,7 @@ write_scu(FILE *out, /* I - Output file */ description = mxmlFindElement(scut, scut, "description", NULL, NULL, MXML_DESCEND_FIRST); - fprintf(out, "

%s%s

\n", - scut->value.element.name, get_comment_info(description), cname, - cname); + fprintf(out, "

%s%s

\n", scut->value.element.name, get_comment_info(description), cname, cname); if (description) write_description(out, description, "p", 1); @@ -4561,7 +4936,7 @@ write_scu(FILE *out, /* I - Output file */ fprintf(out, "

%s %s", scut->value.element.name, cname); if ((parent = mxmlElementGetAttr(scut, "parent")) != NULL) fprintf(out, " %s", parent); - fputs(" {
\n", out); + fprintf(out, " {%s\n", br); maxscope = !strcmp(scut->value.element.name, "class") ? 3 : 1; @@ -4590,7 +4965,7 @@ write_scu(FILE *out, /* I - Output file */ write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL, NULL, MXML_DESCEND_FIRST), OUTPUT_HTML); - fprintf(out, "%s;
\n", mxmlElementGetAttr(arg, "name")); + fprintf(out, "%s;%s\n", mxmlElementGetAttr(arg, "name"), br); } for (function = mxmlFindElement(scut, scut, "function", NULL, NULL, @@ -4607,7 +4982,7 @@ write_scu(FILE *out, /* I - Output file */ if (!inscope) { inscope = 1; - fprintf(out, "  %s:
\n", scopes[i]); + fprintf(out, "  %s:%s\n", scopes[i], br); } name = mxmlElementGetAttr(function, "name"); @@ -4648,9 +5023,9 @@ write_scu(FILE *out, /* I - Output file */ } if (prefix == '(') - fputs("(void);
\n", out); + fprintf(out, "(void);%s\n", br); else - fputs(");
\n", out); + fprintf(out, ");%s\n", br); } } @@ -4682,7 +5057,7 @@ write_scu(FILE *out, /* I - Output file */ function = mxmlFindElement(function, scut, "function", NULL, NULL, MXML_NO_DESCEND)) { - write_function(out, doc, function, 4); + write_function(out, xhtml, doc, function, 4); } } @@ -4698,6 +5073,7 @@ write_string(FILE *out, /* I - Output file */ { switch (mode) { + case OUTPUT_EPUB : case OUTPUT_HTML : case OUTPUT_XML : while (*s) @@ -4856,13 +5232,22 @@ write_toc(FILE *out, /* I - Output file */ */ for (ptr = strchr(line, '<'); ptr; ptr = strchr(ptr + 1, '<')) + { if (!strncmp(ptr, "\n", out); else if (xmlid > 1) fputs("\n", out); + fprintf(out, "", xmlid); level = newlevel; xmlid ++; @@ -5015,6 +5401,7 @@ write_toc(FILE *out, /* I - Output file */ } } + fprintf(out, "\n", xmlid); fclose(fp); }