% Discount -- a C implementation of the Markdown markup language % Jessica L. Parsons (orc@pell.portland.or.us) % #Discount >%class:tincup% >Discount is free software released under the terms of a >[BSD-style](COPYRIGHT.html) license. > >If you find it useful, please consider >making a contribution to help support onward development. > >[donate?](https://www.paypal.com/donate/?hosted_button_id=E9G5WQXEFNA8U) > ##download [Discount 3.0.1.2](discount-3.0.1.2.tar.bz2), released 8-Sep-2025 ##description This is my implementation of [John Gruber][]'s [Markdown][] text to html language. There's not much here that differentiates it from any of the existing Markdown implementations except that it's written in C instead of one of the vast flock of scripting languages that are fighting it out for the Perl crown. **Markdown** provides a library that gives you formatting functions suitable for marking down entire documents or lines of text, a [command-line program] that you can use to mark down documents interactively or from a script, and a tiny (3 programs so far) [suite of example programs] that show how to fully utilize the markdown library. My markdown also does, by default, various [smartypants][]-style substitutions. The API is not too horrifically unsimple, and is described on the [API] page. I have tried to keep all of the versions of discount available on the [downloads] page. ###[Language bindings](id:bindings) I have an experimental C++ binding that lives on [Github](https://www.github.com) in [mkdio.h++](https://gist.github.com/Orc/97b5711dd8c8a3b371928db756eba6e5 "a 'gist', whatever that is"). It implements a couple of RAII objects; `MKIOT` -- can't call the class `MMIOT` because it clashes with the C `MMIOT` it wraps -- for [standard markdown][markdown] (plus my extensions, of course) and `GFIOT` for github-flavo(u)red markdown. Alas, it is undocumented, but the `mkdio.h++` header file is pretty simple and a trivial program that uses it is included in the `mkdio.h++` sccs tree. ###[Smartypants substitutions](id:smartypants) 1. \`\` `text` '' is translated to ``text''. 5. `"double-quoted text"` becomes "double-quoted text" 6. `'single-quoted text'` becomes 'single-quoted text' 7. `don't` is "don't." as well as anything-else't. (But `foo'tbar` is just foo'tbar.) 8. And `it's` is "it's," as well as anything-else's (except not foo'sbar and the like.) 2. `(tm)` becomes (tm) 3. `(r)` becomes (r) 4. `(c)` becomes (c) 9. `1/4th` ? 1/4th. Ditto for `1/4` (1/4), `1/2` (1/2), `3/4ths` (3/4ths), and `3/4` (3/4). 10. `...` becomes ... 10. `. . .` also becomes . . . 11. `---` becomes --- 12. `--` becomes -- 13. [`A^B`](id:superscript) becomes A^B. Complex superscripts can be enclosed in `()`s, so `A^(B+2)` becomes A^(B+2). ###Language extensions My [markdown][] was written so I could replace the fairly gross homemade text to html prettifier that I wrote for [annotations][], so I've extended it in a few ways; I've put support for paragraph centering in so that I don't have to hand enter the `
` block, because that's xhtml compatible instead of the now-depreciated `
`. [Tables](id:tables) : [PHP Markdown Extra]-style tables are supported; aaa | bbbb -----|------ hello|sailor becomes the following table: aaa | bbbb -----|------ hello|sailor And much of the rest of the current table syntax (alignment, handling of orphan columns) follows the [PHP Markdown Extra] spec. [Document Headers](id:headers) : [Pandoc]-style document headers are supported; if the first three lines in the document begin with a `%` character, they are taken to be a document header in the form of % Document title % Document author % Document date and can be retrieved by the [library functions](id:document_header) `mkd_doc_title()`, `mkd_doc_author()`, and `mkd_doc_date()`. Note that I implement Pandoc document headers as they were documented in 2008; any Pandoc changes since then will not be reflected in my implementation. [Fenced code blocks](id:fencedcodeblocks) : If called with the `MKD_FENCEDCODE` option, [Pandoc]-style fenced code blocks are supported; blocks of code wrapped in `~~~` lines are treated as code just as if it was indented the traditional 4 spaces. Github-flavored-markdown fenced code blocks (blocks wrapped in backtick lines) are also supported. Both of these formats support the github-flavored-markdown class extension where you can put a word at the end of the opening backtick line and have the block given that class. [Embedded LaTeX (mathjax)](id:latex) : If called with the `MKD_LATEX` option, text wrapped in `$$`...`$$`, `\[`...`\]`, and `\(`...`\)` is passed unchanged (except for encoding `<`, `>`, and `&`) to the output for processing by a LaTeX renderer. This collides with how Markdown escapes '[', ']', '(', and ')' -- if discount is called with `MKD_LATEX`, `\(` and `\[` will only map to `(` and `[` if corresponding `\)` or `\]`s are **not** found in the same paragraph. [Github checkbox list items](id:checkbox) : If configured with the `--github-checkbox` flag, discount will understand [github-style checkboxes](https://github.github.com/gfm/#task-list-items-extension-) and generate checkboxes using either html entities (`--github-checkbox` w/o an argument) or `` elements (`--github-checkbox=input`) ###How standard is it? When I run the [standard test suite (version 1.0.3)][test suite] from daringfireball, `MarkdownTest.pl` reports: > $ MARKDOWN_FLAGS=0x20004 ./MarkdownTest.pl --tidy --script=/usr/local/bin/markdown > Amps and angle encoding ... OK > Auto links ... OK > Backslash escapes ... OK > Blockquotes with code blocks ... OK > Code Blocks ... OK > Code Spans ... OK > Hard-wrapped paragraphs with list-like lines ... OK > Horizontal rules ... OK > Inline HTML (Advanced) ... OK > Inline HTML (Simple) ... OK > Inline HTML comments ... OK > Links, inline style ... OK > Links, reference style ... OK > Links, shortcut references ... OK > Literal quotes in titles ... OK > Markdown Documentation - Basics ... OK > Markdown Documentation - Syntax ... OK > Nested blockquotes ... OK > Ordered and unordered lists ... OK > Strong and em together ... OK > Tabs ... OK > Tidyness ... OK > > > 22 passed; 0 failed. When I run the [old standard test suite][old test suite] from daringfireball, `MarkdownTest.pl` reports: > $ MARKDOWN_FLAGS=0x22004 ./MarkdownTest.pl --tidy --script=/usr/local/bin/markdown > Amps and angle encoding ... OK > Auto links ... OK > Backslash escapes ... OK > Blockquotes with code blocks ... OK > Hard-wrapped paragraphs with list-like lines ... OK > Horizontal rules ... OK > Inline HTML (Advanced) ... OK > Inline HTML (Simple) ... OK > Inline HTML comments ... OK > Links, inline style ... OK > Links, reference style ... OK > Literal quotes in titles ... OK > Markdown Documentation - Basics ... OK > Markdown Documentation - Syntax ... OK > Nested blockquotes ... OK > Ordered and unordered lists ... OK > Strong and em together ... OK > Tabs ... OK > Tidyness ... OK > > > 19 passed; 0 failed. Most of the "how to get standards compliant" changes that went in were cleaning up corner cases and blatant misreading of the spec, but there were two places where I had to do a horrible hack to get compliant: 1. To pass the **Hard-wrapped paragraphs with list-like lines** test, I had to modify `mkd_compile()` so that it would have top-level paragraphs absorb adjacent list items, but I had to retain the old (and, IMO, _correct_) behavior of a new list forcing a block break within indented (quoted, inside lists) blocks.. 2. To pass the **Markdown Documentation - Syntax** test in MarkdownTest 1.0, I had to change the behavior of code blocks from "preserve trailing whitespace" to "preserve trailing whitespace *unless* it's the first line in the block." From version 1.3.3 on, this is no longer the default, but the flag `MKD_1_COMPAT` (0x2000) turns it on again for testing purposes. ###Does this markdown treat tabs as 4 spaces? By default, yes, it does. The habit of compensating for broken editors that give no way to indent except for tabbing by setting tabstops to 4 is so intertwined with this language that treating tabs properly would be the moral equivalent of dropping nuclear devices into the testsuite. But if you use a proper tabstop (8 characters), you can configure markdown with **`--with-tabstop`** and it will expand tabs to 8 spaces. If you've configured your markdown like this (`markdown -V` will report **`TAB=`**8) and you need to mark up text from other sources, you can set the input flag **`MKD_TABSTOP`** to revert those documents back to the icky standard 4-space tab. ##Trivia 1. This document is [generated from markdown source](index.text). 2. I've got a public mirror of my sccs repository on [github](http://github.com/Orc/discount). [markdown]: http://daringfireball.net/projects/markdown [syntax]: http://daringfireball.net/projects/markdown/syntax [john gruber]: http://daringfireball.net [annotations]: /~orc/Code/annotations [smartypants]: http://daringfireball.net/projects/smartypants/ [test suite]: http://six.pairlist.net/pipermail/markdown-discuss/2006-June/000079.html [old test suite]: http://six.pairlist.net/pipermail/markdown-discuss/2004-December/000909.html [textmate]: http://macromates.com/ [pandoc]: http://johnmacfarlane.net/pandoc/ [vi]: http://thomer.com/vi/vi.html [Ryan Tomakyo]: http://tomayko.com/ [rdiscount]: http://tomayko.com/writings/ruby-markdown-libraries-real-cheap-for-you-two-for-price-of-one [reference dingus]: http://daringfireball.net/projects/markdown/dingus [plan9]: http://plan9.bell-labs.com/plan9/ [PHP markdown extra]: http://michelf.com/projects/php-markdown/extra/ [markdown extra definition list]: http://michelf.com/projects/php-markdown/extra/#def-list [footnotes]: http://michelf.com/projects/php-markdown/extra/#footnotes [Mike Schiraldi]: http://mikeschiraldi.blogspot.com/ [github]: http://github.com/Orc/discount [discount]: /~orc/Code/discount [css]: http://www.w3.org/Style/CSS/ 'See this page? This is how NOT to do styles' [command-line program]: program.html [API]: api.html [downloads]: downloads.html [suite of example programs]: samples.html