% 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 `
` and `
` tags (nowadays I generate a [css]-styled `

` block, because that's xhtml compatible instead of the now-depreciated `

` block element.) I've added support for specifying image sizes, and I've written a not-earthshatteringly-horrible markup extension for definition lists. Paragraph centering : To center a paragraph, frame it with `->` and `<-`. > > ->this is a test<- >produces > >->this is a test<- Specifying image sizes : An image size is defined by adding an additional `=`*width*`x`*height* field to the image tag: > > ![dust mite](http://dust.mite =150x150) >produces >![dust mite](http://dust.mite =150x150) [Definition lists](id:dl) : To mark up a definition list, left-justify the label and frame it with `=` characters, then put the body of the list item on the next line, indented 4 spaces. > > =hey!= > This is a definition list > produces > >``` >
hey!
>
This is a definition list
>``` A definition list label is just a regular line of markdown code, so you can put links and images into it. In [discount 1.2.3](older.html#1.2.3), the definition list syntax has been extended so that you can define sequential `
` blocks by doing =tag1= =tag2= data. which generates
tag1
tag2
data.
(If you want a definition list with a trailing empty tag, give it a body that's just a html comment, like: > > =placeholder!= > > produces > >``` >
placeholder!
>
>``` In [discount 2.0.4](#v2.0.4) I extended the definition list syntax to allow [php markdown extra] [definition lists][markdown extra definition list] which means that source like tag1 : data now generates
tag1
data
[alpha lists](id:alphalist) : Ordered lists with alphabetic labels (enabled by `--enable-alpha-list` during configuration) are supported in the same way that numeric ordered lists are: a. first item b. second item generates a. first item b. second item [New pseudo-protocols for [] links](id:pseudo) : I wanted to be able to apply styles inline without having to manually enter the ``...`` html. So I redid the `[][]` code to support some new "protocols" within my markdown: `abbr:`_description_ : The label will be wrapped by ``...`` `class:`_name_ : The label will be wrapped by ``...`` `id:`_name_ : The label will be wrapped by ``...`` `raw:`_text_ : _Text_ will be written verbatim to the output. The protocol was inspired by a short thread on the markdown mailing list about someone wanting to embed LaTeX inside `` and finding, to their distress, that markdown mangled it. Passing text through in comments seems to be a path to unreadable madness, so I didn't want to do that. This is, to my mind, a better solution. [Style blocks](id:styleblock) : accept `` blocks and set them aside for printing via `mkd_style()`. [Class blocks](id:classblock) : A blockquote with a first line of `> %class%` will become `
` instead of a `
`. [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