summaryrefslogtreecommitdiffstats
path: root/tdemarkdown/md4c/md2html
diff options
context:
space:
mode:
Diffstat (limited to 'tdemarkdown/md4c/md2html')
-rw-r--r--tdemarkdown/md4c/md2html/CMakeLists.txt22
-rw-r--r--tdemarkdown/md4c/md2html/cmdline.c205
-rw-r--r--tdemarkdown/md4c/md2html/cmdline.h153
-rw-r--r--tdemarkdown/md4c/md2html/md2html.1113
-rw-r--r--tdemarkdown/md4c/md2html/md2html.c383
5 files changed, 876 insertions, 0 deletions
diff --git a/tdemarkdown/md4c/md2html/CMakeLists.txt b/tdemarkdown/md4c/md2html/CMakeLists.txt
new file mode 100644
index 000000000..14de6712e
--- /dev/null
+++ b/tdemarkdown/md4c/md2html/CMakeLists.txt
@@ -0,0 +1,22 @@
+
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG")
+
+
+# Build rules for md2html command line utility
+
+include_directories("${PROJECT_SOURCE_DIR}/src")
+add_executable(md2html cmdline.c cmdline.h md2html.c)
+target_link_libraries(md2html md4c-html)
+
+
+# Install rules
+
+install(
+ TARGETS md2html
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+)
+install(FILES "md2html.1" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1")
+
diff --git a/tdemarkdown/md4c/md2html/cmdline.c b/tdemarkdown/md4c/md2html/cmdline.c
new file mode 100644
index 000000000..c3fddfaa4
--- /dev/null
+++ b/tdemarkdown/md4c/md2html/cmdline.c
@@ -0,0 +1,205 @@
+/*
+ * C Reusables
+ * <http://github.com/mity/c-reusables>
+ *
+ * Copyright (c) 2017-2020 Martin Mitas
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "cmdline.h"
+
+#include <stdio.h>
+#include <string.h>
+
+
+#ifdef _WIN32
+ #define snprintf _snprintf
+#endif
+
+
+#define CMDLINE_AUXBUF_SIZE 32
+
+
+
+static int
+cmdline_handle_short_opt_group(const CMDLINE_OPTION* options, const char* arggroup,
+ int (*callback)(int /*optval*/, const char* /*arg*/, void* /*userdata*/),
+ void* userdata)
+{
+ const CMDLINE_OPTION* opt;
+ int i;
+ int ret = 0;
+
+ for(i = 0; arggroup[i] != '\0'; i++) {
+ for(opt = options; opt->id != 0; opt++) {
+ if(arggroup[i] == opt->shortname)
+ break;
+ }
+
+ if(opt->id != 0 && !(opt->flags & CMDLINE_OPTFLAG_REQUIREDARG)) {
+ ret = callback(opt->id, NULL, userdata);
+ } else {
+ /* Unknown option. */
+ char badoptname[3];
+ badoptname[0] = '-';
+ badoptname[1] = arggroup[i];
+ badoptname[2] = '\0';
+ ret = callback((opt->id != 0 ? CMDLINE_OPTID_MISSINGARG : CMDLINE_OPTID_UNKNOWN),
+ badoptname, userdata);
+ }
+
+ if(ret != 0)
+ break;
+ }
+
+ return ret;
+}
+
+int
+cmdline_read(const CMDLINE_OPTION* options, int argc, char** argv,
+ int (*callback)(int /*optval*/, const char* /*arg*/, void* /*userdata*/),
+ void* userdata)
+{
+ const CMDLINE_OPTION* opt;
+ char auxbuf[CMDLINE_AUXBUF_SIZE+1];
+ int fast_optarg_decision = 1;
+ int after_doubledash = 0;
+ int i = 1;
+ int ret = 0;
+
+ auxbuf[CMDLINE_AUXBUF_SIZE] = '\0';
+
+ /* Check whether there is any CMDLINE_OPTFLAG_COMPILERLIKE option with
+ * a name not starting with '-'. That would imply we can to check for
+ * non-option arguments only after refusing all such options. */
+ for(opt = options; opt->id != 0; opt++) {
+ if((opt->flags & CMDLINE_OPTFLAG_COMPILERLIKE) && opt->longname[0] != '-')
+ fast_optarg_decision = 0;
+ }
+
+ while(i < argc) {
+ if(after_doubledash || strcmp(argv[i], "-") == 0) {
+ /* Non-option argument.
+ * Standalone "-" usually means "read from stdin" or "write to
+ * stdout" so treat it always as a non-option. */
+ ret = callback(CMDLINE_OPTID_NONE, argv[i], userdata);
+ } else if(strcmp(argv[i], "--") == 0) {
+ /* End of options. All the remaining tokens are non-options
+ * even if they start with a dash. */
+ after_doubledash = 1;
+ } else if(fast_optarg_decision && argv[i][0] != '-') {
+ /* Non-option argument. */
+ ret = callback(CMDLINE_OPTID_NONE, argv[i], userdata);
+ } else {
+ for(opt = options; opt->id != 0; opt++) {
+ if(opt->flags & CMDLINE_OPTFLAG_COMPILERLIKE) {
+ size_t len = strlen(opt->longname);
+ if(strncmp(argv[i], opt->longname, len) == 0) {
+ /* Compiler-like option. */
+ if(argv[i][len] != '\0')
+ ret = callback(opt->id, argv[i] + len, userdata);
+ else if(i+1 < argc)
+ ret = callback(opt->id, argv[++i], userdata);
+ else
+ ret = callback(CMDLINE_OPTID_MISSINGARG, opt->longname, userdata);
+ break;
+ }
+ } else if(opt->longname != NULL && strncmp(argv[i], "--", 2) == 0) {
+ size_t len = strlen(opt->longname);
+ if(strncmp(argv[i]+2, opt->longname, len) == 0) {
+ /* Regular long option. */
+ if(argv[i][2+len] == '\0') {
+ /* with no argument provided. */
+ if(!(opt->flags & CMDLINE_OPTFLAG_REQUIREDARG))
+ ret = callback(opt->id, NULL, userdata);
+ else
+ ret = callback(CMDLINE_OPTID_MISSINGARG, argv[i], userdata);
+ break;
+ } else if(argv[i][2+len] == '=') {
+ /* with an argument provided. */
+ if(opt->flags & (CMDLINE_OPTFLAG_OPTIONALARG | CMDLINE_OPTFLAG_REQUIREDARG)) {
+ ret = callback(opt->id, argv[i]+2+len+1, userdata);
+ } else {
+ snprintf(auxbuf, CMDLINE_AUXBUF_SIZE, "--%s", opt->longname);
+ ret = callback(CMDLINE_OPTID_BOGUSARG, auxbuf, userdata);
+ }
+ break;
+ } else {
+ continue;
+ }
+ }
+ } else if(opt->shortname != '\0' && argv[i][0] == '-') {
+ if(argv[i][1] == opt->shortname) {
+ /* Regular short option. */
+ if(opt->flags & CMDLINE_OPTFLAG_REQUIREDARG) {
+ if(argv[i][2] != '\0')
+ ret = callback(opt->id, argv[i]+2, userdata);
+ else if(i+1 < argc)
+ ret = callback(opt->id, argv[++i], userdata);
+ else
+ ret = callback(CMDLINE_OPTID_MISSINGARG, argv[i], userdata);
+ break;
+ } else {
+ ret = callback(opt->id, NULL, userdata);
+
+ /* There might be more (argument-less) short options
+ * grouped together. */
+ if(ret == 0 && argv[i][2] != '\0')
+ ret = cmdline_handle_short_opt_group(options, argv[i]+2, callback, userdata);
+ break;
+ }
+ }
+ }
+ }
+
+ if(opt->id == 0) { /* still not handled? */
+ if(argv[i][0] != '-') {
+ /* Non-option argument. */
+ ret = callback(CMDLINE_OPTID_NONE, argv[i], userdata);
+ } else {
+ /* Unknown option. */
+ char* badoptname = argv[i];
+
+ if(strncmp(badoptname, "--", 2) == 0) {
+ /* Strip any argument from the long option. */
+ char* assignment = strchr(badoptname, '=');
+ if(assignment != NULL) {
+ size_t len = assignment - badoptname;
+ if(len > CMDLINE_AUXBUF_SIZE)
+ len = CMDLINE_AUXBUF_SIZE;
+ strncpy(auxbuf, badoptname, len);
+ auxbuf[len] = '\0';
+ badoptname = auxbuf;
+ }
+ }
+
+ ret = callback(CMDLINE_OPTID_UNKNOWN, badoptname, userdata);
+ }
+ }
+ }
+
+ if(ret != 0)
+ return ret;
+ i++;
+ }
+
+ return ret;
+}
+
diff --git a/tdemarkdown/md4c/md2html/cmdline.h b/tdemarkdown/md4c/md2html/cmdline.h
new file mode 100644
index 000000000..5bbde47eb
--- /dev/null
+++ b/tdemarkdown/md4c/md2html/cmdline.h
@@ -0,0 +1,153 @@
+/*
+ * C Reusables
+ * <http://github.com/mity/c-reusables>
+ *
+ * Copyright (c) 2017 Martin Mitas
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef CRE_CMDLINE_H
+#define CRE_CMDLINE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* The option may have an argument. (Affects only long option.) */
+#define CMDLINE_OPTFLAG_OPTIONALARG 0x0001
+
+/* The option must have an argument.
+ * Such short option cannot be grouped within single '-abc'. */
+#define CMDLINE_OPTFLAG_REQUIREDARG 0x0002
+
+/* Enable special compiler-like mode for the long option.
+ *
+ * Note ::shortname is not supported with this flag. CMDLINE_OPTION::shortname
+ * is silently ignored if the flag is used.
+ *
+ * With this flag, CMDLINE_OPTION::longname is treated differently as follows:
+ *
+ * 1. The option matches if the CMDLINE_OPTION::longname is the exact prefix
+ * of the argv[i] from commandline.
+ *
+ * 2. Double dash ("--") is not automatically prepended to
+ * CMDLINE_OPTION::longname. (If you desire any leading dash, include it
+ * explicitly in CMDLINE_OPTION initialization.)
+ *
+ * 3. An argument (optionally after a whitespace) is required (the flag
+ * CMDLINE_OPTFLAG_COMPILERLIKE implicitly implies also the flag
+ * CMDLINE_OPTFLAG_REQUIREDARG).
+ *
+ * But there is no delimiter expected (no "=" between the option and its
+ * argument). Whitespace is optional between the option and its argument.
+ *
+ * Intended use is for options similar to what many compilers accept.
+ * For example:
+ * -DDEBUG=0 (-D is the option, DEBUG=0 is the argument).
+ * -Isrc/include (-I is the option, src/include is the argument).
+ * -isystem /usr/include (-isystem is the option, /usr/include is the argument).
+ * -lmath (-l is the option, math is the argument).
+ */
+#define CMDLINE_OPTFLAG_COMPILERLIKE 0x0004
+
+
+/* Special (reserved) option IDs. Do not use these for any CMDLINE_OPTION::id.
+ * See documentation of cmdline_read() to get info about their meaning.
+ */
+#define CMDLINE_OPTID_NONE 0
+#define CMDLINE_OPTID_UNKNOWN (-0x7fffffff + 0)
+#define CMDLINE_OPTID_MISSINGARG (-0x7fffffff + 1)
+#define CMDLINE_OPTID_BOGUSARG (-0x7fffffff + 2)
+
+
+typedef struct CMDLINE_OPTION {
+ char shortname; /* Short (single char) option or 0. */
+ const char* longname; /* Long name (after "--") or NULL. */
+ int id; /* Non-zero ID to identify the option in the callback; or zero to denote end of options list. */
+ unsigned flags; /* Bitmask of CMDLINE_OPTFLAG_xxxx flags. */
+} CMDLINE_OPTION;
+
+
+/* Parses all options and their arguments as specified by argc, argv accordingly
+ * with the given options (except argv[0] which is ignored).
+ *
+ * The caller must specify the list of supported options in the 1st parameter
+ * of the function. The array must end with a record whose CMDLINE_OPTION::id
+ * is zero to zero.
+ *
+ * The provided callback function is called for each option on the command
+ * line so that:
+ *
+ * -- the "id" refers to the id of the option as specified in options[].
+ *
+ * -- the "arg" specifies an argument of the option or NULL if none is
+ * provided.
+ *
+ * -- the "userdata" just allows to pass in some caller's context into
+ * the callback.
+ *
+ * Special cases (recognized via special "id" value) are reported to the
+ * callback as follows:
+ *
+ * -- If id is CMDLINE_OPTID_NONE, the callback informs about a non-option
+ * also known as a positional argument.
+ *
+ * All argv[] tokens which are not interpreted as an options or an argument
+ * of any option fall into this category.
+ *
+ * Usually, programs interpret these as paths to file to process.
+ *
+ * -- If id is CMDLINE_OPTID_UNKNOWN, the corresponding argv[] looks like an
+ * option but it is not found in the options[] passed to cmdline_read().
+ *
+ * The callback's parameter arg specifies the guilty command line token.
+ * Usually, program writes down an error message and exits.
+ *
+ * -- If id is CMDLINE_OPTID_MISSINGARG, the given option is valid but its
+ * flag in options[] requires an argument; yet there is none on the
+ * command line.
+ *
+ * The callback's parameter arg specifies the guilty option name.
+ * Usually, program writes down an error message and exits.
+ *
+ * -- If id is CMDLINE_OPTID_BOGUSARG, the given option is valid but its
+ * flag in options[] does not expect an argument; yet the command line
+ * does provide one.
+ *
+ * The callback's parameter arg specifies the guilty option name.
+ * Usually, program writes down an error message and exits.
+ *
+ * On success, zero is returned.
+ *
+ * If the callback returns a non-zero, cmdline_read() aborts immediately and
+ * cmdline_read() propagates the same return value to the caller.
+ */
+
+int cmdline_read(const CMDLINE_OPTION* options, int argc, char** argv,
+ int (*callback)(int /*id*/, const char* /*arg*/, void* /*userdata*/),
+ void* userdata);
+
+
+#ifdef __cplusplus
+} /* extern "C" { */
+#endif
+
+#endif /* CRE_CMDLINE_H */
diff --git a/tdemarkdown/md4c/md2html/md2html.1 b/tdemarkdown/md4c/md2html/md2html.1
new file mode 100644
index 000000000..cffaee8b8
--- /dev/null
+++ b/tdemarkdown/md4c/md2html/md2html.1
@@ -0,0 +1,113 @@
+.TH MD2HTML 1 "June 2019" "" "General Commands Manual"
+.nh
+.ad l
+.
+.SH NAME
+.
+md2html \- convert Markdown to HTML
+.
+.SH SYNOPSIS
+.
+.B md2html
+.RI [ OPTION ]...\&
+.RI [ FILE ]
+.
+.SH OPTIONS
+.
+.SS General options:
+.
+.TP
+.BR -o ", " --output= \fIOUTFILE\fR
+Write output to \fIOUTFILE\fR instead of \fBstdout\fR(3)
+.
+.TP
+.BR -f ", " --full-html
+Generate full HTML document, including header
+.
+.TP
+.BR -s ", " --stat
+Measure time of input parsing
+.
+.TP
+.BR -h ", " --help
+Display help and exit
+.
+.TP
+.BR -v ", " --version
+Display version and exit
+.
+.SS Markdown dialect options:
+.
+.TP
+.B --commonmark
+CommonMark (the default)
+.
+.TP
+.B --github
+Github Flavored Markdown
+.
+.PP
+Note: dialect options are equivalent to some combination of flags below.
+.
+.SS Markdown extension options:
+.
+.TP
+.B --fcollapse-whitespace
+Collapse non-trivial whitespace
+.
+.TP
+.B --fverbatim-entities
+Do not translate entities
+.
+.TP
+.B --fpermissive-atx-headers
+Allow ATX headers without delimiting space
+.
+.TP
+.B --fpermissive-url-autolinks
+Allow URL autolinks without "<" and ">" delimiters
+.
+.TP
+.B --fpermissive-www-autolinks
+Allow WWW autolinks without any scheme (e.g. "www.example.com")
+.
+.TP
+.B --fpermissive-email-autolinks
+Allow e-mail autolinks without "<", ">" and "mailto:"
+.
+.TP
+.B --fpermissive-autolinks
+Enable all 3 of the above permissive autolinks options
+.
+.TP
+.B --fno-indented-code
+Disable indented code blocks
+.
+.TP
+.B --fno-html-blocks
+Disable raw HTML blocks
+.
+.TP
+.B --fno-html-spans
+Disable raw HTML spans
+.
+.TP
+.B --fno-html
+Same as \fB--fno-html-blocks --fno-html-spans\fR
+.
+.TP
+.B --ftables
+Enable tables
+.
+.TP
+.B --fstrikethrough
+Enable strikethrough spans
+.
+.TP
+.B --ftasklists
+Enable task lists
+.
+.SH SEE ALSO
+.
+https://github.com/mity/md4c
+.
diff --git a/tdemarkdown/md4c/md2html/md2html.c b/tdemarkdown/md4c/md2html/md2html.c
new file mode 100644
index 000000000..06b2b74b1
--- /dev/null
+++ b/tdemarkdown/md4c/md2html/md2html.c
@@ -0,0 +1,383 @@
+/*
+ * MD4C: Markdown parser for C
+ * (http://github.com/mity/md4c)
+ *
+ * Copyright (c) 2016-2020 Martin Mitas
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "md4c-html.h"
+#include "cmdline.h"
+
+
+
+/* Global options. */
+static unsigned parser_flags = 0;
+#ifndef MD4C_USE_ASCII
+ static unsigned renderer_flags = MD_HTML_FLAG_DEBUG | MD_HTML_FLAG_SKIP_UTF8_BOM;
+#else
+ static unsigned renderer_flags = MD_HTML_FLAG_DEBUG;
+#endif
+static int want_fullhtml = 0;
+static int want_xhtml = 0;
+static int want_stat = 0;
+
+
+/*********************************
+ *** Simple grow-able buffer ***
+ *********************************/
+
+/* We render to a memory buffer instead of directly outputting the rendered
+ * documents, as this allows using this utility for evaluating performance
+ * of MD4C (--stat option). This allows us to measure just time of the parser,
+ * without the I/O.
+ */
+
+struct membuffer {
+ char* data;
+ size_t asize;
+ size_t size;
+};
+
+static void
+membuf_init(struct membuffer* buf, MD_SIZE new_asize)
+{
+ buf->size = 0;
+ buf->asize = new_asize;
+ buf->data = malloc(buf->asize);
+ if(buf->data == NULL) {
+ fprintf(stderr, "membuf_init: malloc() failed.\n");
+ exit(1);
+ }
+}
+
+static void
+membuf_fini(struct membuffer* buf)
+{
+ if(buf->data)
+ free(buf->data);
+}
+
+static void
+membuf_grow(struct membuffer* buf, size_t new_asize)
+{
+ buf->data = realloc(buf->data, new_asize);
+ if(buf->data == NULL) {
+ fprintf(stderr, "membuf_grow: realloc() failed.\n");
+ exit(1);
+ }
+ buf->asize = new_asize;
+}
+
+static void
+membuf_append(struct membuffer* buf, const char* data, MD_SIZE size)
+{
+ if(buf->asize < buf->size + size)
+ membuf_grow(buf, buf->size + buf->size / 2 + size);
+ memcpy(buf->data + buf->size, data, size);
+ buf->size += size;
+}
+
+
+/**********************
+ *** Main program ***
+ **********************/
+
+static void
+process_output(const MD_CHAR* text, MD_SIZE size, void* userdata)
+{
+ membuf_append((struct membuffer*) userdata, text, size);
+}
+
+static int
+process_file(FILE* in, FILE* out)
+{
+ size_t n;
+ struct membuffer buf_in = {0};
+ struct membuffer buf_out = {0};
+ int ret = -1;
+ clock_t t0, t1;
+
+ membuf_init(&buf_in, 32 * 1024);
+
+ /* Read the input file into a buffer. */
+ while(1) {
+ if(buf_in.size >= buf_in.asize)
+ membuf_grow(&buf_in, buf_in.asize + buf_in.asize / 2);
+
+ n = fread(buf_in.data + buf_in.size, 1, buf_in.asize - buf_in.size, in);
+ if(n == 0)
+ break;
+ buf_in.size += n;
+ }
+
+ /* Input size is good estimation of output size. Add some more reserve to
+ * deal with the HTML header/footer and tags. */
+ membuf_init(&buf_out, (MD_SIZE)(buf_in.size + buf_in.size/8 + 64));
+
+ /* Parse the document. This shall call our callbacks provided via the
+ * md_renderer_t structure. */
+ t0 = clock();
+
+ ret = md_html(buf_in.data, (MD_SIZE)buf_in.size, process_output, (void*) &buf_out,
+ parser_flags, renderer_flags);
+
+ t1 = clock();
+ if(ret != 0) {
+ fprintf(stderr, "Parsing failed.\n");
+ goto out;
+ }
+
+ /* Write down the document in the HTML format. */
+ if(want_fullhtml) {
+ if(want_xhtml) {
+ fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf(out, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
+ "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n");
+ fprintf(out, "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n");
+ } else {
+ fprintf(out, "<!DOCTYPE html>\n");
+ fprintf(out, "<html>\n");
+ }
+ fprintf(out, "<head>\n");
+ fprintf(out, "<title></title>\n");
+ fprintf(out, "<meta name=\"generator\" content=\"md2html\"%s>\n", want_xhtml ? " /" : "");
+ fprintf(out, "</head>\n");
+ fprintf(out, "<body>\n");
+ }
+
+ fwrite(buf_out.data, 1, buf_out.size, out);
+
+ if(want_fullhtml) {
+ fprintf(out, "</body>\n");
+ fprintf(out, "</html>\n");
+ }
+
+ if(want_stat) {
+ if(t0 != (clock_t)-1 && t1 != (clock_t)-1) {
+ double elapsed = (double)(t1 - t0) / CLOCKS_PER_SEC;
+ if (elapsed < 1)
+ fprintf(stderr, "Time spent on parsing: %7.2f ms.\n", elapsed*1e3);
+ else
+ fprintf(stderr, "Time spent on parsing: %6.3f s.\n", elapsed);
+ }
+ }
+
+ /* Success if we have reached here. */
+ ret = 0;
+
+out:
+ membuf_fini(&buf_in);
+ membuf_fini(&buf_out);
+
+ return ret;
+}
+
+
+static const CMDLINE_OPTION cmdline_options[] = {
+ { 'o', "output", 'o', CMDLINE_OPTFLAG_REQUIREDARG },
+ { 'f', "full-html", 'f', 0 },
+ { 'x', "xhtml", 'x', 0 },
+ { 's', "stat", 's', 0 },
+ { 'h', "help", 'h', 0 },
+ { 'v', "version", 'v', 0 },
+
+ { 0, "commonmark", 'c', 0 },
+ { 0, "github", 'g', 0 },
+
+ { 0, "fcollapse-whitespace", 'W', 0 },
+ { 0, "flatex-math", 'L', 0 },
+ { 0, "fpermissive-atx-headers", 'A', 0 },
+ { 0, "fpermissive-autolinks", 'V', 0 },
+ { 0, "fpermissive-email-autolinks", '@', 0 },
+ { 0, "fpermissive-url-autolinks", 'U', 0 },
+ { 0, "fpermissive-www-autolinks", '.', 0 },
+ { 0, "fstrikethrough", 'S', 0 },
+ { 0, "ftables", 'T', 0 },
+ { 0, "ftasklists", 'X', 0 },
+ { 0, "funderline", '_', 0 },
+ { 0, "fverbatim-entities", 'E', 0 },
+ { 0, "fwiki-links", 'K', 0 },
+
+ { 0, "fno-html-blocks", 'F', 0 },
+ { 0, "fno-html-spans", 'G', 0 },
+ { 0, "fno-html", 'H', 0 },
+ { 0, "fno-indented-code", 'I', 0 },
+
+ { 0, NULL, 0, 0 }
+};
+
+static void
+usage(void)
+{
+ printf(
+ "Usage: md2html [OPTION]... [FILE]\n"
+ "Convert input FILE (or standard input) in Markdown format to HTML.\n"
+ "\n"
+ "General options:\n"
+ " -o --output=FILE Output file (default is standard output)\n"
+ " -f, --full-html Generate full HTML document, including header\n"
+ " -x, --xhtml Generate XHTML instead of HTML\n"
+ " -s, --stat Measure time of input parsing\n"
+ " -h, --help Display this help and exit\n"
+ " -v, --version Display version and exit\n"
+ "\n"
+ "Markdown dialect options:\n"
+ "(note these are equivalent to some combinations of the flags below)\n"
+ " --commonmark CommonMark (this is default)\n"
+ " --github Github Flavored Markdown\n"
+ "\n"
+ "Markdown extension options:\n"
+ " --fcollapse-whitespace\n"
+ " Collapse non-trivial whitespace\n"
+ " --flatex-math Enable LaTeX style mathematics spans\n"
+ " --fpermissive-atx-headers\n"
+ " Allow ATX headers without delimiting space\n"
+ " --fpermissive-url-autolinks\n"
+ " Allow URL autolinks without '<', '>'\n"
+ " --fpermissive-www-autolinks\n"
+ " Allow WWW autolinks without any scheme (e.g. 'www.example.com')\n"
+ " --fpermissive-email-autolinks \n"
+ " Allow e-mail autolinks without '<', '>' and 'mailto:'\n"
+ " --fpermissive-autolinks\n"
+ " Same as --fpermissive-url-autolinks --fpermissive-www-autolinks\n"
+ " --fpermissive-email-autolinks\n"
+ " --fstrikethrough Enable strike-through spans\n"
+ " --ftables Enable tables\n"
+ " --ftasklists Enable task lists\n"
+ " --funderline Enable underline spans\n"
+ " --fwiki-links Enable wiki links\n"
+ "\n"
+ "Markdown suppression options:\n"
+ " --fno-html-blocks\n"
+ " Disable raw HTML blocks\n"
+ " --fno-html-spans\n"
+ " Disable raw HTML spans\n"
+ " --fno-html Same as --fno-html-blocks --fno-html-spans\n"
+ " --fno-indented-code\n"
+ " Disable indented code blocks\n"
+ "\n"
+ "HTML generator options:\n"
+ " --fverbatim-entities\n"
+ " Do not translate entities\n"
+ "\n"
+ );
+}
+
+static void
+version(void)
+{
+ printf("%d.%d.%d\n", MD_VERSION_MAJOR, MD_VERSION_MINOR, MD_VERSION_RELEASE);
+}
+
+static const char* input_path = NULL;
+static const char* output_path = NULL;
+
+static int
+cmdline_callback(int opt, char const* value, void* data)
+{
+ switch(opt) {
+ case 0:
+ if(input_path) {
+ fprintf(stderr, "Too many arguments. Only one input file can be specified.\n");
+ fprintf(stderr, "Use --help for more info.\n");
+ exit(1);
+ }
+ input_path = value;
+ break;
+
+ case 'o': output_path = value; break;
+ case 'f': want_fullhtml = 1; break;
+ case 'x': want_xhtml = 1; renderer_flags |= MD_HTML_FLAG_XHTML; break;
+ case 's': want_stat = 1; break;
+ case 'h': usage(); exit(0); break;
+ case 'v': version(); exit(0); break;
+
+ case 'c': parser_flags |= MD_DIALECT_COMMONMARK; break;
+ case 'g': parser_flags |= MD_DIALECT_GITHUB; break;
+
+ case 'E': renderer_flags |= MD_HTML_FLAG_VERBATIM_ENTITIES; break;
+ case 'A': parser_flags |= MD_FLAG_PERMISSIVEATXHEADERS; break;
+ case 'I': parser_flags |= MD_FLAG_NOINDENTEDCODEBLOCKS; break;
+ case 'F': parser_flags |= MD_FLAG_NOHTMLBLOCKS; break;
+ case 'G': parser_flags |= MD_FLAG_NOHTMLSPANS; break;
+ case 'H': parser_flags |= MD_FLAG_NOHTML; break;
+ case 'W': parser_flags |= MD_FLAG_COLLAPSEWHITESPACE; break;
+ case 'U': parser_flags |= MD_FLAG_PERMISSIVEURLAUTOLINKS; break;
+ case '.': parser_flags |= MD_FLAG_PERMISSIVEWWWAUTOLINKS; break;
+ case '@': parser_flags |= MD_FLAG_PERMISSIVEEMAILAUTOLINKS; break;
+ case 'V': parser_flags |= MD_FLAG_PERMISSIVEAUTOLINKS; break;
+ case 'T': parser_flags |= MD_FLAG_TABLES; break;
+ case 'S': parser_flags |= MD_FLAG_STRIKETHROUGH; break;
+ case 'L': parser_flags |= MD_FLAG_LATEXMATHSPANS; break;
+ case 'K': parser_flags |= MD_FLAG_WIKILINKS; break;
+ case 'X': parser_flags |= MD_FLAG_TASKLISTS; break;
+ case '_': parser_flags |= MD_FLAG_UNDERLINE; break;
+
+ default:
+ fprintf(stderr, "Illegal option: %s\n", value);
+ fprintf(stderr, "Use --help for more info.\n");
+ exit(1);
+ break;
+ }
+
+ return 0;
+}
+
+int
+main(int argc, char** argv)
+{
+ FILE* in = stdin;
+ FILE* out = stdout;
+ int ret = 0;
+
+ if(cmdline_read(cmdline_options, argc, argv, cmdline_callback, NULL) != 0) {
+ usage();
+ exit(1);
+ }
+
+ if(input_path != NULL && strcmp(input_path, "-") != 0) {
+ in = fopen(input_path, "rb");
+ if(in == NULL) {
+ fprintf(stderr, "Cannot open %s.\n", input_path);
+ exit(1);
+ }
+ }
+ if(output_path != NULL && strcmp(output_path, "-") != 0) {
+ out = fopen(output_path, "wt");
+ if(out == NULL) {
+ fprintf(stderr, "Cannot open %s.\n", output_path);
+ exit(1);
+ }
+ }
+
+ ret = process_file(in, out);
+ if(in != stdin)
+ fclose(in);
+ if(out != stdout)
+ fclose(out);
+
+ return ret;
+}