char* OxMarkDownToHtml(char* sMarkDown) { hoedown_renderer *renderer; hoedown_document *document; hoedown_buffer *buffer; unsigned int extensions = 0, render_flags = 0; const uint8_t *sHtml; renderer = hoedown_html_renderer_new(render_flags, 0); document = hoedown_document_new(renderer, extensions, 16); buffer = hoedown_buffer_new(16); hoedown_document_render(document, buffer, (const uint8_t *)sMarkDown, strlen(sMarkDown)); sHtml = (char*)OxAllocate(buffer->size + 1); StringCchCopyA(sHtml, buffer->size + 1, buffer->data); hoedown_buffer_reset(buffer); hoedown_html_smartypants(buffer, sHtml, buffer->size); hoedown_buffer_free(buffer); hoedown_document_free(document); hoedown_html_renderer_free(renderer); return sHtml; }
// // return html rendered markdown of note text // QString Note::toMarkdownHtml() { hoedown_renderer *renderer = hoedown_html_renderer_new( HOEDOWN_HTML_USE_XHTML, 16 ); hoedown_document *document = hoedown_document_new(renderer, (hoedown_extensions) HOEDOWN_EXT_SPAN, 16); QString str = this->noteText; unsigned char *sequence = (unsigned char*)qstrdup( str.toUtf8().constData() ); int length = strlen( (char*) sequence ); // return an empty string if the note is empty if ( length == 0 ) { return ""; } hoedown_buffer *html = hoedown_buffer_new( length ); // render markdown html hoedown_document_render( document, html, sequence, length ); // get markdown html QString result = QString::fromUtf8( (char*) html->data, html->size ); /* Cleanup */ free(sequence); hoedown_buffer_free(html); hoedown_document_free(document); hoedown_html_renderer_free(renderer); return result; }
// Converts markdown to html QString Markdown::convert2html(const QString& markdown) { QString html; if ( !markdown.isEmpty() ) { QString markdownClean = parseCustomLinksForHTML(markdown); hoedown_html_flags flags = HOEDOWN_HTML_USE_XHTML; hoedown_extensions extensions = (hoedown_extensions)(HOEDOWN_EXT_BLOCK|HOEDOWN_EXT_SPAN|HOEDOWN_EXT_FLAGS); size_t max_nesting = 16; hoedown_renderer *renderer = hoedown_html_renderer_new(flags, 0); hoedown_document *document = hoedown_document_new(renderer, extensions, max_nesting); hoedown_buffer *result = hoedown_buffer_new(max_nesting); std::string markdownStr = markdownClean.toStdString(); hoedown_document_render( document, result, reinterpret_cast<const uint8_t*>(&markdownStr[0]), markdownStr.size() ); std::ostringstream convert; for (size_t x = 0; x < result->size; x++) { convert << result->data[x]; } html = QString::fromStdString( convert.str() ); hoedown_buffer_free(result); hoedown_document_free(document); hoedown_html_renderer_free(renderer); } return html; }
void Preview::refresh() { if (!needRefresh) return; if (type == MARKDOWN) { qDebug() << "Render Markdown and refresh preview"; std::string std_str = content.toStdString(); const char* cstr = std_str.c_str(); hoedown_buffer_set(buf, 0, 0); hoedown_document_render(document, buf, (const uint8_t*)cstr, strlen(cstr)); QString html((const char*)buf->data); html = themelize(html); webView->setHtml(html); needRefresh = false; } else if (type == HTML) { qDebug() << "Render html and refresh preview"; qDebug() << "content: " << content; webView->setHtml(content); needRefresh = false; } }
QString Markdown::parseMarkdown(QString input) { if (input == "") input.append(" "); hoedown_buffer *ib, *ob; size_t iunit = DEF_IUNIT, ounit = DEF_OUNIT; hoedown_document *document; hoedown_extensions extensions; size_t max_nesting = DEF_MAX_NESTING; hoedown_renderer *renderer = NULL; void (*renderer_free)(hoedown_renderer*) = NULL; hoedown_html_flags html_flags; int toc_level = 0; html_flags = HOEDOWN_HTML_HARD_WRAP; extensions = HOEDOWN_EXT_QUOTE; renderer = hoedown_html_renderer_new(html_flags, toc_level); renderer_free = hoedown_html_renderer_free; ib = hoedown_buffer_new(iunit); // reading input std::string stdStringInput = input.toUtf8().constData(); unsigned char* charInput = (unsigned char *)stdStringInput.c_str(); ib->data = charInput + ib->size; ib->size = strlen((char*)charInput); // eori ob = hoedown_buffer_new(ounit); document = hoedown_document_new(renderer, extensions, max_nesting); hoedown_document_render(document, ob, ib->data, ib->size); std::string outputStdString = (char*) ob->data; // this is for trimming output buffer outputStdString.erase(ob->size, outputStdString.length()); hoedown_document_free(document); hoedown_buffer_free(ob); renderer_free(renderer); //free(ib); QString output = QString::fromStdString(outputStdString); return output; }
int main(int argc, char **argv) { int show_time = 0; //struct timespec start, end; /* buffers */ hoedown_buffer *ib, *ob; size_t iunit = DEF_IUNIT, ounit = DEF_OUNIT; /* files */ FILE *in = NULL; /* renderer */ int toc_level = 0; int renderer_type = RENDERER_HTML; /* document */ hoedown_document *document; unsigned int extensions = 0; size_t max_nesting = DEF_MAX_NESTING; /* HTML renderer-specific */ unsigned int html_flags = 0; /* option parsing */ int just_args = 0; int i, j; for (i = 1; i < argc; i++) { char *arg = argv[i]; if (!arg[0]) continue; if (just_args || arg[0] != '-') { /* regular argument */ in = fopen(arg, "r"); if (!in) { fprintf(stderr, "Unable to open input file \"%s\": %s\n", arg, strerror(errno)); return 5; } continue; } if (!arg[1]) { /* arg is "-" */ in = stdin; continue; } if (arg[1] != '-') { /* parse short options */ char opt; const char *val; for (j = 1; (opt = arg[j]); j++) { if (opt == 'h') { print_help(argv[0]); return 1; } if (opt == 'v') { print_version(); return 1; } if (opt == 'T') { show_time = 1; continue; } /* options requiring value */ if (arg[++j]) val = arg+j; else if (argv[++i]) val = argv[i]; else { fprintf(stderr, "Wrong option '-%c' found.\n", opt); return 1; } long int num; int isNum = parseint(val, &num); if (opt == 'n' && isNum) { max_nesting = num; break; } if (opt == 't' && isNum) { toc_level = num; break; } if (opt == 'i' && isNum) { iunit = num; break; } if (opt == 'o' && isNum) { ounit = num; break; } fprintf(stderr, "Wrong option '-%c' found.\n", opt); return 1; } continue; } if (!arg[2]) { /* arg is "--" */ just_args = 1; continue; } /* parse long option */ char opt [100]; strncpy(opt, arg+2, 100); opt[99] = 0; char *val = strchr(opt, '='); long int num = 0; int isNum = 0; if (val) { *val = 0; val++; if (*val) isNum = parseint(val, &num); } int opt_parsed = 0; if (strcmp(opt, "help")==0) { print_help(argv[0]); return 1; } if (strcmp(opt, "version")==0) { print_version(); return 1; } if (strcmp(opt, "max-nesting")==0 && isNum) { opt_parsed = 1; max_nesting = num; } if (strcmp(opt, "toc-level")==0 && isNum) { opt_parsed = 1; toc_level = num; } if (strcmp(opt, "input-unit")==0 && isNum) { opt_parsed = 1; iunit = num; } if (strcmp(opt, "output-unit")==0 && isNum) { opt_parsed = 1; ounit = num; } if (strcmp(opt, "html")==0) { opt_parsed = 1; renderer_type = RENDERER_HTML; } if (strcmp(opt, "html-toc")==0) { opt_parsed = 1; renderer_type = RENDERER_HTML_TOC; } if (strcmp(opt, "null")==0) { opt_parsed = 1; renderer_type = RENDERER_NULL; } const char *name; size_t i; /* extension categories */ if ((name = strprefix(opt, category_prefix))) { for (i = 0; i < count_of(categories_info); i++) { struct extension_category_info *category = categories_info+i; if (strcmp(name, category->option_name)==0) { opt_parsed = 1; extensions |= category->flags; break; } } } /* extensions */ for (i = 0; i < count_of(extensions_info); i++) { struct extension_info *extension = extensions_info+i; if (strcmp(opt, extension->option_name)==0) { opt_parsed = 1; extensions |= extension->flag; break; } } /* html flags */ for (i = 0; i < count_of(html_flags_info); i++) { struct html_flag_info *html_flag = html_flags_info+i; if (strcmp(opt, html_flag->option_name)==0) { opt_parsed = 1; html_flags |= html_flag->flag; break; } } /* negations */ if ((name = strprefix(opt, negative_prefix))) { for (i = 0; i < count_of(categories_info); i++) { struct extension_category_info *category = categories_info+i; if (strcmp(name, category->option_name)==0) { opt_parsed = 1; extensions &= ~(category->flags); break; } } for (i = 0; i < count_of(extensions_info); i++) { struct extension_info *extension = extensions_info+i; if (strcmp(name, extension->option_name)==0) { opt_parsed = 1; extensions &= ~(extension->flag); break; } } for (i = 0; i < count_of(html_flags_info); i++) { struct html_flag_info *html_flag = html_flags_info+i; if (strcmp(name, html_flag->option_name)==0) { opt_parsed = 1; html_flags &= ~(html_flag->flag); break; } } } if (strcmp(opt, "time")==0) { opt_parsed = 1; show_time = 1; } if (!opt_parsed) { fprintf(stderr, "Wrong option '%s' found.\n", arg); return 1; } } if (!in) in = stdin; /* reading everything */ ib = hoedown_buffer_new(iunit); while (!feof(in)) { if (ferror(in)) { fprintf(stderr, "I/O errors found while reading input.\n"); return 5; } hoedown_buffer_grow(ib, ib->size + iunit); ib->size += fread(ib->data + ib->size, 1, iunit, in); } if (in != stdin) fclose(in); /* creating the renderer */ hoedown_renderer *renderer = NULL; void (*renderer_free)(hoedown_renderer*) = NULL; switch (renderer_type) { case RENDERER_HTML: renderer = hoedown_html_renderer_new(html_flags, toc_level); renderer_free = hoedown_html_renderer_free; break; case RENDERER_HTML_TOC: renderer = hoedown_html_toc_renderer_new(toc_level); renderer_free = hoedown_html_renderer_free; break; case RENDERER_NULL: renderer = null_renderer_new(); renderer_free = null_renderer_free; break; }; /* performing markdown rendering */ ob = hoedown_buffer_new(ounit); document = hoedown_document_new(renderer, extensions, max_nesting); //clock_gettime(CLOCK_MONOTONIC, &start); hoedown_document_render(document, ob, ib->data, ib->size); //clock_gettime(CLOCK_MONOTONIC, &end); /* writing the result to stdout */ (void)fwrite(ob->data, 1, ob->size, stdout); /* showing rendering time */ if (show_time) { //TODO: enable this //long long elapsed = ( end.tv_sec*1000000000 + end.tv_nsec) // - (start.tv_sec*1000000000 + start.tv_nsec); //if (elapsed < 1000000000) // fprintf(stderr, "Time spent on rendering: %.2f ms.\n", ((double)elapsed)/1000000); //else // fprintf(stderr, "Time spent on rendering: %.3f s.\n", ((double)elapsed)/1000000000); } /* cleanup */ hoedown_buffer_free(ib); hoedown_buffer_free(ob); hoedown_document_free(document); renderer_free(renderer); if (ferror(stdout)) { fprintf(stderr, "I/O errors found while writing output.\n"); return 5; } return 0; }
QByteArray HoedownMarkdownConverterPrivate::markdown2Html(const QByteArray &markdownText) const { int markdownLength = markdownText.size(); if(markdownLength == 0) { return QByteArray(""); } hoedown_buffer *ib, *ob; hoedown_renderer *renderer = NULL; hoedown_document *document; // malloc ob = hoedown_buffer_new(markdownLength); ib = hoedown_buffer_new(markdownLength); renderer = hoedown_html_renderer_new(HOEDOWN_HTML_USE_XHTML, 0); /* typedef enum hoedown_extensions { // block-level extensions HOEDOWN_EXT_TABLES = (1 << 0), HOEDOWN_EXT_FENCED_CODE = (1 << 1), HOEDOWN_EXT_FOOTNOTES = (1 << 2), // span-level extensions HOEDOWN_EXT_AUTOLINK = (1 << 3), HOEDOWN_EXT_STRIKETHROUGH = (1 << 4), HOEDOWN_EXT_UNDERLINE = (1 << 5), HOEDOWN_EXT_HIGHLIGHT = (1 << 6), HOEDOWN_EXT_QUOTE = (1 << 7), HOEDOWN_EXT_SUPERSCRIPT = (1 << 8), HOEDOWN_EXT_MATH = (1 << 9), // other flags HOEDOWN_EXT_NO_INTRA_EMPHASIS = (1 << 11), HOEDOWN_EXT_SPACE_HEADERS = (1 << 12), HOEDOWN_EXT_MATH_EXPLICIT = (1 << 13), // negative flags HOEDOWN_EXT_DISABLE_INDENTED_CODE = (1 << 14) } hoedown_extensions; */ // 尽可能的指定 document = hoedown_document_new(renderer, HOEDOWN_EXT_TABLES, 16); // put data hoedown_buffer_put(ib, (const uint8_t *) markdownText.toStdString().c_str(), markdownText.size()); // render markdown to html hoedown_document_render(document, ob, ib->data, ib->size); QByteArray html((const char*)ob->data, ob->size); // free hoedown_buffer_free(ib); hoedown_document_free(document); hoedown_html_renderer_free(renderer); hoedown_buffer_free(ob); return html; }
/** * @brief Returns html rendered markdown of the note text * @param notesPath for transforming relative local urls to absolute ones * @param maxImageWidth defined maximum image width (ignored if forExport is true) * @param forExport defines whether the export or preview stylesheet * @return */ QString Note::toMarkdownHtml(QString notesPath, int maxImageWidth, bool forExport) { hoedown_renderer *renderer = hoedown_html_renderer_new(HOEDOWN_HTML_USE_XHTML, 16); hoedown_extensions extensions = (hoedown_extensions) (HOEDOWN_EXT_BLOCK | HOEDOWN_EXT_SPAN); hoedown_document *document = hoedown_document_new(renderer, extensions, 16); // get the decrypted note text (or the normal note text if there isn't any) QString str = getDecryptedNoteText(); QString windowsSlash = ""; #ifdef Q_OS_WIN32 // we need an other slash for Windows windowsSlash = "/"; #endif // parse for relative file urls and make them absolute // (for example to show images under the note path) str.replace( QRegularExpression("\\(file:\\/\\/([^\\/].+)\\)"), "(file://" + windowsSlash + notesPath + "/\\1)"); unsigned char *sequence = (unsigned char *) qstrdup( str.toUtf8().constData()); qint64 length = strlen((char *) sequence); // return an empty string if the note is empty if (length == 0) { return ""; } hoedown_buffer *html = hoedown_buffer_new(length); // render markdown html hoedown_document_render(document, html, sequence, length); // get markdown html QString result = QString::fromUtf8((char *) html->data, html->size); /* Cleanup */ free(sequence); hoedown_buffer_free(html); hoedown_document_free(document); hoedown_html_renderer_free(renderer); QSettings(settings); QString fontString = settings.value("MainWindow/noteTextView.code.font") .toString(); // set the stylesheet for the <code> blocks QString codeStyleSheet = ""; if (fontString != "") { // set the note text view font QFont font; font.fromString(fontString); // add the font for the code block codeStyleSheet = QString( "pre, code { %1; }").arg(encodeCssFont(font)); } bool darkModeColors = settings.value("darkModeColors").toBool(); QString codeBackgroundColor = darkModeColors ? "#444444" : "#f1f1f1"; // do some more code formatting codeStyleSheet += QString( "pre, code { padding: 16px; overflow: auto;" " line-height: 1.45em; background-color: %1;" " border-radius: 3px; }").arg(codeBackgroundColor); // remove double code blocks result.replace("<pre><code>", "<pre>") .replace("</code></pre>", "</pre>"); if (forExport) { // get defined body font from settings QString bodyfontString = settings.value("MainWindow/noteTextView.font") .toString(); // create export stylesheet QString exportStyleSheet = ""; if (bodyfontString != "") { QFont bodyFont; bodyFont.fromString(bodyfontString); exportStyleSheet = QString( "body { %1; }").arg(encodeCssFont(bodyFont)); } result = QString("<html><head><meta charset=\"utf-8\"/><style>" "h1 { margin: 5px 0 20px 0; }" "h2, h3 { margin: 10px 0 15px 0; }" "img { max-width: 100%; }" "a { color: #FF9137; text-decoration: none; } %1 %2" "</style></head><body>%3</body></html>") .arg(codeStyleSheet, exportStyleSheet, result); } else { // for preview result = QString("<html><head><style>" "h1 { margin: 5px 0 20px 0; }" "h2, h3 { margin: 10px 0 15px 0; }" "a { color: #FF9137; text-decoration: none; } %1" "</style></head><body>%2</body></html>") .arg(codeStyleSheet, result); } // check if width of embedded local images is too high QRegularExpression re("<img src=\"file:\\/\\/([^\"]+)\""); QRegularExpressionMatchIterator i = re.globalMatch(result); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); QString fileName = match.captured(1); #ifdef Q_OS_WIN // remove the leading slash under Windows to get a more correct filename QImage image(Utils::Misc::removeIfStartsWith(fileName, "/")); #else QImage image(fileName); #endif if (forExport) { result.replace( QRegularExpression("<img src=\"file:\\/\\/" + QRegularExpression::escape(fileName) + "\""), QString("<img src=\"file://%2\"").arg(fileName)); } else { // for preview // cap the image width at 980px or the note text view width if (image.width() > maxImageWidth) { result.replace( QRegularExpression("<img src=\"file:\\/\\/" + QRegularExpression::escape(fileName) + "\""), QString("<img width=\"%1\" src=\"file://%2\"").arg( QString::number(maxImageWidth), fileName)); } } } // check if there is a script that wants to modify the content QString scriptResult = ScriptingService::instance() ->callNoteToMarkdownHtmlHook(this, result); if (!scriptResult.isEmpty()) { result = scriptResult; } return result; }
/** * @brief Returns html rendered markdown of the note text * @param notesPath for transforming relative local urls to absolute ones * @return */ QString Note::toMarkdownHtml(QString notesPath) { hoedown_renderer *renderer = hoedown_html_renderer_new(HOEDOWN_HTML_USE_XHTML, 16); hoedown_extensions extensions = (hoedown_extensions) (HOEDOWN_EXT_BLOCK | HOEDOWN_EXT_SPAN); hoedown_document *document = hoedown_document_new(renderer, extensions, 16); // get the decrypted note text (or the normal note text if there isn't any) QString str = getDecryptedNoteText(); QString windowsSlash = ""; #ifdef Q_OS_WIN32 // we need an other slash for Windows windowsSlash = "/"; #endif // parse for relative file urls and make them absolute // (for example to show images under the note path) str.replace( QRegularExpression("\\(file:\\/\\/([^\\/].+)\\)"), "(file://" + windowsSlash + notesPath + "/\\1)"); unsigned char *sequence = (unsigned char *) qstrdup( str.toUtf8().constData()); qint64 length = strlen((char *) sequence); // return an empty string if the note is empty if (length == 0) { return ""; } hoedown_buffer *html = hoedown_buffer_new(length); // render markdown html hoedown_document_render(document, html, sequence, length); // get markdown html QString result = QString::fromUtf8((char *) html->data, html->size); /* Cleanup */ free(sequence); hoedown_buffer_free(html); hoedown_document_free(document); hoedown_html_renderer_free(renderer); QSettings(settings); QString fontString = settings.value("MainWindow/noteTextView.code.font") .toString(); // set the stylesheet for the <code> blocks QString codeStyleSheet = ""; if (fontString != "") { // set the note text view font QFont font; font.fromString(fontString); codeStyleSheet = "pre, code {" + encodeCssFont(font) + "}"; } result = "<html><head>" "<style>h1, h2, h3 { margin: 5pt 0 10pt 0; }" "a { color: #FF9137; text-decoration: none; }" + codeStyleSheet + "</style></head><body>" + result + "</body></html>"; // check if width of embedded local images is too high QRegularExpression re("<img src=\"file:\\/\\/([^\"]+)\""); QRegularExpressionMatchIterator i = re.globalMatch(result); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); QString fileName = match.captured(1); QImage image(fileName); // cap the image width at 980px if (image.width() > 980) { result.replace( QRegularExpression("<img src=\"file:\\/\\/" + QRegularExpression::escape(fileName) + "\""), "<img width=\"980\" src=\"file://" + fileName + "\""); } } return result; }
/** * @brief Returns html rendered markdown of the note text * @param notesPath for transforming relative local urls to absolute ones * @return */ QString Note::toMarkdownHtml(QString notesPath) { hoedown_renderer *renderer = hoedown_html_renderer_new(HOEDOWN_HTML_USE_XHTML, 16); hoedown_extensions extensions = (hoedown_extensions) (HOEDOWN_EXT_BLOCK | HOEDOWN_EXT_SPAN); hoedown_document *document = hoedown_document_new(renderer, extensions, 16); // get the decrypted note text (or the normal note text if there isn't any) QString str = getDecryptedNoteText(); // parse for relative file urls and make them absolute // (for example to show images under the note path) str.replace( QRegularExpression("\\(file:\\/\\/([^\\/].+)\\)"), "(file://" + notesPath + "/\\1)"); unsigned char *sequence = (unsigned char *) qstrdup(str.toUtf8().constData()); int length = strlen((char *) sequence); // return an empty string if the note is empty if (length == 0) { return ""; } hoedown_buffer *html = hoedown_buffer_new(length); // render markdown html hoedown_document_render(document, html, sequence, length); // get markdown html QString result = QString::fromUtf8((char *) html->data, html->size); /* Cleanup */ free(sequence); hoedown_buffer_free(html); hoedown_document_free(document); hoedown_html_renderer_free(renderer); result = "<html><head><style>h1, h2, h3 { margin: 5pt 0 10pt 0; }" "a { color: #FF9137; text-decoration: none; }</style></head><body>" + result + "</body></html>"; // check if width of embedded local images is too high QRegularExpression re("<img src=\"file:\\/\\/([^\"]+)\""); QRegularExpressionMatchIterator i = re.globalMatch(result); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); QString fileName = match.captured(1); QImage image(fileName); // cap the image width at 980px if (image.width() > 980) { result.replace( QRegularExpression("<img src=\"file:\\/\\/" + QRegularExpression::escape(fileName) + "\""), "<img width=\"980\" src=\"file://" + fileName + "\""); } } return result; }
int main(int argc, char **argv) { struct option_data data; clock_t t1, t2; FILE *file = stdin; hoedown_buffer *ib, *ob, *meta; hoedown_renderer *renderer = NULL; void (*renderer_free)(hoedown_renderer *) = NULL; hoedown_document *document; /* Parse options */ data.basename = argv[0]; data.done = 0; data.show_time = 0; data.iunit = DEF_IUNIT; data.ounit = DEF_OUNIT; data.filename = NULL; data.renderer = RENDERER_HTML; data.toc_level = 0; data.html_flags = 0; data.extensions = 0; data.max_nesting = DEF_MAX_NESTING; data.link_attributes = 0; argc = parse_options(argc, argv, parse_short_option, parse_long_option, parse_argument, &data); if (data.done) return 0; if (!argc) return 1; /* Add extesion flags, case html_flags */ if (data.html_flags & HOEDOWN_HTML_FENCED_CODE_SCRIPT) { data.extensions |= HOEDOWN_EXT_FENCED_CODE; } /* Open input file, if needed */ if (data.filename) { file = fopen(data.filename, "r"); if (!file) { fprintf(stderr, "Unable to open input file \"%s\": %s\n", data.filename, strerror(errno)); return 5; } } /* Read everything */ ib = hoedown_buffer_new(data.iunit); if (hoedown_buffer_putf(ib, file)) { fprintf(stderr, "I/O errors found while reading input.\n"); return 5; } if (file != stdin) fclose(file); /* Create the renderer */ switch (data.renderer) { case RENDERER_HTML: renderer = hoedown_html_renderer_new(data.html_flags, data.toc_level); renderer_free = hoedown_html_renderer_free; break; case RENDERER_HTML_TOC: renderer = hoedown_html_toc_renderer_new(data.toc_level); renderer_free = hoedown_html_renderer_free; break; case RENDERER_CONTEXT_TEST: renderer = hoedown_context_test_renderer_new(); renderer_free = hoedown_context_test_renderer_free; break; }; /* Perform Markdown rendering */ ob = hoedown_buffer_new(data.ounit); meta = hoedown_buffer_new(data.ounit); document = hoedown_document_new(renderer, data.extensions, data.max_nesting, NULL, meta); /* state */ if (data.renderer == RENDERER_CONTEXT_TEST) { hoedown_context_test_renderer_state *state; state = (hoedown_context_test_renderer_state *)renderer->opaque; state->doc = document; } else { hoedown_html_renderer_state *state; state = (hoedown_html_renderer_state *)renderer->opaque; /* toc_data */ if (data.toc_level > 0) { state->toc_data.current_level = 0; state->toc_data.level_offset = 0; state->toc_data.nesting_level = data.toc_level; state->toc_data.header = "<div class=\"toc\">"; state->toc_data.footer = "</div>"; } /* link_attributes */ if (data.link_attributes) { state->link_attributes = rndr_test_link_attributes; } } t1 = clock(); hoedown_document_render(document, ob, ib->data, ib->size); t2 = clock(); /* Cleanup */ hoedown_buffer_free(ib); hoedown_document_free(document); renderer_free(renderer); /* Write the result to stdout */ (void)fwrite(ob->data, 1, ob->size, stdout); hoedown_buffer_free(ob); if (ferror(stdout)) { hoedown_buffer_free(meta); fprintf(stderr, "I/O errors found while writing output.\n"); return 5; } /* Meta block */ if (meta->size > 0) { fprintf(stdout, "-- Meta Block --\n"); (void)fwrite(meta->data, 1, meta->size, stdout); } hoedown_buffer_free(meta); if (ferror(stdout)) { fprintf(stderr, "I/O errors found while writing output.\n"); return 5; } /* Show rendering time */ if (data.show_time) { double elapsed; if (t1 == ((clock_t) -1) || t2 == ((clock_t) -1)) { fprintf(stderr, "Failed to get the time.\n"); return 1; } elapsed = (double)(t2 - t1) / CLOCKS_PER_SEC; if (elapsed < 1) fprintf(stderr, "Time spent on rendering: %7.2f ms.\n", elapsed*1e3); else fprintf(stderr, "Time spent on rendering: %6.3f s.\n", elapsed); } return 0; }