├── test ├── Tests │ ├── Underline.text │ ├── Underline.html │ ├── Formatting in Table of Contents.text │ ├── Formatting in Table of Contents.html │ ├── Table.text │ ├── Math.text │ ├── Escape character.text │ ├── Math.html │ ├── Escape character.html │ └── Table.html ├── MarkdownTest_1.0.3 │ ├── Tests │ │ ├── Nested blockquotes.text │ │ ├── Tidyness.text │ │ ├── Strong and em together.text │ │ ├── Literal quotes in titles.text │ │ ├── Nested blockquotes.html │ │ ├── Tidyness.html │ │ ├── Code Spans.text │ │ ├── Literal quotes in titles.html │ │ ├── Blockquotes with code blocks.text │ │ ├── Inline HTML (Advanced).text │ │ ├── Inline HTML comments.text │ │ ├── Code Spans.html │ │ ├── Inline HTML (Advanced).html │ │ ├── Strong and em together.html │ │ ├── Hard-wrapped paragraphs with list-like lines.text │ │ ├── Code Blocks.text │ │ ├── Inline HTML comments.html │ │ ├── Hard-wrapped paragraphs with list-like lines.html │ │ ├── Blockquotes with code blocks.html │ │ ├── Links, inline style.text │ │ ├── Links, shortcut references.html │ │ ├── Auto links.text │ │ ├── Links, shortcut references.text │ │ ├── Code Blocks.html │ │ ├── Tabs.text │ │ ├── Links, inline style.html │ │ ├── Amps and angle encoding.text │ │ ├── Tabs.html │ │ ├── Amps and angle encoding.html │ │ ├── Horizontal rules.text │ │ ├── Auto links.html │ │ ├── Horizontal rules.html │ │ ├── Inline HTML (Simple).text │ │ ├── Inline HTML (Simple).html │ │ ├── Links, reference style.text │ │ ├── Links, reference style.html │ │ ├── Ordered and unordered lists.text │ │ ├── Backslash escapes.text │ │ ├── Backslash escapes.html │ │ ├── Ordered and unordered lists.html │ │ ├── Markdown Documentation - Basics.text │ │ ├── Markdown Documentation - Basics.html │ │ └── Markdown Documentation - Syntax.text │ └── MarkdownTest.pl ├── runner.py └── config.json ├── .gitignore ├── .travis.yml ├── src ├── version.c ├── escape.h ├── version.h ├── stack.h ├── autolink.h ├── stack.c ├── html.h ├── buffer.h ├── escape.c ├── autolink.c ├── buffer.c ├── document.h ├── html_blocks.c ├── html_smartypants.c └── html.c ├── html_block_names.gperf ├── .editorconfig ├── LICENSE ├── hoedown.def ├── Makefile.win ├── Makefile ├── bin ├── common.h ├── smartypants.c └── hoedown.c └── README.md /test/Tests/Underline.text: -------------------------------------------------------------------------------- 1 | This _underline_ will work. 2 | -------------------------------------------------------------------------------- /test/Tests/Underline.html: -------------------------------------------------------------------------------- 1 |

This underline will work.

2 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Nested blockquotes.text: -------------------------------------------------------------------------------- 1 | > foo 2 | > 3 | > > bar 4 | > 5 | > foo 6 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Tidyness.text: -------------------------------------------------------------------------------- 1 | > A list within a blockquote: 2 | > 3 | > * asterisk 1 4 | > * asterisk 2 5 | > * asterisk 3 6 | -------------------------------------------------------------------------------- /test/Tests/Formatting in Table of Contents.text: -------------------------------------------------------------------------------- 1 | # Header with special & characters 2 | 3 | ## With `Code` 4 | 5 | ### With *Emphasis* 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.obj 3 | *.exe 4 | hoedown 5 | hoedown.dll 6 | hoedown.exp 7 | hoedown.lib 8 | smartypants 9 | libhoedown.so* 10 | libhoedown.a 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | compiler: 3 | - clang 4 | - gcc 5 | perl: 6 | - "5.12" 7 | before_install: 8 | - sudo apt-get install -qq tidy 9 | script: make test 10 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Strong and em together.text: -------------------------------------------------------------------------------- 1 | ***This is strong and em.*** 2 | 3 | So is ***this*** word. 4 | 5 | ___This is strong and em.___ 6 | 7 | So is ___this___ word. 8 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Literal quotes in titles.text: -------------------------------------------------------------------------------- 1 | Foo [bar][]. 2 | 3 | Foo [bar](/url/ "Title with "quotes" inside"). 4 | 5 | 6 | [bar]: /url/ "Title with "quotes" inside" 7 | 8 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Nested blockquotes.html: -------------------------------------------------------------------------------- 1 |
2 |

foo

3 | 4 |
5 |

bar

6 |
7 | 8 |

foo

9 |
10 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Tidyness.html: -------------------------------------------------------------------------------- 1 |
2 |

A list within a blockquote:

3 | 8 |
9 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Code Spans.text: -------------------------------------------------------------------------------- 1 | `` 2 | 3 | Fix for backticks within HTML tag: like this 4 | 5 | Here's how you put `` `backticks` `` in a code span. 6 | 7 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Literal quotes in titles.html: -------------------------------------------------------------------------------- 1 |

Foo bar.

2 | 3 |

Foo bar.

4 | -------------------------------------------------------------------------------- /src/version.c: -------------------------------------------------------------------------------- 1 | #include "version.h" 2 | 3 | void 4 | hoedown_version(int *major, int *minor, int *revision) 5 | { 6 | *major = HOEDOWN_VERSION_MAJOR; 7 | *minor = HOEDOWN_VERSION_MINOR; 8 | *revision = HOEDOWN_VERSION_REVISION; 9 | } 10 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.text: -------------------------------------------------------------------------------- 1 | > Example: 2 | > 3 | > sub status { 4 | > print "working"; 5 | > } 6 | > 7 | > Or: 8 | > 9 | > sub status { 10 | > return "working"; 11 | > } 12 | -------------------------------------------------------------------------------- /html_block_names.gperf: -------------------------------------------------------------------------------- 1 | p 2 | dl 3 | h1 4 | h2 5 | h3 6 | h4 7 | h5 8 | h6 9 | ol 10 | ul 11 | del 12 | div 13 | ins 14 | pre 15 | form 16 | math 17 | style 18 | table 19 | figure 20 | iframe 21 | script 22 | fieldset 23 | noscript 24 | blockquote 25 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).text: -------------------------------------------------------------------------------- 1 | Simple block on one line: 2 | 3 |
foo
4 | 5 | And nested without indentation: 6 | 7 |
8 |
9 |
10 | foo 11 |
12 |
13 |
14 |
bar
15 |
16 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Inline HTML comments.text: -------------------------------------------------------------------------------- 1 | Paragraph one. 2 | 3 | 4 | 5 | 8 | 9 | Paragraph two. 10 | 11 | 12 | 13 | The end. 14 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Code Spans.html: -------------------------------------------------------------------------------- 1 |

<test a=" content of attribute ">

2 | 3 |

Fix for backticks within HTML tag: like this

4 | 5 |

Here's how you put `backticks` in a code span.

6 | 7 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).html: -------------------------------------------------------------------------------- 1 |

Simple block on one line:

2 | 3 |
foo
4 | 5 |

And nested without indentation:

6 | 7 |
8 |
9 |
10 | foo 11 |
12 |
13 |
14 |
bar
15 |
16 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Strong and em together.html: -------------------------------------------------------------------------------- 1 |

This is strong and em.

2 | 3 |

So is this word.

4 | 5 |

This is strong and em.

6 | 7 |

So is this word.

8 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.text: -------------------------------------------------------------------------------- 1 | In Markdown 1.0.0 and earlier. Version 2 | 8. This line turns into a list item. 3 | Because a hard-wrapped line in the 4 | middle of a paragraph looked like a 5 | list item. 6 | 7 | Here's one with a bullet. 8 | * criminey. 9 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Code Blocks.text: -------------------------------------------------------------------------------- 1 | code block on the first line 2 | 3 | Regular text. 4 | 5 | code block indented by spaces 6 | 7 | Regular text. 8 | 9 | the lines in this block 10 | all contain trailing spaces 11 | 12 | Regular Text. 13 | 14 | code block on the last line -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Inline HTML comments.html: -------------------------------------------------------------------------------- 1 |

Paragraph one.

2 | 3 | 4 | 5 | 8 | 9 |

Paragraph two.

10 | 11 | 12 | 13 |

The end.

14 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.html: -------------------------------------------------------------------------------- 1 |

In Markdown 1.0.0 and earlier. Version 2 | 8. This line turns into a list item. 3 | Because a hard-wrapped line in the 4 | middle of a paragraph looked like a 5 | list item.

6 | 7 |

Here's one with a bullet. 8 | * criminey.

9 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.html: -------------------------------------------------------------------------------- 1 |
2 |

Example:

3 | 4 |
sub status {
 5 |     print "working";
 6 | }
 7 | 
8 | 9 |

Or:

10 | 11 |
sub status {
12 |     return "working";
13 | }
14 | 
15 |
16 | -------------------------------------------------------------------------------- /test/Tests/Formatting in Table of Contents.html: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Links, inline style.text: -------------------------------------------------------------------------------- 1 | Just a [URL](/url/). 2 | 3 | [URL and title](/url/ "title"). 4 | 5 | [URL and title](/url/ "title preceded by two spaces"). 6 | 7 | [URL and title](/url/ "title preceded by a tab"). 8 | 9 | [URL and title](/url/ "title has spaces afterward" ). 10 | 11 | 12 | [Empty](). 13 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Links, shortcut references.html: -------------------------------------------------------------------------------- 1 |

This is the simple case.

2 | 3 |

This one has a line 4 | break.

5 | 6 |

This one has a line 7 | break with a line-ending space.

8 | 9 |

this and the other

10 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Auto links.text: -------------------------------------------------------------------------------- 1 | Link: . 2 | 3 | With an ampersand: 4 | 5 | * In a list? 6 | * 7 | * It should. 8 | 9 | > Blockquoted: 10 | 11 | Auto-links should not occur here: `` 12 | 13 | or here: -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Links, shortcut references.text: -------------------------------------------------------------------------------- 1 | This is the [simple case]. 2 | 3 | [simple case]: /simple 4 | 5 | 6 | 7 | This one has a [line 8 | break]. 9 | 10 | This one has a [line 11 | break] with a line-ending space. 12 | 13 | [line break]: /foo 14 | 15 | 16 | [this] [that] and the [other] 17 | 18 | [this]: /this 19 | [that]: /that 20 | [other]: /other 21 | -------------------------------------------------------------------------------- /test/Tests/Table.text: -------------------------------------------------------------------------------- 1 | # Standard table 2 | 3 | |headline1|headline2| 4 | |---------|---------| 5 | |123 | | 6 | 7 | 8 | # Cell alignment 9 | 10 | |headline1|headline2|headline3| 11 | |:-------|:------:|------:| 12 | |123||| 13 | 14 | 15 | # Malformed table: missing cell at row in body 16 | 17 | |headline1|headline2|headline3| 18 | |-------|-------|-------| 19 | |12 20 | |34|| 21 | |56| 22 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # Tab indentation (no size specified) 12 | [*.{c,h}] 13 | indent_style = tab 14 | 15 | # 4 space indentation 16 | [*.md] 17 | indent_style = space 18 | indent_size = 4 19 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Code Blocks.html: -------------------------------------------------------------------------------- 1 |
code block on the first line
 2 | 
3 | 4 |

Regular text.

5 | 6 |
code block indented by spaces
 7 | 
8 | 9 |

Regular text.

10 | 11 |
the lines in this block  
12 | all contain trailing spaces  
13 | 
14 | 15 |

Regular Text.

16 | 17 |
code block on the last line
18 | 
19 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Tabs.text: -------------------------------------------------------------------------------- 1 | + this is a list item 2 | indented with tabs 3 | 4 | + this is a list item 5 | indented with spaces 6 | 7 | Code: 8 | 9 | this code block is indented by one tab 10 | 11 | And: 12 | 13 | this code block is indented by two tabs 14 | 15 | And: 16 | 17 | + this is an example list item 18 | indented with tabs 19 | 20 | + this is an example list item 21 | indented with spaces 22 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Links, inline style.html: -------------------------------------------------------------------------------- 1 |

Just a URL.

2 | 3 |

URL and title.

4 | 5 |

URL and title.

6 | 7 |

URL and title.

8 | 9 |

URL and title.

10 | 11 |

Empty.

12 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Amps and angle encoding.text: -------------------------------------------------------------------------------- 1 | AT&T has an ampersand in their name. 2 | 3 | AT&T is another way to write it. 4 | 5 | This & that. 6 | 7 | 4 < 5. 8 | 9 | 6 > 5. 10 | 11 | Here's a [link] [1] with an ampersand in the URL. 12 | 13 | Here's a link with an amersand in the link text: [AT&T] [2]. 14 | 15 | Here's an inline [link](/script?foo=1&bar=2). 16 | 17 | Here's an inline [link](). 18 | 19 | 20 | [1]: http://example.com/?foo=1&bar=2 21 | [2]: http://att.com/ "AT&T" -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Tabs.html: -------------------------------------------------------------------------------- 1 |
    2 |
  • this is a list item 3 | indented with tabs

  • 4 |
  • this is a list item 5 | indented with spaces

  • 6 |
7 | 8 |

Code:

9 | 10 |
this code block is indented by one tab
11 | 
12 | 13 |

And:

14 | 15 |
    this code block is indented by two tabs
16 | 
17 | 18 |

And:

19 | 20 |
+   this is an example list item
21 |     indented with tabs
22 | 
23 | +   this is an example list item
24 |     indented with spaces
25 | 
26 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Amps and angle encoding.html: -------------------------------------------------------------------------------- 1 |

AT&T has an ampersand in their name.

2 | 3 |

AT&T is another way to write it.

4 | 5 |

This & that.

6 | 7 |

4 < 5.

8 | 9 |

6 > 5.

10 | 11 |

Here's a link with an ampersand in the URL.

12 | 13 |

Here's a link with an amersand in the link text: AT&T.

14 | 15 |

Here's an inline link.

16 | 17 |

Here's an inline link.

18 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Horizontal rules.text: -------------------------------------------------------------------------------- 1 | Dashes: 2 | 3 | --- 4 | 5 | --- 6 | 7 | --- 8 | 9 | --- 10 | 11 | --- 12 | 13 | - - - 14 | 15 | - - - 16 | 17 | - - - 18 | 19 | - - - 20 | 21 | - - - 22 | 23 | 24 | Asterisks: 25 | 26 | *** 27 | 28 | *** 29 | 30 | *** 31 | 32 | *** 33 | 34 | *** 35 | 36 | * * * 37 | 38 | * * * 39 | 40 | * * * 41 | 42 | * * * 43 | 44 | * * * 45 | 46 | 47 | Underscores: 48 | 49 | ___ 50 | 51 | ___ 52 | 53 | ___ 54 | 55 | ___ 56 | 57 | ___ 58 | 59 | _ _ _ 60 | 61 | _ _ _ 62 | 63 | _ _ _ 64 | 65 | _ _ _ 66 | 67 | _ _ _ 68 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Auto links.html: -------------------------------------------------------------------------------- 1 |

Link: http://example.com/.

2 | 3 |

With an ampersand: http://example.com/?foo=1&bar=2

4 | 5 | 10 | 11 |
12 |

Blockquoted: http://example.com/

13 |
14 | 15 |

Auto-links should not occur here: <http://example.com/>

16 | 17 |
or here: <http://example.com/>
18 | 
19 | -------------------------------------------------------------------------------- /src/escape.h: -------------------------------------------------------------------------------- 1 | /* escape.h - escape utilities */ 2 | 3 | #ifndef HOEDOWN_ESCAPE_H 4 | #define HOEDOWN_ESCAPE_H 5 | 6 | #include "buffer.h" 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | 13 | /************* 14 | * FUNCTIONS * 15 | *************/ 16 | 17 | /* hoedown_escape_href: escape (part of) a URL inside HTML */ 18 | void hoedown_escape_href(hoedown_buffer *ob, const uint8_t *data, size_t size); 19 | 20 | /* hoedown_escape_html: escape HTML */ 21 | void hoedown_escape_html(hoedown_buffer *ob, const uint8_t *data, size_t size, int secure); 22 | 23 | 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | 28 | #endif /** HOEDOWN_ESCAPE_H **/ 29 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | /* version.h - holds Hoedown's version */ 2 | 3 | #ifndef HOEDOWN_VERSION_H 4 | #define HOEDOWN_VERSION_H 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | 11 | /************* 12 | * CONSTANTS * 13 | *************/ 14 | 15 | #define HOEDOWN_VERSION "3.0.5" 16 | #define HOEDOWN_VERSION_MAJOR 3 17 | #define HOEDOWN_VERSION_MINOR 0 18 | #define HOEDOWN_VERSION_REVISION 5 19 | 20 | 21 | /************* 22 | * FUNCTIONS * 23 | *************/ 24 | 25 | /* hoedown_version: retrieve Hoedown's version numbers */ 26 | void hoedown_version(int *major, int *minor, int *revision); 27 | 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif /** HOEDOWN_VERSION_H **/ 34 | -------------------------------------------------------------------------------- /test/Tests/Math.text: -------------------------------------------------------------------------------- 1 | \\[ 2 | 1*2*3 multi-line math 3 | \\] 4 | 5 | \\( 1*2*3 inline-math \\) 6 | 7 | $$ 1*2*3 math with dollar $$ 8 | 9 | $$ 1*2*3 \$ \\ \text{dollar with escapes} $$ 10 | 11 | \\( \\ \text{backslash with escapes} \$ 1*2*3 \\) 12 | 13 | \( not *really* math \) 14 | 15 | \$$ also *not* math \$$ 16 | 17 | this $$*should* be$$ math 18 | 19 | this$$ *should* also be$$ math 20 | 21 | and $$this *should* $$too 22 | 23 | Something \\{ like *math* but \\} is not 24 | 25 | Also \\\(like *math* but \\\) is not 26 | 27 | \\\\( should be *math* as well \\\\) 28 | 29 | This is \\( math, and the \\\( inner one \\\) should be \\) preserved 30 | 31 | $$ did you know this is math? $$ 32 | -------------------------------------------------------------------------------- /test/Tests/Escape character.text: -------------------------------------------------------------------------------- 1 | \==Highlight\== 2 | 3 | \~~Strikethrough\~~ 4 | 5 | \_Underscore\_ 6 | 7 | \__Underscore\__ 8 | 9 | _\_Underscore_\_ 10 | 11 | \__Underscore_\_ 12 | 13 | _\_Underscore\__ 14 | 15 | \*Asterisk\* 16 | 17 | \**Asterisk\** 18 | 19 | \**Asterisk*\* 20 | 21 | *\*Asterisk\** 22 | 23 | *\*Asterisk*\* 24 | 25 | \[Bracket\] 26 | 27 | \(Parenthesis\) 28 | 29 | \ 30 | 31 | Super\^script 32 | 33 | \`Backtick\` 34 | 35 | \"Quote\" 36 | 37 | **Foo\\** 38 | 39 | *Foo\\\** 40 | 41 | **Foo\\\Bar\\** 42 | 43 | *Foo\\Bar\\\* 44 | 45 | [Foo\]](http://example.com) 46 | 47 | [Foo\\](http://example.com) 48 | 49 | [Foo\\\]](http://example.com) 50 | 51 | [Foo\\\\](http://example.com) 52 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Horizontal rules.html: -------------------------------------------------------------------------------- 1 |

Dashes:

2 | 3 |
4 | 5 |
6 | 7 |
8 | 9 |
10 | 11 |
---
12 | 
13 | 14 |
15 | 16 |
17 | 18 |
19 | 20 |
21 | 22 |
- - -
23 | 
24 | 25 |

Asterisks:

26 | 27 |
28 | 29 |
30 | 31 |
32 | 33 |
34 | 35 |
***
36 | 
37 | 38 |
39 | 40 |
41 | 42 |
43 | 44 |
45 | 46 |
* * *
47 | 
48 | 49 |

Underscores:

50 | 51 |
52 | 53 |
54 | 55 |
56 | 57 |
58 | 59 |
___
60 | 
61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 |
69 | 70 |
_ _ _
71 | 
72 | -------------------------------------------------------------------------------- /test/Tests/Math.html: -------------------------------------------------------------------------------- 1 |

\[ 2 | 1*2*3 multi-line math 3 | \]

4 | 5 |

\( 1*2*3 inline-math \)

6 | 7 |

\[ 1*2*3 math with dollar \]

8 | 9 |

\[ 1*2*3 \$ \\ \text{dollar with escapes} \]

10 | 11 |

\( \\ \text{backslash with escapes} \$ 1*2*3 \)

12 | 13 |

( not really math )

14 | 15 |

$$ also not math $$

16 | 17 |

this \(*should* be\) math

18 | 19 |

this\( *should* also be\) math

20 | 21 |

and \(this *should* \)too

22 | 23 |

Something \{ like math but \} is not

24 | 25 |

Also \(like math but \) is not

26 | 27 |

\\( should be *math* as well \\\)

28 | 29 |

This is \( math, and the \\\( inner one \\\) should be \) preserved

30 | 31 |

\[ did you <em> know </em> this is math? \]

32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008, Natacha Porté 2 | Copyright (c) 2011, Vicent Martí 3 | Copyright (c) 2014, Xavier Mendez, Devin Torres and the Hoedown authors 4 | 5 | Permission to use, copy, modify, and distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Inline HTML (Simple).text: -------------------------------------------------------------------------------- 1 | Here's a simple block: 2 | 3 |
4 | foo 5 |
6 | 7 | This should be a code block, though: 8 | 9 |
10 | foo 11 |
12 | 13 | As should this: 14 | 15 |
foo
16 | 17 | Now, nested: 18 | 19 |
20 |
21 |
22 | foo 23 |
24 |
25 |
26 | 27 | This should just be an HTML comment: 28 | 29 | 30 | 31 | Multiline: 32 | 33 | 37 | 38 | Code block: 39 | 40 | 41 | 42 | Just plain comment, with trailing spaces on the line: 43 | 44 | 45 | 46 | Code: 47 | 48 |
49 | 50 | Hr's: 51 | 52 |
53 | 54 |
55 | 56 |
57 | 58 |
59 | 60 |
61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 |
69 | 70 | -------------------------------------------------------------------------------- /test/Tests/Escape character.html: -------------------------------------------------------------------------------- 1 |

==Highlight==

2 | 3 |

~~Strikethrough~~

4 | 5 |

_Underscore_

6 | 7 |

_Underscore_

8 | 9 |

_Underscore_

10 | 11 |

_Underscore_

12 | 13 |

_Underscore_

14 | 15 |

*Asterisk*

16 | 17 |

*Asterisk*

18 | 19 |

*Asterisk*

20 | 21 |

*Asterisk*

22 | 23 |

*Asterisk*

24 | 25 |

[Bracket]

26 | 27 |

(Parenthesis)

28 | 29 |

<Chevron>

30 | 31 |

Super^script

32 | 33 |

`Backtick`

34 | 35 |

"Quote"

36 | 37 |

Foo\

38 | 39 |

Foo\*

40 | 41 |

Foo\\Bar\

42 | 43 |

*Foo\Bar\*

44 | 45 |

Foo]

46 | 47 |

Foo\

48 | 49 |

Foo\]

50 | 51 |

Foo\\

52 | -------------------------------------------------------------------------------- /hoedown.def: -------------------------------------------------------------------------------- 1 | LIBRARY HOEDOWN 2 | EXPORTS 3 | hoedown_autolink_is_safe 4 | hoedown_autolink__www 5 | hoedown_autolink__email 6 | hoedown_autolink__url 7 | hoedown_buffer_init 8 | hoedown_buffer_new 9 | hoedown_buffer_reset 10 | hoedown_buffer_grow 11 | hoedown_buffer_put 12 | hoedown_buffer_puts 13 | hoedown_buffer_putc 14 | hoedown_buffer_set 15 | hoedown_buffer_sets 16 | hoedown_buffer_eq 17 | hoedown_buffer_eqs 18 | hoedown_buffer_prefix 19 | hoedown_buffer_slurp 20 | hoedown_buffer_cstr 21 | hoedown_buffer_printf 22 | hoedown_buffer_free 23 | hoedown_document_new 24 | hoedown_document_render 25 | hoedown_document_render_inline 26 | hoedown_document_free 27 | hoedown_escape_href 28 | hoedown_escape_html 29 | hoedown_html_smartypants 30 | hoedown_html_is_tag 31 | hoedown_html_renderer_new 32 | hoedown_html_toc_renderer_new 33 | hoedown_html_renderer_free 34 | hoedown_stack_init 35 | hoedown_stack_uninit 36 | hoedown_stack_grow 37 | hoedown_stack_push 38 | hoedown_stack_pop 39 | hoedown_stack_top 40 | hoedown_version 41 | -------------------------------------------------------------------------------- /Makefile.win: -------------------------------------------------------------------------------- 1 | CC = cl 2 | CFLAGS = /O2 /sdl /Isrc /D_CRT_SECURE_NO_WARNINGS 3 | 4 | HOEDOWN_SRC = \ 5 | src\autolink.obj \ 6 | src\buffer.obj \ 7 | src\document.obj \ 8 | src\escape.obj \ 9 | src\html.obj \ 10 | src\html_blocks.obj \ 11 | src\html_smartypants.obj \ 12 | src\stack.obj \ 13 | src\version.obj 14 | 15 | all: hoedown.dll hoedown.exe smartypants.exe 16 | 17 | hoedown.dll: $(HOEDOWN_SRC) hoedown.def 18 | $(CC) $(HOEDOWN_SRC) hoedown.def /link /DLL $(LDFLAGS) /out:$@ 19 | 20 | hoedown.exe: bin\hoedown.obj $(HOEDOWN_SRC) 21 | $(CC) bin\hoedown.obj $(HOEDOWN_SRC) /link $(LDFLAGS) /out:$@ 22 | 23 | smartypants.exe: bin\smartypants.obj $(HOEDOWN_SRC) 24 | $(CC) bin\smartypants.obj $(HOEDOWN_SRC) /link $(LDFLAGS) /out:$@ 25 | 26 | # Housekeeping 27 | 28 | clean: 29 | del $(HOEDOWN_SRC) 30 | del hoedown.dll hoedown.exp hoedown.lib 31 | del hoedown.exe smartypants.exe 32 | 33 | # Generic object compilations 34 | 35 | .c.obj: 36 | $(CC) $(CFLAGS) /c $< /Fo$@ 37 | 38 | # Testing 39 | 40 | test: hoedown.exe 41 | python test\runner.py 42 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Inline HTML (Simple).html: -------------------------------------------------------------------------------- 1 |

Here's a simple block:

2 | 3 |
4 | foo 5 |
6 | 7 |

This should be a code block, though:

8 | 9 |
<div>
10 |     foo
11 | </div>
12 | 
13 | 14 |

As should this:

15 | 16 |
<div>foo</div>
17 | 
18 | 19 |

Now, nested:

20 | 21 |
22 |
23 |
24 | foo 25 |
26 |
27 |
28 | 29 |

This should just be an HTML comment:

30 | 31 | 32 | 33 |

Multiline:

34 | 35 | 39 | 40 |

Code block:

41 | 42 |
<!-- Comment -->
43 | 
44 | 45 |

Just plain comment, with trailing spaces on the line:

46 | 47 | 48 | 49 |

Code:

50 | 51 |
<hr />
52 | 
53 | 54 |

Hr's:

55 | 56 |
57 | 58 |
59 | 60 |
61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 |
69 | 70 |
71 | 72 |
73 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Links, reference style.text: -------------------------------------------------------------------------------- 1 | Foo [bar] [1]. 2 | 3 | Foo [bar][1]. 4 | 5 | Foo [bar] 6 | [1]. 7 | 8 | [1]: /url/ "Title" 9 | 10 | 11 | With [embedded [brackets]] [b]. 12 | 13 | 14 | Indented [once][]. 15 | 16 | Indented [twice][]. 17 | 18 | Indented [thrice][]. 19 | 20 | Indented [four][] times. 21 | 22 | [once]: /url 23 | 24 | [twice]: /url 25 | 26 | [thrice]: /url 27 | 28 | [four]: /url 29 | 30 | 31 | [b]: /url/ 32 | 33 | * * * 34 | 35 | [this] [this] should work 36 | 37 | So should [this][this]. 38 | 39 | And [this] []. 40 | 41 | And [this][]. 42 | 43 | And [this]. 44 | 45 | But not [that] []. 46 | 47 | Nor [that][]. 48 | 49 | Nor [that]. 50 | 51 | [Something in brackets like [this][] should work] 52 | 53 | [Same with [this].] 54 | 55 | In this case, [this](/somethingelse/) points to something else. 56 | 57 | Backslashing should suppress \[this] and [this\]. 58 | 59 | [this]: foo 60 | 61 | 62 | * * * 63 | 64 | Here's one where the [link 65 | breaks] across lines. 66 | 67 | Here's another where the [link 68 | breaks] across lines, but with a line-ending space. 69 | 70 | 71 | [link breaks]: /url/ 72 | -------------------------------------------------------------------------------- /test/Tests/Table.html: -------------------------------------------------------------------------------- 1 |

Standard table

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
headline1headline2
123
17 | 18 | 19 |

Cell alignment

20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
headline1headline2headline3
123
37 | 38 | 39 |

Malformed table: missing cell at row in body

40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
headline1headline2headline3
12
34
56
67 | -------------------------------------------------------------------------------- /src/stack.h: -------------------------------------------------------------------------------- 1 | /* stack.h - simple stacking */ 2 | 3 | #ifndef HOEDOWN_STACK_H 4 | #define HOEDOWN_STACK_H 5 | 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | 13 | /********* 14 | * TYPES * 15 | *********/ 16 | 17 | struct hoedown_stack { 18 | void **item; 19 | size_t size; 20 | size_t asize; 21 | }; 22 | typedef struct hoedown_stack hoedown_stack; 23 | 24 | 25 | /************* 26 | * FUNCTIONS * 27 | *************/ 28 | 29 | /* hoedown_stack_init: initialize a stack */ 30 | void hoedown_stack_init(hoedown_stack *st, size_t initial_size); 31 | 32 | /* hoedown_stack_uninit: free internal data of the stack */ 33 | void hoedown_stack_uninit(hoedown_stack *st); 34 | 35 | /* hoedown_stack_grow: increase the allocated size to the given value */ 36 | void hoedown_stack_grow(hoedown_stack *st, size_t neosz); 37 | 38 | /* hoedown_stack_push: push an item to the top of the stack */ 39 | void hoedown_stack_push(hoedown_stack *st, void *item); 40 | 41 | /* hoedown_stack_pop: retrieve and remove the item at the top of the stack */ 42 | void *hoedown_stack_pop(hoedown_stack *st); 43 | 44 | /* hoedown_stack_top: retrieve the item at the top of the stack */ 45 | void *hoedown_stack_top(const hoedown_stack *st); 46 | 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif 51 | 52 | #endif /** HOEDOWN_STACK_H **/ 53 | -------------------------------------------------------------------------------- /src/autolink.h: -------------------------------------------------------------------------------- 1 | /* autolink.h - versatile autolinker */ 2 | 3 | #ifndef HOEDOWN_AUTOLINK_H 4 | #define HOEDOWN_AUTOLINK_H 5 | 6 | #include "buffer.h" 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | 13 | /************* 14 | * CONSTANTS * 15 | *************/ 16 | 17 | typedef enum hoedown_autolink_flags { 18 | HOEDOWN_AUTOLINK_SHORT_DOMAINS = (1 << 0) 19 | } hoedown_autolink_flags; 20 | 21 | 22 | /************* 23 | * FUNCTIONS * 24 | *************/ 25 | 26 | /* hoedown_autolink_is_safe: verify that a URL has a safe protocol */ 27 | int hoedown_autolink_is_safe(const uint8_t *data, size_t size); 28 | 29 | /* hoedown_autolink__www: search for the next www link in data */ 30 | size_t hoedown_autolink__www(size_t *rewind_p, hoedown_buffer *link, 31 | uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags); 32 | 33 | /* hoedown_autolink__email: search for the next email in data */ 34 | size_t hoedown_autolink__email(size_t *rewind_p, hoedown_buffer *link, 35 | uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags); 36 | 37 | /* hoedown_autolink__url: search for the next URL in data */ 38 | size_t hoedown_autolink__url(size_t *rewind_p, hoedown_buffer *link, 39 | uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags); 40 | 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | #endif /** HOEDOWN_AUTOLINK_H **/ 47 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Links, reference style.html: -------------------------------------------------------------------------------- 1 |

Foo bar.

2 | 3 |

Foo bar.

4 | 5 |

Foo bar.

6 | 7 |

With embedded [brackets].

8 | 9 |

Indented once.

10 | 11 |

Indented twice.

12 | 13 |

Indented thrice.

14 | 15 |

Indented [four][] times.

16 | 17 |
[four]: /url
18 | 
19 | 20 |
21 | 22 |

this should work

23 | 24 |

So should this.

25 | 26 |

And this.

27 | 28 |

And this.

29 | 30 |

And this.

31 | 32 |

But not [that] [].

33 | 34 |

Nor [that][].

35 | 36 |

Nor [that].

37 | 38 |

[Something in brackets like this should work]

39 | 40 |

[Same with this.]

41 | 42 |

In this case, this points to something else.

43 | 44 |

Backslashing should suppress [this] and [this].

45 | 46 |
47 | 48 |

Here's one where the link 49 | breaks across lines.

50 | 51 |

Here's another where the link 52 | breaks across lines, but with a line-ending space.

53 | -------------------------------------------------------------------------------- /src/stack.c: -------------------------------------------------------------------------------- 1 | #include "stack.h" 2 | 3 | #include "buffer.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | void 10 | hoedown_stack_init(hoedown_stack *st, size_t initial_size) 11 | { 12 | assert(st); 13 | 14 | st->item = NULL; 15 | st->size = st->asize = 0; 16 | 17 | if (!initial_size) 18 | initial_size = 8; 19 | 20 | hoedown_stack_grow(st, initial_size); 21 | } 22 | 23 | void 24 | hoedown_stack_uninit(hoedown_stack *st) 25 | { 26 | assert(st); 27 | 28 | free(st->item); 29 | } 30 | 31 | void 32 | hoedown_stack_grow(hoedown_stack *st, size_t neosz) 33 | { 34 | assert(st); 35 | 36 | if (st->asize >= neosz) 37 | return; 38 | 39 | st->item = hoedown_realloc(st->item, neosz * sizeof(void *)); 40 | memset(st->item + st->asize, 0x0, (neosz - st->asize) * sizeof(void *)); 41 | 42 | st->asize = neosz; 43 | 44 | if (st->size > neosz) 45 | st->size = neosz; 46 | } 47 | 48 | void 49 | hoedown_stack_push(hoedown_stack *st, void *item) 50 | { 51 | assert(st); 52 | 53 | if (st->size >= st->asize) 54 | hoedown_stack_grow(st, st->size * 2); 55 | 56 | st->item[st->size++] = item; 57 | } 58 | 59 | void * 60 | hoedown_stack_pop(hoedown_stack *st) 61 | { 62 | assert(st); 63 | 64 | if (!st->size) 65 | return NULL; 66 | 67 | return st->item[--st->size]; 68 | } 69 | 70 | void * 71 | hoedown_stack_top(const hoedown_stack *st) 72 | { 73 | assert(st); 74 | 75 | if (!st->size) 76 | return NULL; 77 | 78 | return st->item[st->size - 1]; 79 | } 80 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Ordered and unordered lists.text: -------------------------------------------------------------------------------- 1 | ## Unordered 2 | 3 | Asterisks tight: 4 | 5 | * asterisk 1 6 | * asterisk 2 7 | * asterisk 3 8 | 9 | 10 | Asterisks loose: 11 | 12 | * asterisk 1 13 | 14 | * asterisk 2 15 | 16 | * asterisk 3 17 | 18 | * * * 19 | 20 | Pluses tight: 21 | 22 | + Plus 1 23 | + Plus 2 24 | + Plus 3 25 | 26 | 27 | Pluses loose: 28 | 29 | + Plus 1 30 | 31 | + Plus 2 32 | 33 | + Plus 3 34 | 35 | * * * 36 | 37 | 38 | Minuses tight: 39 | 40 | - Minus 1 41 | - Minus 2 42 | - Minus 3 43 | 44 | 45 | Minuses loose: 46 | 47 | - Minus 1 48 | 49 | - Minus 2 50 | 51 | - Minus 3 52 | 53 | 54 | ## Ordered 55 | 56 | Tight: 57 | 58 | 1. First 59 | 2. Second 60 | 3. Third 61 | 62 | and: 63 | 64 | 1. One 65 | 2. Two 66 | 3. Three 67 | 68 | 69 | Loose using tabs: 70 | 71 | 1. First 72 | 73 | 2. Second 74 | 75 | 3. Third 76 | 77 | and using spaces: 78 | 79 | 1. One 80 | 81 | 2. Two 82 | 83 | 3. Three 84 | 85 | Multiple paragraphs: 86 | 87 | 1. Item 1, graf one. 88 | 89 | Item 2. graf two. The quick brown fox jumped over the lazy dog's 90 | back. 91 | 92 | 2. Item 2. 93 | 94 | 3. Item 3. 95 | 96 | 97 | 98 | ## Nested 99 | 100 | * Tab 101 | * Tab 102 | * Tab 103 | 104 | Here's another: 105 | 106 | 1. First 107 | 2. Second: 108 | * Fee 109 | * Fie 110 | * Foe 111 | 3. Third 112 | 113 | Same thing but with paragraphs: 114 | 115 | 1. First 116 | 117 | 2. Second: 118 | * Fee 119 | * Fie 120 | * Foe 121 | 122 | 3. Third 123 | 124 | 125 | This was an error in Markdown 1.0.1: 126 | 127 | * this 128 | 129 | * sub 130 | 131 | that 132 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Backslash escapes.text: -------------------------------------------------------------------------------- 1 | These should all get escaped: 2 | 3 | Backslash: \\ 4 | 5 | Backtick: \` 6 | 7 | Asterisk: \* 8 | 9 | Underscore: \_ 10 | 11 | Left brace: \{ 12 | 13 | Right brace: \} 14 | 15 | Left bracket: \[ 16 | 17 | Right bracket: \] 18 | 19 | Left paren: \( 20 | 21 | Right paren: \) 22 | 23 | Greater-than: \> 24 | 25 | Hash: \# 26 | 27 | Period: \. 28 | 29 | Bang: \! 30 | 31 | Plus: \+ 32 | 33 | Minus: \- 34 | 35 | 36 | 37 | These should not, because they occur within a code block: 38 | 39 | Backslash: \\ 40 | 41 | Backtick: \` 42 | 43 | Asterisk: \* 44 | 45 | Underscore: \_ 46 | 47 | Left brace: \{ 48 | 49 | Right brace: \} 50 | 51 | Left bracket: \[ 52 | 53 | Right bracket: \] 54 | 55 | Left paren: \( 56 | 57 | Right paren: \) 58 | 59 | Greater-than: \> 60 | 61 | Hash: \# 62 | 63 | Period: \. 64 | 65 | Bang: \! 66 | 67 | Plus: \+ 68 | 69 | Minus: \- 70 | 71 | 72 | Nor should these, which occur in code spans: 73 | 74 | Backslash: `\\` 75 | 76 | Backtick: `` \` `` 77 | 78 | Asterisk: `\*` 79 | 80 | Underscore: `\_` 81 | 82 | Left brace: `\{` 83 | 84 | Right brace: `\}` 85 | 86 | Left bracket: `\[` 87 | 88 | Right bracket: `\]` 89 | 90 | Left paren: `\(` 91 | 92 | Right paren: `\)` 93 | 94 | Greater-than: `\>` 95 | 96 | Hash: `\#` 97 | 98 | Period: `\.` 99 | 100 | Bang: `\!` 101 | 102 | Plus: `\+` 103 | 104 | Minus: `\-` 105 | 106 | 107 | These should get escaped, even though they're matching pairs for 108 | other Markdown constructs: 109 | 110 | \*asterisks\* 111 | 112 | \_underscores\_ 113 | 114 | \`backticks\` 115 | 116 | This is a code span with a literal backslash-backtick sequence: `` \` `` 117 | 118 | This is a tag with unescaped backticks bar. 119 | 120 | This is a tag with backslashes bar. 121 | -------------------------------------------------------------------------------- /src/html.h: -------------------------------------------------------------------------------- 1 | /* html.h - HTML renderer and utilities */ 2 | 3 | #ifndef HOEDOWN_HTML_H 4 | #define HOEDOWN_HTML_H 5 | 6 | #include "document.h" 7 | #include "buffer.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | 14 | /************* 15 | * CONSTANTS * 16 | *************/ 17 | 18 | typedef enum hoedown_html_flags { 19 | HOEDOWN_HTML_SKIP_HTML = (1 << 0), 20 | HOEDOWN_HTML_ESCAPE = (1 << 1), 21 | HOEDOWN_HTML_HARD_WRAP = (1 << 2), 22 | HOEDOWN_HTML_USE_XHTML = (1 << 3) 23 | } hoedown_html_flags; 24 | 25 | typedef enum hoedown_html_tag { 26 | HOEDOWN_HTML_TAG_NONE = 0, 27 | HOEDOWN_HTML_TAG_OPEN, 28 | HOEDOWN_HTML_TAG_CLOSE 29 | } hoedown_html_tag; 30 | 31 | 32 | /********* 33 | * TYPES * 34 | *********/ 35 | 36 | struct hoedown_html_renderer_state { 37 | void *opaque; 38 | 39 | struct { 40 | int header_count; 41 | int current_level; 42 | int level_offset; 43 | int nesting_level; 44 | } toc_data; 45 | 46 | hoedown_html_flags flags; 47 | 48 | /* extra callbacks */ 49 | void (*link_attributes)(hoedown_buffer *ob, const hoedown_buffer *url, const hoedown_renderer_data *data); 50 | }; 51 | typedef struct hoedown_html_renderer_state hoedown_html_renderer_state; 52 | 53 | 54 | /************* 55 | * FUNCTIONS * 56 | *************/ 57 | 58 | /* hoedown_html_smartypants: process an HTML snippet using SmartyPants for smart punctuation */ 59 | void hoedown_html_smartypants(hoedown_buffer *ob, const uint8_t *data, size_t size); 60 | 61 | /* hoedown_html_is_tag: checks if data starts with a specific tag, returns the tag type or NONE */ 62 | hoedown_html_tag hoedown_html_is_tag(const uint8_t *data, size_t size, const char *tagname); 63 | 64 | 65 | /* hoedown_html_renderer_new: allocates a regular HTML renderer */ 66 | hoedown_renderer *hoedown_html_renderer_new( 67 | hoedown_html_flags render_flags, 68 | int nesting_level 69 | ) __attribute__ ((malloc)); 70 | 71 | /* hoedown_html_toc_renderer_new: like hoedown_html_renderer_new, but the returned renderer produces the Table of Contents */ 72 | hoedown_renderer *hoedown_html_toc_renderer_new( 73 | int nesting_level 74 | ) __attribute__ ((malloc)); 75 | 76 | /* hoedown_html_renderer_free: deallocate an HTML renderer */ 77 | void hoedown_html_renderer_free(hoedown_renderer *renderer); 78 | 79 | 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | 84 | #endif /** HOEDOWN_HTML_H **/ 85 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Backslash escapes.html: -------------------------------------------------------------------------------- 1 |

These should all get escaped:

2 | 3 |

Backslash: \

4 | 5 |

Backtick: `

6 | 7 |

Asterisk: *

8 | 9 |

Underscore: _

10 | 11 |

Left brace: {

12 | 13 |

Right brace: }

14 | 15 |

Left bracket: [

16 | 17 |

Right bracket: ]

18 | 19 |

Left paren: (

20 | 21 |

Right paren: )

22 | 23 |

Greater-than: >

24 | 25 |

Hash: #

26 | 27 |

Period: .

28 | 29 |

Bang: !

30 | 31 |

Plus: +

32 | 33 |

Minus: -

34 | 35 |

These should not, because they occur within a code block:

36 | 37 |
Backslash: \\
 38 | 
 39 | Backtick: \`
 40 | 
 41 | Asterisk: \*
 42 | 
 43 | Underscore: \_
 44 | 
 45 | Left brace: \{
 46 | 
 47 | Right brace: \}
 48 | 
 49 | Left bracket: \[
 50 | 
 51 | Right bracket: \]
 52 | 
 53 | Left paren: \(
 54 | 
 55 | Right paren: \)
 56 | 
 57 | Greater-than: \>
 58 | 
 59 | Hash: \#
 60 | 
 61 | Period: \.
 62 | 
 63 | Bang: \!
 64 | 
 65 | Plus: \+
 66 | 
 67 | Minus: \-
 68 | 
69 | 70 |

Nor should these, which occur in code spans:

71 | 72 |

Backslash: \\

73 | 74 |

Backtick: \`

75 | 76 |

Asterisk: \*

77 | 78 |

Underscore: \_

79 | 80 |

Left brace: \{

81 | 82 |

Right brace: \}

83 | 84 |

Left bracket: \[

85 | 86 |

Right bracket: \]

87 | 88 |

Left paren: \(

89 | 90 |

Right paren: \)

91 | 92 |

Greater-than: \>

93 | 94 |

Hash: \#

95 | 96 |

Period: \.

97 | 98 |

Bang: \!

99 | 100 |

Plus: \+

101 | 102 |

Minus: \-

103 | 104 | 105 |

These should get escaped, even though they're matching pairs for 106 | other Markdown constructs:

107 | 108 |

*asterisks*

109 | 110 |

_underscores_

111 | 112 |

`backticks`

113 | 114 |

This is a code span with a literal backslash-backtick sequence: \`

115 | 116 |

This is a tag with unescaped backticks bar.

117 | 118 |

This is a tag with backslashes bar.

119 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -g -O3 -ansi -pedantic -Wall -Wextra -Wno-unused-parameter 2 | PREFIX = /usr/local 3 | BINDIR = $(PREFIX)/bin 4 | LIBDIR = $(PREFIX)/lib 5 | INCLUDEDIR = $(PREFIX)/include 6 | 7 | HOEDOWN_CFLAGS = $(CFLAGS) -Isrc 8 | ifneq ($(OS),Windows_NT) 9 | HOEDOWN_CFLAGS += -fPIC 10 | endif 11 | 12 | HOEDOWN_SRC=\ 13 | src/autolink.o \ 14 | src/buffer.o \ 15 | src/document.o \ 16 | src/escape.o \ 17 | src/html.o \ 18 | src/html_blocks.o \ 19 | src/html_smartypants.o \ 20 | src/stack.o \ 21 | src/version.o 22 | 23 | .PHONY: all test test-pl clean 24 | 25 | all: libhoedown.so libhoedown.a hoedown smartypants 26 | 27 | # Libraries 28 | 29 | libhoedown.so: libhoedown.so.3 30 | ln -f -s $^ $@ 31 | 32 | libhoedown.so.3: $(HOEDOWN_SRC) 33 | $(CC) -Wl,-soname,$(@F) -shared $^ $(LDFLAGS) -o $@ 34 | 35 | libhoedown.a: $(HOEDOWN_SRC) 36 | $(AR) rcs libhoedown.a $^ 37 | 38 | # Executables 39 | 40 | hoedown: bin/hoedown.o $(HOEDOWN_SRC) 41 | $(CC) $^ $(LDFLAGS) -o $@ 42 | 43 | smartypants: bin/smartypants.o $(HOEDOWN_SRC) 44 | $(CC) $^ $(LDFLAGS) -o $@ 45 | 46 | # Perfect hashing 47 | 48 | src/html_blocks.c: html_block_names.gperf 49 | gperf -L ANSI-C -N hoedown_find_block_tag -c -C -E -S 1 --ignore-case -m100 $^ > $@ 50 | 51 | # Testing 52 | 53 | test: hoedown 54 | python test/runner.py 55 | 56 | test-pl: hoedown 57 | perl test/MarkdownTest_1.0.3/MarkdownTest.pl \ 58 | --script=./hoedown --testdir=test/MarkdownTest_1.0.3/Tests --tidy 59 | 60 | # Housekeeping 61 | 62 | clean: 63 | $(RM) src/*.o bin/*.o 64 | $(RM) libhoedown.so libhoedown.so.1 libhoedown.a 65 | $(RM) hoedown smartypants hoedown.exe smartypants.exe 66 | 67 | # Installing 68 | 69 | install: 70 | install -m755 -d $(DESTDIR)$(LIBDIR) 71 | install -m755 -d $(DESTDIR)$(BINDIR) 72 | install -m755 -d $(DESTDIR)$(INCLUDEDIR) 73 | 74 | install -m644 libhoedown.a $(DESTDIR)$(LIBDIR) 75 | install -m755 libhoedown.so.3 $(DESTDIR)$(LIBDIR) 76 | ln -f -s libhoedown.so.3 $(DESTDIR)$(LIBDIR)/libhoedown.so 77 | 78 | install -m755 hoedown $(DESTDIR)$(BINDIR) 79 | install -m755 smartypants $(DESTDIR)$(BINDIR) 80 | 81 | install -m755 -d $(DESTDIR)$(INCLUDEDIR)/hoedown 82 | install -m644 src/*.h $(DESTDIR)$(INCLUDEDIR)/hoedown 83 | 84 | # Generic object compilations 85 | 86 | %.o: %.c 87 | $(CC) $(HOEDOWN_CFLAGS) -c -o $@ $< 88 | 89 | src/html_blocks.o: src/html_blocks.c 90 | $(CC) $(HOEDOWN_CFLAGS) -Wno-static-in-inline -c -o $@ $< 91 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Ordered and unordered lists.html: -------------------------------------------------------------------------------- 1 |

Unordered

2 | 3 |

Asterisks tight:

4 | 5 |
    6 |
  • asterisk 1
  • 7 |
  • asterisk 2
  • 8 |
  • asterisk 3
  • 9 |
10 | 11 |

Asterisks loose:

12 | 13 |
    14 |
  • asterisk 1

  • 15 |
  • asterisk 2

  • 16 |
  • asterisk 3

  • 17 |
18 | 19 |
20 | 21 |

Pluses tight:

22 | 23 |
    24 |
  • Plus 1
  • 25 |
  • Plus 2
  • 26 |
  • Plus 3
  • 27 |
28 | 29 |

Pluses loose:

30 | 31 |
    32 |
  • Plus 1

  • 33 |
  • Plus 2

  • 34 |
  • Plus 3

  • 35 |
36 | 37 |
38 | 39 |

Minuses tight:

40 | 41 |
    42 |
  • Minus 1
  • 43 |
  • Minus 2
  • 44 |
  • Minus 3
  • 45 |
46 | 47 |

Minuses loose:

48 | 49 |
    50 |
  • Minus 1

  • 51 |
  • Minus 2

  • 52 |
  • Minus 3

  • 53 |
54 | 55 |

Ordered

56 | 57 |

Tight:

58 | 59 |
    60 |
  1. First
  2. 61 |
  3. Second
  4. 62 |
  5. Third
  6. 63 |
64 | 65 |

and:

66 | 67 |
    68 |
  1. One
  2. 69 |
  3. Two
  4. 70 |
  5. Three
  6. 71 |
72 | 73 |

Loose using tabs:

74 | 75 |
    76 |
  1. First

  2. 77 |
  3. Second

  4. 78 |
  5. Third

  6. 79 |
80 | 81 |

and using spaces:

82 | 83 |
    84 |
  1. One

  2. 85 |
  3. Two

  4. 86 |
  5. Three

  6. 87 |
88 | 89 |

Multiple paragraphs:

90 | 91 |
    92 |
  1. Item 1, graf one.

    93 | 94 |

    Item 2. graf two. The quick brown fox jumped over the lazy dog's 95 | back.

  2. 96 |
  3. Item 2.

  4. 97 |
  5. Item 3.

  6. 98 |
99 | 100 |

Nested

101 | 102 |
    103 |
  • Tab 104 |
      105 |
    • Tab 106 |
        107 |
      • Tab
      • 108 |
    • 109 |
  • 110 |
111 | 112 |

Here's another:

113 | 114 |
    115 |
  1. First
  2. 116 |
  3. Second: 117 |
      118 |
    • Fee
    • 119 |
    • Fie
    • 120 |
    • Foe
    • 121 |
  4. 122 |
  5. Third
  6. 123 |
124 | 125 |

Same thing but with paragraphs:

126 | 127 |
    128 |
  1. First

  2. 129 |
  3. Second:

    130 | 131 |
      132 |
    • Fee
    • 133 |
    • Fie
    • 134 |
    • Foe
    • 135 |
  4. 136 |
  5. Third

  6. 137 |
138 | 139 | 140 |

This was an error in Markdown 1.0.1:

141 | 142 |
    143 |
  • this

    144 | 145 |
    • sub
    146 | 147 |

    that

  • 148 |
149 | -------------------------------------------------------------------------------- /bin/common.h: -------------------------------------------------------------------------------- 1 | #include "version.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define str(x) __str(x) 9 | #define __str(x) #x 10 | 11 | #define count_of(arr) (sizeof(arr)/sizeof(0[arr])) 12 | 13 | int 14 | parseint(const char *string, long *result) 15 | { 16 | char *end; 17 | errno = 0; 18 | *result = strtol(string, &end, 10); 19 | return !(*end || errno); 20 | } 21 | 22 | const char * 23 | strprefix(const char *str, const char *prefix) 24 | { 25 | while (*prefix) { 26 | if (!(*str && *str == *prefix)) return 0; 27 | prefix++; str++; 28 | } 29 | return str; 30 | } 31 | 32 | void 33 | print_option(char short_opt, const char *long_opt, const char *description) 34 | { 35 | if (short_opt) 36 | printf(" -%c, ", short_opt); 37 | else 38 | printf(" "); 39 | 40 | printf("--%-13s %s\n", long_opt, description); 41 | } 42 | 43 | void 44 | print_version() 45 | { 46 | printf("Built with Hoedown " HOEDOWN_VERSION ".\n"); 47 | } 48 | 49 | int 50 | parse_options( 51 | int argc, char **argv, 52 | int(*parse_short_option)(char opt, char *next, void *opaque), 53 | int(*parse_long_option)(char *opt, char *next, void *opaque), 54 | int(*parse_argument)(int argn, char *arg, int is_forced, void *opaque), 55 | void *opaque) 56 | { 57 | int result; 58 | int i = 1, regular_args = 0; 59 | 60 | /* Parse options mixed with arguments */ 61 | while (i < argc) { 62 | char *arg = argv[i]; 63 | 64 | if (arg[0] == '-' && arg[1]) { 65 | char *next_arg = (i+1 < argc) ? argv[i+1] : NULL; 66 | 67 | if (arg[1] == '-' && !arg[2]) { 68 | /* '--' signals end of options */ 69 | i++; 70 | break; 71 | } 72 | 73 | if (arg[1] == '-') { 74 | /* Long option */ 75 | result = parse_long_option(arg + 2, next_arg, opaque); 76 | if (!result) return 0; 77 | i += result; 78 | } else { 79 | /* Sequence of short options */ 80 | size_t pos; 81 | for (pos = 1; arg[pos]; pos++) { 82 | char *next = (arg[pos+1]) ? arg + pos+1 : next_arg; 83 | result = parse_short_option(arg[pos], next, opaque); 84 | if (!result) return 0; 85 | if (result == 2) { 86 | if (next == next_arg) i++; 87 | break; 88 | } 89 | } 90 | i++; 91 | } 92 | } else { 93 | /* Argument */ 94 | result = parse_argument(regular_args++, arg, 0, opaque); 95 | if (!result) return 0; 96 | i++; 97 | } 98 | } 99 | 100 | /* Parse rest as forced arguments */ 101 | while (i < argc) { 102 | result = parse_argument(regular_args++, argv[i], 1, opaque); 103 | if (!result) return 0; 104 | i++; 105 | } 106 | 107 | return 1; 108 | } 109 | -------------------------------------------------------------------------------- /test/runner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import difflib 5 | import json 6 | import os 7 | import re 8 | import subprocess 9 | import unittest 10 | 11 | TEST_ROOT = os.path.dirname(__file__) 12 | PROJECT_ROOT = os.path.dirname(TEST_ROOT) 13 | HOEDOWN = [os.path.abspath(os.path.join(PROJECT_ROOT, 'hoedown'))] 14 | TIDY = ['tidy', '--show-body-only', '1', '--show-warnings', '0', 15 | '--quiet', '1'] 16 | CONFIG_PATH = os.path.join(TEST_ROOT, 'config.json') 17 | SLUGIFY_PATTERN = re.compile(r'\W') 18 | 19 | 20 | def with_metaclass(meta, *bases): 21 | """Metaclass injection utility from six. 22 | 23 | See: https://pythonhosted.org/six/ 24 | """ 25 | class metaclass(meta): 26 | def __new__(cls, name, this_bases, d): 27 | return meta(name, bases, d) 28 | return type.__new__(metaclass, 'temporary_class', (), {}) 29 | 30 | 31 | class TestFailed(AssertionError): 32 | def __init__(self, name, expected, got): 33 | super(TestFailed, self).__init__(self) 34 | diff = difflib.unified_diff( 35 | expected.splitlines(), got.splitlines(), 36 | fromfile='Expected', tofile='Got', 37 | ) 38 | self.description = '{name}\n{diff}'.format( 39 | name=name, diff='\n'.join(diff), 40 | ) 41 | 42 | def __str__(self): 43 | return self.description 44 | 45 | 46 | def _test_func(test_case): 47 | flags = test_case.get('flags') or [] 48 | hoedown_proc = subprocess.Popen( 49 | HOEDOWN + flags + [os.path.join(TEST_ROOT, test_case['input'])], 50 | stdout=subprocess.PIPE, 51 | ) 52 | stdoutdata = hoedown_proc.communicate()[0] 53 | 54 | got_tidy_proc = subprocess.Popen( 55 | TIDY, stdin=subprocess.PIPE, stdout=subprocess.PIPE, 56 | ) 57 | got = got_tidy_proc.communicate(input=stdoutdata)[0].strip() 58 | 59 | expected_tidy_proc = subprocess.Popen( 60 | TIDY + [os.path.join(TEST_ROOT, test_case['output'])], 61 | stdout=subprocess.PIPE, 62 | ) 63 | expected = expected_tidy_proc.communicate()[0].strip() 64 | 65 | # Cleanup. 66 | hoedown_proc.stdout.close() 67 | got_tidy_proc.stdout.close() 68 | expected_tidy_proc.stdout.close() 69 | 70 | try: 71 | assert expected == got 72 | except AssertionError: 73 | raise TestFailed(test_case['input'], expected, got) 74 | 75 | 76 | def _make_test(test_case): 77 | return lambda self: _test_func(test_case) 78 | 79 | 80 | class MarkdownTestsMeta(type): 81 | """Meta class for ``MarkdownTestCase`` to inject test cases on the fly. 82 | """ 83 | def __new__(meta, name, bases, attrs): 84 | with open(CONFIG_PATH) as f: 85 | config = json.load(f) 86 | 87 | for test in config['tests']: 88 | input_name = test['input'] 89 | attr_name = 'test_' + SLUGIFY_PATTERN.sub( 90 | '_', os.path.splitext(input_name)[0].lower(), 91 | ) 92 | func = _make_test(test) 93 | func.__doc__ = input_name 94 | if test.get('skip', False): 95 | func = unittest.skip(input_name)(func) 96 | if test.get('fail', False): 97 | func = unittest.expectsFailure(func) 98 | attrs[attr_name] = func 99 | return type.__new__(meta, name, bases, attrs) 100 | 101 | 102 | class MarkdownTests(with_metaclass(MarkdownTestsMeta, unittest.TestCase)): 103 | pass 104 | 105 | 106 | if __name__ == '__main__': 107 | unittest.main() 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Hoedown 2 | ======= 3 | 4 | [![Build Status](https://travis-ci.org/hoedown/hoedown.png?branch=master)](https://travis-ci.org/hoedown/hoedown) 5 | 6 | `Hoedown` is a revived fork of [Sundown](https://github.com/vmg/sundown), 7 | the Markdown parser based on the original code of the 8 | [Upskirt library](http://fossil.instinctive.eu/libupskirt/index) 9 | by Natacha Porté. 10 | 11 | Features 12 | -------- 13 | 14 | * **Fully standards compliant** 15 | 16 | `Hoedown` passes out of the box the official Markdown v1.0.0 and v1.0.3 17 | test suites, and has been extensively tested with additional corner cases 18 | to make sure its output is as sane as possible at all times. 19 | 20 | * **Massive extension support** 21 | 22 | `Hoedown` has optional support for several (unofficial) Markdown extensions, 23 | such as non-strict emphasis, fenced code blocks, tables, autolinks, 24 | strikethrough and more. 25 | 26 | * **UTF-8 aware** 27 | 28 | `Hoedown` is fully UTF-8 aware, both when parsing the source document and when 29 | generating the resulting (X)HTML code. 30 | 31 | * **Tested & Ready to be used on production** 32 | 33 | `Hoedown` has been extensively security audited, and includes protection against 34 | all possible DOS attacks (stack overflows, out of memory situations, malformed 35 | Markdown syntax...). 36 | 37 | We've worked very hard to make `Hoedown` never leak or crash under *any* input. 38 | 39 | **Warning**: `Hoedown` doesn't validate or post-process the HTML in Markdown documents. 40 | Unless you use `HTML_ESCAPE` or `HTML_SKIP`, you should strongly consider using a 41 | good post-processor in conjunction with Hoedown to prevent client-side attacks. 42 | 43 | * **Customizable renderers** 44 | 45 | `Hoedown` is not stuck with XHTML output: the Markdown parser of the library 46 | is decoupled from the renderer, so it's trivial to extend the library with 47 | custom renderers. A fully functional (X)HTML renderer is included. 48 | 49 | * **Optimized for speed** 50 | 51 | `Hoedown` is written in C, with a special emphasis on performance. When wrapped 52 | on a dynamic language such as Python or Ruby, it has shown to be up to 40 53 | times faster than other native alternatives. 54 | 55 | * **Zero-dependency** 56 | 57 | `Hoedown` is a zero-dependency library composed of some `.c` files and their 58 | headers. No dependencies, no bullshit. Only standard C99 that builds everywhere. 59 | 60 | * **Additional features** 61 | 62 | `Hoedown` comes with a fully functional implementation of SmartyPants, 63 | a separate autolinker, escaping utilities, buffers and stacks. 64 | 65 | Bindings 66 | -------- 67 | 68 | You can see a community-maintained list of `Hoedown` bindings at 69 | [the wiki](https://github.com/hoedown/hoedown/wiki/Bindings). There is also a 70 | [migration guide](https://github.com/hoedown/hoedown/wiki/Migration-Guide) 71 | available for authors of Sundown bindings. 72 | 73 | Help us 74 | ------- 75 | 76 | `Hoedown` is all about security. If you find a (potential) security vulnerability in the 77 | library, or a way to make it crash through malicious input, please report it to us by 78 | emailing the private [Hoedown Security](mailto:hoedown-security@googlegroups.com) 79 | mailing list. The `Hoedown` security team will review the vulnerability and work with you 80 | to reproduce and resolve it. 81 | 82 | Unicode character handling 83 | -------------------------- 84 | 85 | Given that the Markdown spec makes no provision for Unicode character handling, `Hoedown` 86 | takes a conservative approach towards deciding which extended characters trigger Markdown 87 | features: 88 | 89 | * Punctuation characters outside of the U+007F codepoint are not handled as punctuation. 90 | They are considered as normal, in-word characters for word-boundary checks. 91 | 92 | * Whitespace characters outside of the U+007F codepoint are not considered as 93 | whitespace. They are considered as normal, in-word characters for word-boundary checks. 94 | 95 | Install 96 | ------- 97 | 98 | Just typing `make` will build `Hoedown` into a dynamic library and create the `hoedown` 99 | and `smartypants` executables, which are command-line tools to render Markdown to HTML 100 | and perform SmartyPants, respectively. 101 | 102 | If you are using [CocoaPods](http://cocoapods.org), just add the line `pod 'hoedown'` to your Podfile and call `pod install`. 103 | 104 | Or, if you prefer, you can just throw the files at `src` into your project. 105 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/MarkdownTest.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # 4 | # MarkdownTester -- Run tests for Markdown implementations 5 | # 6 | # Copyright (c) 2004-2005 John Gruber 7 | # 8 | # 9 | 10 | use strict; 11 | use warnings; 12 | use Getopt::Long; 13 | use Benchmark; 14 | 15 | our $VERSION = '1.0.2'; 16 | # Sat 24 Dec 2005 17 | 18 | my $time_start = new Benchmark; 19 | my $test_dir = "Tests"; 20 | my $script = "./Markdown.pl"; 21 | my $use_tidy = 0; 22 | my ($flag_version); 23 | 24 | GetOptions ( 25 | "script=s" => \$script, 26 | "testdir=s" => \$test_dir, 27 | "tidy" => \$use_tidy, 28 | "version" => \$flag_version, 29 | ); 30 | 31 | if($flag_version) { 32 | my $progname = $0; 33 | $progname =~ s{.*/}{}; 34 | die "$progname version $VERSION\n"; 35 | } 36 | 37 | unless (-d $test_dir) { die "'$test_dir' is not a directory.\n"; } 38 | unless (-f $script) { die "$script does not exist.\n"; } 39 | unless (-x $script) { die "$script is not executable.\n"; } 40 | 41 | my $tests_passed = 0; 42 | my $tests_failed = 0; 43 | 44 | TEST: 45 | foreach my $testfile (glob "$test_dir/*.text") { 46 | my $testname = $testfile; 47 | $testname =~ s{.*/(.+)\.text$}{$1}i; 48 | print "$testname ... "; 49 | 50 | # Look for a corresponding .html file for each .text file: 51 | my $resultfile = $testfile; 52 | $resultfile =~ s{\.text$}{\.html}i; 53 | unless (-f $resultfile) { 54 | print "'$resultfile' does not exist.\n\n"; 55 | next TEST; 56 | } 57 | 58 | # open(TEST, $testfile) || die("Can't open testfile: $!"); 59 | open(RESULT, $resultfile) || die("Can't open resultfile: $!"); 60 | undef $/; 61 | # my $t_input = ; 62 | my $t_result = ; 63 | 64 | my $t_output = `'$script' '$testfile'`; 65 | 66 | # Normalize the output and expected result strings: 67 | $t_result =~ s/\s+\z//; # trim trailing whitespace 68 | $t_output =~ s/\s+\z//; # trim trailing whitespace 69 | if ($use_tidy) { 70 | # Escape the strings, pass them through to CLI tidy tool for tag-level equivalency 71 | $t_result =~ s{'}{'\\''}g; # escape ' chars for shell 72 | $t_output =~ s{'}{'\\''}g; 73 | $t_result = `echo '$t_result' | tidy --show-body-only 1 --quiet 1 --show-warnings 0`; 74 | $t_output = `echo '$t_output' | tidy --show-body-only 1 --quiet 1 --show-warnings 0`; 75 | } 76 | 77 | if ($t_output eq $t_result) { 78 | print "OK\n"; 79 | $tests_passed++; 80 | } 81 | else { 82 | print "FAILED\n\n"; 83 | # This part added by JM to print diffs 84 | open(OUT, '>tmp1') or die $!; 85 | print OUT $t_output or die $!; 86 | open(RES, '>tmp2') or die $!; 87 | print RES $t_result or die $!; 88 | print `diff tmp1 tmp2`; 89 | close RES; 90 | close OUT; 91 | print "\n"; 92 | `rm tmp?`; 93 | # End of added part 94 | $tests_failed++; 95 | } 96 | } 97 | 98 | print "\n\n"; 99 | print "$tests_passed passed; $tests_failed failed.\n"; 100 | 101 | my $time_end = new Benchmark; 102 | my $time_diff = timediff($time_end, $time_start); 103 | print "Benchmark: ", timestr($time_diff), "\n"; 104 | 105 | exit 1 if $tests_failed; 106 | 107 | __END__ 108 | 109 | =pod 110 | 111 | =head1 NAME 112 | 113 | B 114 | 115 | 116 | =head1 SYNOPSIS 117 | 118 | B [ B<--options> ] [ I ... ] 119 | 120 | 121 | =head1 DESCRIPTION 122 | 123 | 124 | =head1 OPTIONS 125 | 126 | Use "--" to end switch parsing. For example, to open a file named "-z", use: 127 | 128 | MarkdownTest.pl -- -z 129 | 130 | =over 4 131 | 132 | =item B<--script> 133 | 134 | Specify the path to the Markdown script to test. Defaults to 135 | "./Markdown.pl". Example: 136 | 137 | ./MarkdownTest.pl --script ./PHP-Markdown/php-markdown 138 | 139 | =item B<--testdir> 140 | 141 | Specify the path to a directory containing test data. Defaults to "Tests". 142 | 143 | =item B<--tidy> 144 | 145 | Flag to turn on using the command line 'tidy' tool to normalize HTML 146 | output before comparing script output to the expected test result. 147 | Assumes that the 'tidy' command is available in your PATH. Defaults to 148 | off. 149 | 150 | =back 151 | 152 | 153 | 154 | =head1 BUGS 155 | 156 | 157 | 158 | =head1 VERSION HISTORY 159 | 160 | 1.0 Mon 13 Dec 2004-2005 161 | 162 | 1.0.1 Mon 19 Sep 2005 163 | 164 | + Better handling of case when foo.text exists, but foo.html doesn't. 165 | It now prints a message and moves on, rather than dying. 166 | 167 | 168 | =head1 COPYRIGHT AND LICENSE 169 | 170 | Copyright (c) 2004-2005 John Gruber 171 | 172 | All rights reserved. 173 | 174 | This is free software; you may redistribute it and/or modify it under 175 | the same terms as Perl itself. 176 | 177 | =cut 178 | -------------------------------------------------------------------------------- /test/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "tests": [ 3 | { 4 | "input": "MarkdownTest_1.0.3/Tests/Amps and angle encoding.text", 5 | "output": "MarkdownTest_1.0.3/Tests/Amps and angle encoding.html" 6 | }, 7 | { 8 | "input": "MarkdownTest_1.0.3/Tests/Auto links.text", 9 | "output": "MarkdownTest_1.0.3/Tests/Auto links.html" 10 | }, 11 | { 12 | "input": "MarkdownTest_1.0.3/Tests/Backslash escapes.text", 13 | "output": "MarkdownTest_1.0.3/Tests/Backslash escapes.html" 14 | }, 15 | { 16 | "input": "MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.text", 17 | "output": "MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.html" 18 | }, 19 | { 20 | "input": "MarkdownTest_1.0.3/Tests/Code Blocks.text", 21 | "output": "MarkdownTest_1.0.3/Tests/Code Blocks.html" 22 | }, 23 | { 24 | "input": "MarkdownTest_1.0.3/Tests/Code Spans.text", 25 | "output": "MarkdownTest_1.0.3/Tests/Code Spans.html" 26 | }, 27 | { 28 | "input": "MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.text", 29 | "output": "MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.html" 30 | }, 31 | { 32 | "input": "MarkdownTest_1.0.3/Tests/Horizontal rules.text", 33 | "output": "MarkdownTest_1.0.3/Tests/Horizontal rules.html" 34 | }, 35 | { 36 | "input": "MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).text", 37 | "output": "MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).html" 38 | }, 39 | { 40 | "input": "MarkdownTest_1.0.3/Tests/Inline HTML (Simple).text", 41 | "output": "MarkdownTest_1.0.3/Tests/Inline HTML (Simple).html" 42 | }, 43 | { 44 | "input": "MarkdownTest_1.0.3/Tests/Inline HTML comments.text", 45 | "output": "MarkdownTest_1.0.3/Tests/Inline HTML comments.html" 46 | }, 47 | { 48 | "input": "MarkdownTest_1.0.3/Tests/Links, inline style.text", 49 | "output": "MarkdownTest_1.0.3/Tests/Links, inline style.html" 50 | }, 51 | { 52 | "input": "MarkdownTest_1.0.3/Tests/Links, reference style.text", 53 | "output": "MarkdownTest_1.0.3/Tests/Links, reference style.html" 54 | }, 55 | { 56 | "input": "MarkdownTest_1.0.3/Tests/Links, shortcut references.text", 57 | "output": "MarkdownTest_1.0.3/Tests/Links, shortcut references.html" 58 | }, 59 | { 60 | "input": "MarkdownTest_1.0.3/Tests/Literal quotes in titles.text", 61 | "output": "MarkdownTest_1.0.3/Tests/Literal quotes in titles.html" 62 | }, 63 | { 64 | "input": "MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.text", 65 | "output": "MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.html" 66 | }, 67 | { 68 | "input": "MarkdownTest_1.0.3/Tests/Markdown Documentation - Syntax.text", 69 | "output": "MarkdownTest_1.0.3/Tests/Markdown Documentation - Syntax.html" 70 | }, 71 | { 72 | "input": "MarkdownTest_1.0.3/Tests/Nested blockquotes.text", 73 | "output": "MarkdownTest_1.0.3/Tests/Nested blockquotes.html" 74 | }, 75 | { 76 | "input": "MarkdownTest_1.0.3/Tests/Ordered and unordered lists.text", 77 | "output": "MarkdownTest_1.0.3/Tests/Ordered and unordered lists.html" 78 | }, 79 | { 80 | "input": "MarkdownTest_1.0.3/Tests/Strong and em together.text", 81 | "output": "MarkdownTest_1.0.3/Tests/Strong and em together.html" 82 | }, 83 | { 84 | "input": "MarkdownTest_1.0.3/Tests/Tabs.text", 85 | "output": "MarkdownTest_1.0.3/Tests/Tabs.html" 86 | }, 87 | { 88 | "input": "MarkdownTest_1.0.3/Tests/Tidyness.text", 89 | "output": "MarkdownTest_1.0.3/Tests/Tidyness.html" 90 | }, 91 | { 92 | "input": "Tests/Escape character.text", 93 | "output": "Tests/Escape character.html" 94 | }, 95 | { 96 | "input": "Tests/Formatting in Table of Contents.text", 97 | "output": "Tests/Formatting in Table of Contents.html", 98 | "flags": ["--html-toc", "-t", "3"] 99 | }, 100 | { 101 | "input": "Tests/Math.text", 102 | "output": "Tests/Math.html", 103 | "flags": ["--math"] 104 | }, 105 | { 106 | "input": "Tests/Underline.text", 107 | "output": "Tests/Underline.html", 108 | "flags": ["--underline"] 109 | }, 110 | { 111 | "input": "Tests/Table.text", 112 | "output": "Tests/Table.html", 113 | "flags": ["--tables"] 114 | } 115 | ] 116 | } 117 | -------------------------------------------------------------------------------- /src/buffer.h: -------------------------------------------------------------------------------- 1 | /* buffer.h - simple, fast buffers */ 2 | 3 | #ifndef HOEDOWN_BUFFER_H 4 | #define HOEDOWN_BUFFER_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | #if defined(_MSC_VER) 17 | #define __attribute__(x) 18 | #define inline __inline 19 | #define __builtin_expect(x,n) x 20 | #endif 21 | 22 | 23 | /********* 24 | * TYPES * 25 | *********/ 26 | 27 | typedef void *(*hoedown_realloc_callback)(void *, size_t); 28 | typedef void (*hoedown_free_callback)(void *); 29 | 30 | struct hoedown_buffer { 31 | uint8_t *data; /* actual character data */ 32 | size_t size; /* size of the string */ 33 | size_t asize; /* allocated size (0 = volatile buffer) */ 34 | size_t unit; /* reallocation unit size (0 = read-only buffer) */ 35 | 36 | hoedown_realloc_callback data_realloc; 37 | hoedown_free_callback data_free; 38 | hoedown_free_callback buffer_free; 39 | }; 40 | 41 | typedef struct hoedown_buffer hoedown_buffer; 42 | 43 | 44 | /************* 45 | * FUNCTIONS * 46 | *************/ 47 | 48 | /* allocation wrappers */ 49 | void *hoedown_malloc(size_t size) __attribute__ ((malloc)); 50 | void *hoedown_calloc(size_t nmemb, size_t size) __attribute__ ((malloc)); 51 | void *hoedown_realloc(void *ptr, size_t size) __attribute__ ((malloc)); 52 | 53 | /* hoedown_buffer_init: initialize a buffer with custom allocators */ 54 | void hoedown_buffer_init( 55 | hoedown_buffer *buffer, 56 | size_t unit, 57 | hoedown_realloc_callback data_realloc, 58 | hoedown_free_callback data_free, 59 | hoedown_free_callback buffer_free 60 | ); 61 | 62 | /* hoedown_buffer_uninit: uninitialize an existing buffer */ 63 | void hoedown_buffer_uninit(hoedown_buffer *buf); 64 | 65 | /* hoedown_buffer_new: allocate a new buffer */ 66 | hoedown_buffer *hoedown_buffer_new(size_t unit) __attribute__ ((malloc)); 67 | 68 | /* hoedown_buffer_reset: free internal data of the buffer */ 69 | void hoedown_buffer_reset(hoedown_buffer *buf); 70 | 71 | /* hoedown_buffer_grow: increase the allocated size to the given value */ 72 | void hoedown_buffer_grow(hoedown_buffer *buf, size_t neosz); 73 | 74 | /* hoedown_buffer_put: append raw data to a buffer */ 75 | void hoedown_buffer_put(hoedown_buffer *buf, const uint8_t *data, size_t size); 76 | 77 | /* hoedown_buffer_puts: append a NUL-terminated string to a buffer */ 78 | void hoedown_buffer_puts(hoedown_buffer *buf, const char *str); 79 | 80 | /* hoedown_buffer_putc: append a single char to a buffer */ 81 | void hoedown_buffer_putc(hoedown_buffer *buf, uint8_t c); 82 | 83 | /* hoedown_buffer_putf: read from a file and append to a buffer, until EOF or error */ 84 | int hoedown_buffer_putf(hoedown_buffer *buf, FILE* file); 85 | 86 | /* hoedown_buffer_set: replace the buffer's contents with raw data */ 87 | void hoedown_buffer_set(hoedown_buffer *buf, const uint8_t *data, size_t size); 88 | 89 | /* hoedown_buffer_sets: replace the buffer's contents with a NUL-terminated string */ 90 | void hoedown_buffer_sets(hoedown_buffer *buf, const char *str); 91 | 92 | /* hoedown_buffer_eq: compare a buffer's data with other data for equality */ 93 | int hoedown_buffer_eq(const hoedown_buffer *buf, const uint8_t *data, size_t size); 94 | 95 | /* hoedown_buffer_eq: compare a buffer's data with NUL-terminated string for equality */ 96 | int hoedown_buffer_eqs(const hoedown_buffer *buf, const char *str); 97 | 98 | /* hoedown_buffer_prefix: compare the beginning of a buffer with a string */ 99 | int hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix); 100 | 101 | /* hoedown_buffer_slurp: remove a given number of bytes from the head of the buffer */ 102 | void hoedown_buffer_slurp(hoedown_buffer *buf, size_t size); 103 | 104 | /* hoedown_buffer_cstr: NUL-termination of the string array (making a C-string) */ 105 | const char *hoedown_buffer_cstr(hoedown_buffer *buf); 106 | 107 | /* hoedown_buffer_printf: formatted printing to a buffer */ 108 | void hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); 109 | 110 | /* hoedown_buffer_put_utf8: put a Unicode character encoded as UTF-8 */ 111 | void hoedown_buffer_put_utf8(hoedown_buffer *buf, unsigned int codepoint); 112 | 113 | /* hoedown_buffer_free: free the buffer */ 114 | void hoedown_buffer_free(hoedown_buffer *buf); 115 | 116 | 117 | /* HOEDOWN_BUFPUTSL: optimized hoedown_buffer_puts of a string literal */ 118 | #define HOEDOWN_BUFPUTSL(output, literal) \ 119 | hoedown_buffer_put(output, (const uint8_t *)literal, sizeof(literal) - 1) 120 | 121 | /* HOEDOWN_BUFSETSL: optimized hoedown_buffer_sets of a string literal */ 122 | #define HOEDOWN_BUFSETSL(output, literal) \ 123 | hoedown_buffer_set(output, (const uint8_t *)literal, sizeof(literal) - 1) 124 | 125 | /* HOEDOWN_BUFEQSL: optimized hoedown_buffer_eqs of a string literal */ 126 | #define HOEDOWN_BUFEQSL(output, literal) \ 127 | hoedown_buffer_eq(output, (const uint8_t *)literal, sizeof(literal) - 1) 128 | 129 | 130 | #ifdef __cplusplus 131 | } 132 | #endif 133 | 134 | #endif /** HOEDOWN_BUFFER_H **/ 135 | -------------------------------------------------------------------------------- /src/escape.c: -------------------------------------------------------------------------------- 1 | #include "escape.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | #define likely(x) __builtin_expect((x),1) 9 | #define unlikely(x) __builtin_expect((x),0) 10 | 11 | 12 | /* 13 | * The following characters will not be escaped: 14 | * 15 | * -_.+!*'(),%#@?=;:/,+&$ alphanum 16 | * 17 | * Note that this character set is the addition of: 18 | * 19 | * - The characters which are safe to be in an URL 20 | * - The characters which are *not* safe to be in 21 | * an URL because they are RESERVED characters. 22 | * 23 | * We assume (lazily) that any RESERVED char that 24 | * appears inside an URL is actually meant to 25 | * have its native function (i.e. as an URL 26 | * component/separator) and hence needs no escaping. 27 | * 28 | * There are two exceptions: the chacters & (amp) 29 | * and ' (single quote) do not appear in the table. 30 | * They are meant to appear in the URL as components, 31 | * yet they require special HTML-entity escaping 32 | * to generate valid HTML markup. 33 | * 34 | * All other characters will be escaped to %XX. 35 | * 36 | */ 37 | static const uint8_t HREF_SAFE[UINT8_MAX+1] = { 38 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40 | 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 41 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 42 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 43 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 44 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 46 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54 | }; 55 | 56 | void 57 | hoedown_escape_href(hoedown_buffer *ob, const uint8_t *data, size_t size) 58 | { 59 | static const char hex_chars[] = "0123456789ABCDEF"; 60 | size_t i = 0, mark; 61 | char hex_str[3]; 62 | 63 | hex_str[0] = '%'; 64 | 65 | while (i < size) { 66 | mark = i; 67 | while (i < size && HREF_SAFE[data[i]]) i++; 68 | 69 | /* Optimization for cases where there's nothing to escape */ 70 | if (mark == 0 && i >= size) { 71 | hoedown_buffer_put(ob, data, size); 72 | return; 73 | } 74 | 75 | if (likely(i > mark)) { 76 | hoedown_buffer_put(ob, data + mark, i - mark); 77 | } 78 | 79 | /* escaping */ 80 | if (i >= size) 81 | break; 82 | 83 | switch (data[i]) { 84 | /* amp appears all the time in URLs, but needs 85 | * HTML-entity escaping to be inside an href */ 86 | case '&': 87 | HOEDOWN_BUFPUTSL(ob, "&"); 88 | break; 89 | 90 | /* the single quote is a valid URL character 91 | * according to the standard; it needs HTML 92 | * entity escaping too */ 93 | case '\'': 94 | HOEDOWN_BUFPUTSL(ob, "'"); 95 | break; 96 | 97 | /* the space can be escaped to %20 or a plus 98 | * sign. we're going with the generic escape 99 | * for now. the plus thing is more commonly seen 100 | * when building GET strings */ 101 | #if 0 102 | case ' ': 103 | hoedown_buffer_putc(ob, '+'); 104 | break; 105 | #endif 106 | 107 | /* every other character goes with a %XX escaping */ 108 | default: 109 | hex_str[1] = hex_chars[(data[i] >> 4) & 0xF]; 110 | hex_str[2] = hex_chars[data[i] & 0xF]; 111 | hoedown_buffer_put(ob, (uint8_t *)hex_str, 3); 112 | } 113 | 114 | i++; 115 | } 116 | } 117 | 118 | 119 | /** 120 | * According to the OWASP rules: 121 | * 122 | * & --> & 123 | * < --> < 124 | * > --> > 125 | * " --> " 126 | * ' --> ' ' is not recommended 127 | * / --> / forward slash is included as it helps end an HTML entity 128 | * 129 | */ 130 | static const uint8_t HTML_ESCAPE_TABLE[UINT8_MAX+1] = { 131 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133 | 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4, 134 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, 135 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147 | }; 148 | 149 | static const char *HTML_ESCAPES[] = { 150 | "", 151 | """, 152 | "&", 153 | "'", 154 | "/", 155 | "<", 156 | ">" 157 | }; 158 | 159 | void 160 | hoedown_escape_html(hoedown_buffer *ob, const uint8_t *data, size_t size, int secure) 161 | { 162 | size_t i = 0, mark; 163 | 164 | while (1) { 165 | mark = i; 166 | while (i < size && HTML_ESCAPE_TABLE[data[i]] == 0) i++; 167 | 168 | /* Optimization for cases where there's nothing to escape */ 169 | if (mark == 0 && i >= size) { 170 | hoedown_buffer_put(ob, data, size); 171 | return; 172 | } 173 | 174 | if (likely(i > mark)) 175 | hoedown_buffer_put(ob, data + mark, i - mark); 176 | 177 | if (i >= size) break; 178 | 179 | /* The forward slash is only escaped in secure mode */ 180 | if (!secure && data[i] == '/') { 181 | hoedown_buffer_putc(ob, '/'); 182 | } else { 183 | hoedown_buffer_puts(ob, HTML_ESCAPES[HTML_ESCAPE_TABLE[data[i]]]); 184 | } 185 | 186 | i++; 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /bin/smartypants.c: -------------------------------------------------------------------------------- 1 | #include "html.h" 2 | 3 | #include "common.h" 4 | /*#include */ 5 | 6 | 7 | /* FEATURES INFO / DEFAULTS */ 8 | 9 | #define DEF_IUNIT 1024 10 | #define DEF_OUNIT 64 11 | 12 | 13 | /* PRINT HELP */ 14 | 15 | void 16 | print_help(const char *basename) 17 | { 18 | /* usage */ 19 | printf("Usage: %s [OPTION]... [FILE]\n\n", basename); 20 | 21 | /* description */ 22 | printf("Apply SmartyPants smart punctuation to the HTML in FILE (or standard input), and output the resulting HTML to standard output.\n\n"); 23 | 24 | /* main options */ 25 | printf("Main options:\n"); 26 | print_option('T', "time", "Show time spent in SmartyPants processing."); 27 | print_option('i', "input-unit=N", "Reading block size. Default is " str(DEF_IUNIT) "."); 28 | print_option('o', "output-unit=N", "Writing block size. Default is " str(DEF_OUNIT) "."); 29 | print_option('h', "help", "Print this help text."); 30 | print_option('v', "version", "Print Hoedown version."); 31 | printf("\n"); 32 | 33 | /* ending */ 34 | printf("Options are processed in order, so in case of contradictory options the last specified stands.\n\n"); 35 | 36 | printf("When FILE is '-', read standard input. If no FILE was given, read standard input. Use '--' to signal end of option parsing. " 37 | "Exit status is 0 if no errors occurred, 1 with option parsing errors, 4 with memory allocation errors or 5 with I/O errors.\n\n"); 38 | } 39 | 40 | 41 | /* OPTION PARSING */ 42 | 43 | struct option_data { 44 | char *basename; 45 | int done; 46 | 47 | /* time reporting */ 48 | int show_time; 49 | 50 | /* I/O */ 51 | size_t iunit; 52 | size_t ounit; 53 | const char *filename; 54 | }; 55 | 56 | int 57 | parse_short_option(char opt, char *next, void *opaque) 58 | { 59 | struct option_data *data = opaque; 60 | long int num; 61 | int isNum = next ? parseint(next, &num) : 0; 62 | 63 | if (opt == 'h') { 64 | print_help(data->basename); 65 | data->done = 1; 66 | return 0; 67 | } 68 | 69 | if (opt == 'v') { 70 | print_version(); 71 | data->done = 1; 72 | return 0; 73 | } 74 | 75 | if (opt == 'T') { 76 | data->show_time = 1; 77 | return 1; 78 | } 79 | 80 | /* options requiring value */ 81 | /* FIXME: add validation */ 82 | 83 | if (opt == 'i' && isNum) { 84 | data->iunit = num; 85 | return 2; 86 | } 87 | 88 | if (opt == 'o' && isNum) { 89 | data->ounit = num; 90 | return 2; 91 | } 92 | 93 | fprintf(stderr, "Wrong option '-%c' found.\n", opt); 94 | return 0; 95 | } 96 | 97 | int 98 | parse_long_option(char *opt, char *next, void *opaque) 99 | { 100 | struct option_data *data = opaque; 101 | long int num; 102 | int isNum = next ? parseint(next, &num) : 0; 103 | 104 | if (strcmp(opt, "help")==0) { 105 | print_help(data->basename); 106 | data->done = 1; 107 | return 0; 108 | } 109 | 110 | if (strcmp(opt, "version")==0) { 111 | print_version(); 112 | data->done = 1; 113 | return 0; 114 | } 115 | 116 | if (strcmp(opt, "time")==0) { 117 | data->show_time = 1; 118 | return 1; 119 | } 120 | 121 | /* FIXME: validation */ 122 | 123 | if (strcmp(opt, "input-unit")==0 && isNum) { 124 | data->iunit = num; 125 | return 2; 126 | } 127 | if (strcmp(opt, "output-unit")==0 && isNum) { 128 | data->ounit = num; 129 | return 2; 130 | } 131 | 132 | fprintf(stderr, "Wrong option '--%s' found.\n", opt); 133 | return 0; 134 | } 135 | 136 | int 137 | parse_argument(int argn, char *arg, int is_forced, void *opaque) 138 | { 139 | struct option_data *data = opaque; 140 | 141 | if (argn == 0) { 142 | /* Input file */ 143 | if (strcmp(arg, "-")!=0 || is_forced) data->filename = arg; 144 | return 1; 145 | } 146 | 147 | fprintf(stderr, "Too many arguments.\n"); 148 | return 0; 149 | } 150 | 151 | 152 | /* MAIN LOGIC */ 153 | 154 | int 155 | main(int argc, char **argv) 156 | { 157 | struct option_data data; 158 | /*struct timespec start, end;*/ 159 | FILE *file = stdin; 160 | hoedown_buffer *ib, *ob; 161 | 162 | /* Parse options */ 163 | data.basename = argv[0]; 164 | data.done = 0; 165 | data.show_time = 0; 166 | data.iunit = DEF_IUNIT; 167 | data.ounit = DEF_OUNIT; 168 | data.filename = NULL; 169 | 170 | argc = parse_options(argc, argv, parse_short_option, parse_long_option, parse_argument, &data); 171 | if (data.done) return 0; 172 | if (!argc) return 1; 173 | 174 | /* Open input file, if needed */ 175 | if (data.filename) { 176 | file = fopen(data.filename, "r"); 177 | if (!file) { 178 | fprintf(stderr, "Unable to open input file \"%s\": %s\n", data.filename, strerror(errno)); 179 | return 5; 180 | } 181 | } 182 | 183 | /* Read everything */ 184 | ib = hoedown_buffer_new(data.iunit); 185 | 186 | while (!feof(file)) { 187 | if (ferror(file)) { 188 | fprintf(stderr, "I/O errors found while reading input.\n"); 189 | return 5; 190 | } 191 | hoedown_buffer_grow(ib, ib->size + data.iunit); 192 | ib->size += fread(ib->data + ib->size, 1, data.iunit, file); 193 | } 194 | 195 | if (file != stdin) fclose(file); 196 | 197 | /* Perform SmartyPants processing */ 198 | ob = hoedown_buffer_new(data.ounit); 199 | 200 | /*clock_gettime(CLOCK_MONOTONIC, &start);*/ 201 | hoedown_html_smartypants(ob, ib->data, ib->size); 202 | /*clock_gettime(CLOCK_MONOTONIC, &end);*/ 203 | 204 | /* Write the result to stdout */ 205 | (void)fwrite(ob->data, 1, ob->size, stdout); 206 | 207 | /* Show rendering time */ 208 | if (data.show_time) { 209 | /*TODO: enable this 210 | long long elapsed = (end.tv_sec - start.tv_sec)*1e9 + (end.tv_nsec - start.tv_nsec); 211 | if (elapsed < 1e9) 212 | fprintf(stderr, "Time spent on rendering: %.2f ms.\n", ((double)elapsed)/1e6); 213 | else 214 | fprintf(stderr, "Time spent on rendering: %.3f s.\n", ((double)elapsed)/1e9); 215 | */ 216 | } 217 | 218 | /* Cleanup */ 219 | hoedown_buffer_free(ib); 220 | hoedown_buffer_free(ob); 221 | 222 | if (ferror(stdout)) { 223 | fprintf(stderr, "I/O errors found while writing output.\n"); 224 | return 5; 225 | } 226 | 227 | return 0; 228 | } 229 | -------------------------------------------------------------------------------- /src/autolink.c: -------------------------------------------------------------------------------- 1 | #include "autolink.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #ifndef _MSC_VER 9 | #include 10 | #else 11 | #define strncasecmp _strnicmp 12 | #endif 13 | 14 | int 15 | hoedown_autolink_is_safe(const uint8_t *data, size_t size) 16 | { 17 | static const size_t valid_uris_count = 6; 18 | static const char *valid_uris[] = { 19 | "http://", "https://", "/", "#", "ftp://", "mailto:" 20 | }; 21 | static const size_t valid_uris_size[] = { 7, 8, 1, 1, 6, 7 }; 22 | size_t i; 23 | 24 | for (i = 0; i < valid_uris_count; ++i) { 25 | size_t len = valid_uris_size[i]; 26 | 27 | if (size > len && 28 | strncasecmp((char *)data, valid_uris[i], len) == 0 && 29 | isalnum(data[len])) 30 | return 1; 31 | } 32 | 33 | return 0; 34 | } 35 | 36 | static size_t 37 | autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size) 38 | { 39 | uint8_t cclose, copen = 0; 40 | size_t i; 41 | 42 | for (i = 0; i < link_end; ++i) 43 | if (data[i] == '<') { 44 | link_end = i; 45 | break; 46 | } 47 | 48 | while (link_end > 0) { 49 | if (strchr("?!.,:", data[link_end - 1]) != NULL) 50 | link_end--; 51 | 52 | else if (data[link_end - 1] == ';') { 53 | size_t new_end = link_end - 2; 54 | 55 | while (new_end > 0 && isalpha(data[new_end])) 56 | new_end--; 57 | 58 | if (new_end < link_end - 2 && data[new_end] == '&') 59 | link_end = new_end; 60 | else 61 | link_end--; 62 | } 63 | else break; 64 | } 65 | 66 | if (link_end == 0) 67 | return 0; 68 | 69 | cclose = data[link_end - 1]; 70 | 71 | switch (cclose) { 72 | case '"': copen = '"'; break; 73 | case '\'': copen = '\''; break; 74 | case ')': copen = '('; break; 75 | case ']': copen = '['; break; 76 | case '}': copen = '{'; break; 77 | } 78 | 79 | if (copen != 0) { 80 | size_t closing = 0; 81 | size_t opening = 0; 82 | size_t i = 0; 83 | 84 | /* Try to close the final punctuation sign in this same line; 85 | * if we managed to close it outside of the URL, that means that it's 86 | * not part of the URL. If it closes inside the URL, that means it 87 | * is part of the URL. 88 | * 89 | * Examples: 90 | * 91 | * foo http://www.pokemon.com/Pikachu_(Electric) bar 92 | * => http://www.pokemon.com/Pikachu_(Electric) 93 | * 94 | * foo (http://www.pokemon.com/Pikachu_(Electric)) bar 95 | * => http://www.pokemon.com/Pikachu_(Electric) 96 | * 97 | * foo http://www.pokemon.com/Pikachu_(Electric)) bar 98 | * => http://www.pokemon.com/Pikachu_(Electric)) 99 | * 100 | * (foo http://www.pokemon.com/Pikachu_(Electric)) bar 101 | * => foo http://www.pokemon.com/Pikachu_(Electric) 102 | */ 103 | 104 | while (i < link_end) { 105 | if (data[i] == copen) 106 | opening++; 107 | else if (data[i] == cclose) 108 | closing++; 109 | 110 | i++; 111 | } 112 | 113 | if (closing != opening) 114 | link_end--; 115 | } 116 | 117 | return link_end; 118 | } 119 | 120 | static size_t 121 | check_domain(uint8_t *data, size_t size, int allow_short) 122 | { 123 | size_t i, np = 0; 124 | 125 | if (!isalnum(data[0])) 126 | return 0; 127 | 128 | for (i = 1; i < size - 1; ++i) { 129 | if (strchr(".:", data[i]) != NULL) np++; 130 | else if (!isalnum(data[i]) && data[i] != '-') break; 131 | } 132 | 133 | if (allow_short) { 134 | /* We don't need a valid domain in the strict sense (with 135 | * least one dot; so just make sure it's composed of valid 136 | * domain characters and return the length of the the valid 137 | * sequence. */ 138 | return i; 139 | } else { 140 | /* a valid domain needs to have at least a dot. 141 | * that's as far as we get */ 142 | return np ? i : 0; 143 | } 144 | } 145 | 146 | size_t 147 | hoedown_autolink__www( 148 | size_t *rewind_p, 149 | hoedown_buffer *link, 150 | uint8_t *data, 151 | size_t max_rewind, 152 | size_t size, 153 | unsigned int flags) 154 | { 155 | size_t link_end; 156 | 157 | if (max_rewind > 0 && !ispunct(data[-1]) && !isspace(data[-1])) 158 | return 0; 159 | 160 | if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0) 161 | return 0; 162 | 163 | link_end = check_domain(data, size, 0); 164 | 165 | if (link_end == 0) 166 | return 0; 167 | 168 | while (link_end < size && !isspace(data[link_end])) 169 | link_end++; 170 | 171 | link_end = autolink_delim(data, link_end, max_rewind, size); 172 | 173 | if (link_end == 0) 174 | return 0; 175 | 176 | hoedown_buffer_put(link, data, link_end); 177 | *rewind_p = 0; 178 | 179 | return (int)link_end; 180 | } 181 | 182 | size_t 183 | hoedown_autolink__email( 184 | size_t *rewind_p, 185 | hoedown_buffer *link, 186 | uint8_t *data, 187 | size_t max_rewind, 188 | size_t size, 189 | unsigned int flags) 190 | { 191 | size_t link_end, rewind; 192 | int nb = 0, np = 0; 193 | 194 | for (rewind = 0; rewind < max_rewind; ++rewind) { 195 | uint8_t c = data[-1 - rewind]; 196 | 197 | if (isalnum(c)) 198 | continue; 199 | 200 | if (strchr(".+-_", c) != NULL) 201 | continue; 202 | 203 | break; 204 | } 205 | 206 | if (rewind == 0) 207 | return 0; 208 | 209 | for (link_end = 0; link_end < size; ++link_end) { 210 | uint8_t c = data[link_end]; 211 | 212 | if (isalnum(c)) 213 | continue; 214 | 215 | if (c == '@') 216 | nb++; 217 | else if (c == '.' && link_end < size - 1) 218 | np++; 219 | else if (c != '-' && c != '_') 220 | break; 221 | } 222 | 223 | if (link_end < 2 || nb != 1 || np == 0 || 224 | !isalpha(data[link_end - 1])) 225 | return 0; 226 | 227 | link_end = autolink_delim(data, link_end, max_rewind, size); 228 | 229 | if (link_end == 0) 230 | return 0; 231 | 232 | hoedown_buffer_put(link, data - rewind, link_end + rewind); 233 | *rewind_p = rewind; 234 | 235 | return link_end; 236 | } 237 | 238 | size_t 239 | hoedown_autolink__url( 240 | size_t *rewind_p, 241 | hoedown_buffer *link, 242 | uint8_t *data, 243 | size_t max_rewind, 244 | size_t size, 245 | unsigned int flags) 246 | { 247 | size_t link_end, rewind = 0, domain_len; 248 | 249 | if (size < 4 || data[1] != '/' || data[2] != '/') 250 | return 0; 251 | 252 | while (rewind < max_rewind && isalpha(data[-1 - rewind])) 253 | rewind++; 254 | 255 | if (!hoedown_autolink_is_safe(data - rewind, size + rewind)) 256 | return 0; 257 | 258 | link_end = strlen("://"); 259 | 260 | domain_len = check_domain( 261 | data + link_end, 262 | size - link_end, 263 | flags & HOEDOWN_AUTOLINK_SHORT_DOMAINS); 264 | 265 | if (domain_len == 0) 266 | return 0; 267 | 268 | link_end += domain_len; 269 | while (link_end < size && !isspace(data[link_end])) 270 | link_end++; 271 | 272 | link_end = autolink_delim(data, link_end, max_rewind, size); 273 | 274 | if (link_end == 0) 275 | return 0; 276 | 277 | hoedown_buffer_put(link, data - rewind, link_end + rewind); 278 | *rewind_p = rewind; 279 | 280 | return link_end; 281 | } 282 | -------------------------------------------------------------------------------- /src/buffer.c: -------------------------------------------------------------------------------- 1 | #include "buffer.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void * 9 | hoedown_malloc(size_t size) 10 | { 11 | void *ret = malloc(size); 12 | 13 | if (!ret) { 14 | fprintf(stderr, "Allocation failed.\n"); 15 | abort(); 16 | } 17 | 18 | return ret; 19 | } 20 | 21 | void * 22 | hoedown_calloc(size_t nmemb, size_t size) 23 | { 24 | void *ret = calloc(nmemb, size); 25 | 26 | if (!ret) { 27 | fprintf(stderr, "Allocation failed.\n"); 28 | abort(); 29 | } 30 | 31 | return ret; 32 | } 33 | 34 | void * 35 | hoedown_realloc(void *ptr, size_t size) 36 | { 37 | void *ret = realloc(ptr, size); 38 | 39 | if (!ret) { 40 | fprintf(stderr, "Allocation failed.\n"); 41 | abort(); 42 | } 43 | 44 | return ret; 45 | } 46 | 47 | void 48 | hoedown_buffer_init( 49 | hoedown_buffer *buf, 50 | size_t unit, 51 | hoedown_realloc_callback data_realloc, 52 | hoedown_free_callback data_free, 53 | hoedown_free_callback buffer_free) 54 | { 55 | assert(buf); 56 | 57 | buf->data = NULL; 58 | buf->size = buf->asize = 0; 59 | buf->unit = unit; 60 | buf->data_realloc = data_realloc; 61 | buf->data_free = data_free; 62 | buf->buffer_free = buffer_free; 63 | } 64 | 65 | void 66 | hoedown_buffer_uninit(hoedown_buffer *buf) 67 | { 68 | assert(buf && buf->unit); 69 | buf->data_free(buf->data); 70 | } 71 | 72 | hoedown_buffer * 73 | hoedown_buffer_new(size_t unit) 74 | { 75 | hoedown_buffer *ret = hoedown_malloc(sizeof (hoedown_buffer)); 76 | hoedown_buffer_init(ret, unit, hoedown_realloc, free, free); 77 | return ret; 78 | } 79 | 80 | void 81 | hoedown_buffer_free(hoedown_buffer *buf) 82 | { 83 | if (!buf) return; 84 | assert(buf && buf->unit); 85 | 86 | buf->data_free(buf->data); 87 | 88 | if (buf->buffer_free) 89 | buf->buffer_free(buf); 90 | } 91 | 92 | void 93 | hoedown_buffer_reset(hoedown_buffer *buf) 94 | { 95 | assert(buf && buf->unit); 96 | 97 | buf->data_free(buf->data); 98 | buf->data = NULL; 99 | buf->size = buf->asize = 0; 100 | } 101 | 102 | void 103 | hoedown_buffer_grow(hoedown_buffer *buf, size_t neosz) 104 | { 105 | size_t neoasz; 106 | assert(buf && buf->unit); 107 | 108 | if (buf->asize >= neosz) 109 | return; 110 | 111 | neoasz = buf->asize + buf->unit; 112 | while (neoasz < neosz) 113 | neoasz += buf->unit; 114 | 115 | buf->data = buf->data_realloc(buf->data, neoasz); 116 | buf->asize = neoasz; 117 | } 118 | 119 | void 120 | hoedown_buffer_put(hoedown_buffer *buf, const uint8_t *data, size_t size) 121 | { 122 | assert(buf && buf->unit); 123 | 124 | if (buf->size + size > buf->asize) 125 | hoedown_buffer_grow(buf, buf->size + size); 126 | 127 | memcpy(buf->data + buf->size, data, size); 128 | buf->size += size; 129 | } 130 | 131 | void 132 | hoedown_buffer_puts(hoedown_buffer *buf, const char *str) 133 | { 134 | hoedown_buffer_put(buf, (const uint8_t *)str, strlen(str)); 135 | } 136 | 137 | void 138 | hoedown_buffer_putc(hoedown_buffer *buf, uint8_t c) 139 | { 140 | assert(buf && buf->unit); 141 | 142 | if (buf->size >= buf->asize) 143 | hoedown_buffer_grow(buf, buf->size + 1); 144 | 145 | buf->data[buf->size] = c; 146 | buf->size += 1; 147 | } 148 | 149 | int 150 | hoedown_buffer_putf(hoedown_buffer *buf, FILE *file) 151 | { 152 | assert(buf && buf->unit); 153 | 154 | while (!(feof(file) || ferror(file))) { 155 | hoedown_buffer_grow(buf, buf->size + buf->unit); 156 | buf->size += fread(buf->data + buf->size, 1, buf->unit, file); 157 | } 158 | 159 | return ferror(file); 160 | } 161 | 162 | void 163 | hoedown_buffer_set(hoedown_buffer *buf, const uint8_t *data, size_t size) 164 | { 165 | assert(buf && buf->unit); 166 | 167 | if (size > buf->asize) 168 | hoedown_buffer_grow(buf, size); 169 | 170 | memcpy(buf->data, data, size); 171 | buf->size = size; 172 | } 173 | 174 | void 175 | hoedown_buffer_sets(hoedown_buffer *buf, const char *str) 176 | { 177 | hoedown_buffer_set(buf, (const uint8_t *)str, strlen(str)); 178 | } 179 | 180 | int 181 | hoedown_buffer_eq(const hoedown_buffer *buf, const uint8_t *data, size_t size) 182 | { 183 | if (buf->size != size) return 0; 184 | return memcmp(buf->data, data, size) == 0; 185 | } 186 | 187 | int 188 | hoedown_buffer_eqs(const hoedown_buffer *buf, const char *str) 189 | { 190 | return hoedown_buffer_eq(buf, (const uint8_t *)str, strlen(str)); 191 | } 192 | 193 | int 194 | hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix) 195 | { 196 | size_t i; 197 | 198 | for (i = 0; i < buf->size; ++i) { 199 | if (prefix[i] == 0) 200 | return 0; 201 | 202 | if (buf->data[i] != prefix[i]) 203 | return buf->data[i] - prefix[i]; 204 | } 205 | 206 | return 0; 207 | } 208 | 209 | void 210 | hoedown_buffer_slurp(hoedown_buffer *buf, size_t size) 211 | { 212 | assert(buf && buf->unit); 213 | 214 | if (size >= buf->size) { 215 | buf->size = 0; 216 | return; 217 | } 218 | 219 | buf->size -= size; 220 | memmove(buf->data, buf->data + size, buf->size); 221 | } 222 | 223 | const char * 224 | hoedown_buffer_cstr(hoedown_buffer *buf) 225 | { 226 | assert(buf && buf->unit); 227 | 228 | if (buf->size < buf->asize && buf->data[buf->size] == 0) 229 | return (char *)buf->data; 230 | 231 | hoedown_buffer_grow(buf, buf->size + 1); 232 | buf->data[buf->size] = 0; 233 | 234 | return (char *)buf->data; 235 | } 236 | 237 | void 238 | hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...) 239 | { 240 | va_list ap; 241 | int n; 242 | 243 | assert(buf && buf->unit); 244 | 245 | if (buf->size >= buf->asize) 246 | hoedown_buffer_grow(buf, buf->size + 1); 247 | 248 | va_start(ap, fmt); 249 | n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap); 250 | va_end(ap); 251 | 252 | if (n < 0) { 253 | #ifndef _MSC_VER 254 | return; 255 | #else 256 | va_start(ap, fmt); 257 | n = _vscprintf(fmt, ap); 258 | va_end(ap); 259 | #endif 260 | } 261 | 262 | if ((size_t)n >= buf->asize - buf->size) { 263 | hoedown_buffer_grow(buf, buf->size + n + 1); 264 | 265 | va_start(ap, fmt); 266 | n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap); 267 | va_end(ap); 268 | } 269 | 270 | if (n < 0) 271 | return; 272 | 273 | buf->size += n; 274 | } 275 | 276 | void hoedown_buffer_put_utf8(hoedown_buffer *buf, unsigned int c) { 277 | unsigned char unichar[4]; 278 | 279 | assert(buf && buf->unit); 280 | 281 | if (c < 0x80) { 282 | hoedown_buffer_putc(buf, c); 283 | } 284 | else if (c < 0x800) { 285 | unichar[0] = 192 + (c / 64); 286 | unichar[1] = 128 + (c % 64); 287 | hoedown_buffer_put(buf, unichar, 2); 288 | } 289 | else if (c - 0xd800u < 0x800) { 290 | HOEDOWN_BUFPUTSL(buf, "\xef\xbf\xbd"); 291 | } 292 | else if (c < 0x10000) { 293 | unichar[0] = 224 + (c / 4096); 294 | unichar[1] = 128 + (c / 64) % 64; 295 | unichar[2] = 128 + (c % 64); 296 | hoedown_buffer_put(buf, unichar, 3); 297 | } 298 | else if (c < 0x110000) { 299 | unichar[0] = 240 + (c / 262144); 300 | unichar[1] = 128 + (c / 4096) % 64; 301 | unichar[2] = 128 + (c / 64) % 64; 302 | unichar[3] = 128 + (c % 64); 303 | hoedown_buffer_put(buf, unichar, 4); 304 | } 305 | else { 306 | HOEDOWN_BUFPUTSL(buf, "\xef\xbf\xbd"); 307 | } 308 | } 309 | -------------------------------------------------------------------------------- /src/document.h: -------------------------------------------------------------------------------- 1 | /* document.h - generic markdown parser */ 2 | 3 | #ifndef HOEDOWN_DOCUMENT_H 4 | #define HOEDOWN_DOCUMENT_H 5 | 6 | #include "buffer.h" 7 | #include "autolink.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | 14 | /************* 15 | * CONSTANTS * 16 | *************/ 17 | 18 | typedef enum hoedown_extensions { 19 | /* block-level extensions */ 20 | HOEDOWN_EXT_TABLES = (1 << 0), 21 | HOEDOWN_EXT_FENCED_CODE = (1 << 1), 22 | HOEDOWN_EXT_FOOTNOTES = (1 << 2), 23 | 24 | /* span-level extensions */ 25 | HOEDOWN_EXT_AUTOLINK = (1 << 3), 26 | HOEDOWN_EXT_STRIKETHROUGH = (1 << 4), 27 | HOEDOWN_EXT_UNDERLINE = (1 << 5), 28 | HOEDOWN_EXT_HIGHLIGHT = (1 << 6), 29 | HOEDOWN_EXT_QUOTE = (1 << 7), 30 | HOEDOWN_EXT_SUPERSCRIPT = (1 << 8), 31 | HOEDOWN_EXT_MATH = (1 << 9), 32 | 33 | /* other flags */ 34 | HOEDOWN_EXT_NO_INTRA_EMPHASIS = (1 << 11), 35 | HOEDOWN_EXT_SPACE_HEADERS = (1 << 12), 36 | HOEDOWN_EXT_MATH_EXPLICIT = (1 << 13), 37 | 38 | /* negative flags */ 39 | HOEDOWN_EXT_DISABLE_INDENTED_CODE = (1 << 14) 40 | } hoedown_extensions; 41 | 42 | #define HOEDOWN_EXT_BLOCK (\ 43 | HOEDOWN_EXT_TABLES |\ 44 | HOEDOWN_EXT_FENCED_CODE |\ 45 | HOEDOWN_EXT_FOOTNOTES ) 46 | 47 | #define HOEDOWN_EXT_SPAN (\ 48 | HOEDOWN_EXT_AUTOLINK |\ 49 | HOEDOWN_EXT_STRIKETHROUGH |\ 50 | HOEDOWN_EXT_UNDERLINE |\ 51 | HOEDOWN_EXT_HIGHLIGHT |\ 52 | HOEDOWN_EXT_QUOTE |\ 53 | HOEDOWN_EXT_SUPERSCRIPT |\ 54 | HOEDOWN_EXT_MATH ) 55 | 56 | #define HOEDOWN_EXT_FLAGS (\ 57 | HOEDOWN_EXT_NO_INTRA_EMPHASIS |\ 58 | HOEDOWN_EXT_SPACE_HEADERS |\ 59 | HOEDOWN_EXT_MATH_EXPLICIT ) 60 | 61 | #define HOEDOWN_EXT_NEGATIVE (\ 62 | HOEDOWN_EXT_DISABLE_INDENTED_CODE ) 63 | 64 | typedef enum hoedown_list_flags { 65 | HOEDOWN_LIST_ORDERED = (1 << 0), 66 | HOEDOWN_LI_BLOCK = (1 << 1) /*
  • containing block data */ 67 | } hoedown_list_flags; 68 | 69 | typedef enum hoedown_table_flags { 70 | HOEDOWN_TABLE_ALIGN_LEFT = 1, 71 | HOEDOWN_TABLE_ALIGN_RIGHT = 2, 72 | HOEDOWN_TABLE_ALIGN_CENTER = 3, 73 | HOEDOWN_TABLE_ALIGNMASK = 3, 74 | HOEDOWN_TABLE_HEADER = 4 75 | } hoedown_table_flags; 76 | 77 | typedef enum hoedown_autolink_type { 78 | HOEDOWN_AUTOLINK_NONE, /* used internally when it is not an autolink*/ 79 | HOEDOWN_AUTOLINK_NORMAL, /* normal http/http/ftp/mailto/etc link */ 80 | HOEDOWN_AUTOLINK_EMAIL /* e-mail link without explit mailto: */ 81 | } hoedown_autolink_type; 82 | 83 | 84 | /********* 85 | * TYPES * 86 | *********/ 87 | 88 | struct hoedown_document; 89 | typedef struct hoedown_document hoedown_document; 90 | 91 | struct hoedown_renderer_data { 92 | void *opaque; 93 | }; 94 | typedef struct hoedown_renderer_data hoedown_renderer_data; 95 | 96 | /* hoedown_renderer - functions for rendering parsed data */ 97 | struct hoedown_renderer { 98 | /* state object */ 99 | void *opaque; 100 | 101 | /* block level callbacks - NULL skips the block */ 102 | void (*blockcode)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data); 103 | void (*blockquote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 104 | void (*header)(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data); 105 | void (*hrule)(hoedown_buffer *ob, const hoedown_renderer_data *data); 106 | void (*list)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data); 107 | void (*listitem)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data); 108 | void (*paragraph)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 109 | void (*table)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 110 | void (*table_header)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 111 | void (*table_body)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 112 | void (*table_row)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 113 | void (*table_cell)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data); 114 | void (*footnotes)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 115 | void (*footnote_def)(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data); 116 | void (*blockhtml)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 117 | 118 | /* span level callbacks - NULL or return 0 prints the span verbatim */ 119 | int (*autolink)(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data); 120 | int (*codespan)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 121 | int (*double_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 122 | int (*emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 123 | int (*underline)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 124 | int (*highlight)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 125 | int (*quote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 126 | int (*image)(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data); 127 | int (*linebreak)(hoedown_buffer *ob, const hoedown_renderer_data *data); 128 | int (*link)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data); 129 | int (*triple_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 130 | int (*strikethrough)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 131 | int (*superscript)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 132 | int (*footnote_ref)(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data); 133 | int (*math)(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data); 134 | int (*raw_html)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 135 | 136 | /* low level callbacks - NULL copies input directly into the output */ 137 | void (*entity)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 138 | void (*normal_text)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 139 | 140 | /* miscellaneous callbacks */ 141 | void (*doc_header)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data); 142 | void (*doc_footer)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data); 143 | }; 144 | typedef struct hoedown_renderer hoedown_renderer; 145 | 146 | 147 | /************* 148 | * FUNCTIONS * 149 | *************/ 150 | 151 | /* hoedown_document_new: allocate a new document processor instance */ 152 | hoedown_document *hoedown_document_new( 153 | const hoedown_renderer *renderer, 154 | hoedown_extensions extensions, 155 | size_t max_nesting 156 | ) __attribute__ ((malloc)); 157 | 158 | /* hoedown_document_render: render regular Markdown using the document processor */ 159 | void hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t size); 160 | 161 | /* hoedown_document_render_inline: render inline Markdown using the document processor */ 162 | void hoedown_document_render_inline(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t size); 163 | 164 | /* hoedown_document_free: deallocate a document processor instance */ 165 | void hoedown_document_free(hoedown_document *doc); 166 | 167 | 168 | #ifdef __cplusplus 169 | } 170 | #endif 171 | 172 | #endif /** HOEDOWN_DOCUMENT_H **/ 173 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.text: -------------------------------------------------------------------------------- 1 | Markdown: Basics 2 | ================ 3 | 4 | 11 | 12 | 13 | Getting the Gist of Markdown's Formatting Syntax 14 | ------------------------------------------------ 15 | 16 | This page offers a brief overview of what it's like to use Markdown. 17 | The [syntax page] [s] provides complete, detailed documentation for 18 | every feature, but Markdown should be very easy to pick up simply by 19 | looking at a few examples of it in action. The examples on this page 20 | are written in a before/after style, showing example syntax and the 21 | HTML output produced by Markdown. 22 | 23 | It's also helpful to simply try Markdown out; the [Dingus] [d] is a 24 | web application that allows you type your own Markdown-formatted text 25 | and translate it to XHTML. 26 | 27 | **Note:** This document is itself written using Markdown; you 28 | can [see the source for it by adding '.text' to the URL] [src]. 29 | 30 | [s]: /projects/markdown/syntax "Markdown Syntax" 31 | [d]: /projects/markdown/dingus "Markdown Dingus" 32 | [src]: /projects/markdown/basics.text 33 | 34 | 35 | ## Paragraphs, Headers, Blockquotes ## 36 | 37 | A paragraph is simply one or more consecutive lines of text, separated 38 | by one or more blank lines. (A blank line is any line that looks like a 39 | blank line -- a line containing nothing spaces or tabs is considered 40 | blank.) Normal paragraphs should not be intended with spaces or tabs. 41 | 42 | Markdown offers two styles of headers: *Setext* and *atx*. 43 | Setext-style headers for `

    ` and `

    ` are created by 44 | "underlining" with equal signs (`=`) and hyphens (`-`), respectively. 45 | To create an atx-style header, you put 1-6 hash marks (`#`) at the 46 | beginning of the line -- the number of hashes equals the resulting 47 | HTML header level. 48 | 49 | Blockquotes are indicated using email-style '`>`' angle brackets. 50 | 51 | Markdown: 52 | 53 | A First Level Header 54 | ==================== 55 | 56 | A Second Level Header 57 | --------------------- 58 | 59 | Now is the time for all good men to come to 60 | the aid of their country. This is just a 61 | regular paragraph. 62 | 63 | The quick brown fox jumped over the lazy 64 | dog's back. 65 | 66 | ### Header 3 67 | 68 | > This is a blockquote. 69 | > 70 | > This is the second paragraph in the blockquote. 71 | > 72 | > ## This is an H2 in a blockquote 73 | 74 | 75 | Output: 76 | 77 |

    A First Level Header

    78 | 79 |

    A Second Level Header

    80 | 81 |

    Now is the time for all good men to come to 82 | the aid of their country. This is just a 83 | regular paragraph.

    84 | 85 |

    The quick brown fox jumped over the lazy 86 | dog's back.

    87 | 88 |

    Header 3

    89 | 90 |
    91 |

    This is a blockquote.

    92 | 93 |

    This is the second paragraph in the blockquote.

    94 | 95 |

    This is an H2 in a blockquote

    96 |
    97 | 98 | 99 | 100 | ### Phrase Emphasis ### 101 | 102 | Markdown uses asterisks and underscores to indicate spans of emphasis. 103 | 104 | Markdown: 105 | 106 | Some of these words *are emphasized*. 107 | Some of these words _are emphasized also_. 108 | 109 | Use two asterisks for **strong emphasis**. 110 | Or, if you prefer, __use two underscores instead__. 111 | 112 | Output: 113 | 114 |

    Some of these words are emphasized. 115 | Some of these words are emphasized also.

    116 | 117 |

    Use two asterisks for strong emphasis. 118 | Or, if you prefer, use two underscores instead.

    119 | 120 | 121 | 122 | ## Lists ## 123 | 124 | Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`, 125 | `+`, and `-`) as list markers. These three markers are 126 | interchangable; this: 127 | 128 | * Candy. 129 | * Gum. 130 | * Booze. 131 | 132 | this: 133 | 134 | + Candy. 135 | + Gum. 136 | + Booze. 137 | 138 | and this: 139 | 140 | - Candy. 141 | - Gum. 142 | - Booze. 143 | 144 | all produce the same output: 145 | 146 |
      147 |
    • Candy.
    • 148 |
    • Gum.
    • 149 |
    • Booze.
    • 150 |
    151 | 152 | Ordered (numbered) lists use regular numbers, followed by periods, as 153 | list markers: 154 | 155 | 1. Red 156 | 2. Green 157 | 3. Blue 158 | 159 | Output: 160 | 161 |
      162 |
    1. Red
    2. 163 |
    3. Green
    4. 164 |
    5. Blue
    6. 165 |
    166 | 167 | If you put blank lines between items, you'll get `

    ` tags for the 168 | list item text. You can create multi-paragraph list items by indenting 169 | the paragraphs by 4 spaces or 1 tab: 170 | 171 | * A list item. 172 | 173 | With multiple paragraphs. 174 | 175 | * Another item in the list. 176 | 177 | Output: 178 | 179 |

      180 |
    • A list item.

      181 |

      With multiple paragraphs.

    • 182 |
    • Another item in the list.

    • 183 |
    184 | 185 | 186 | 187 | ### Links ### 188 | 189 | Markdown supports two styles for creating links: *inline* and 190 | *reference*. With both styles, you use square brackets to delimit the 191 | text you want to turn into a link. 192 | 193 | Inline-style links use parentheses immediately after the link text. 194 | For example: 195 | 196 | This is an [example link](http://example.com/). 197 | 198 | Output: 199 | 200 |

    This is an 201 | example link.

    202 | 203 | Optionally, you may include a title attribute in the parentheses: 204 | 205 | This is an [example link](http://example.com/ "With a Title"). 206 | 207 | Output: 208 | 209 |

    This is an 210 | example link.

    211 | 212 | Reference-style links allow you to refer to your links by names, which 213 | you define elsewhere in your document: 214 | 215 | I get 10 times more traffic from [Google][1] than from 216 | [Yahoo][2] or [MSN][3]. 217 | 218 | [1]: http://google.com/ "Google" 219 | [2]: http://search.yahoo.com/ "Yahoo Search" 220 | [3]: http://search.msn.com/ "MSN Search" 221 | 222 | Output: 223 | 224 |

    I get 10 times more traffic from Google than from Yahoo or MSN.

    228 | 229 | The title attribute is optional. Link names may contain letters, 230 | numbers and spaces, but are *not* case sensitive: 231 | 232 | I start my morning with a cup of coffee and 233 | [The New York Times][NY Times]. 234 | 235 | [ny times]: http://www.nytimes.com/ 236 | 237 | Output: 238 | 239 |

    I start my morning with a cup of coffee and 240 | The New York Times.

    241 | 242 | 243 | ### Images ### 244 | 245 | Image syntax is very much like link syntax. 246 | 247 | Inline (titles are optional): 248 | 249 | ![alt text](/path/to/img.jpg "Title") 250 | 251 | Reference-style: 252 | 253 | ![alt text][id] 254 | 255 | [id]: /path/to/img.jpg "Title" 256 | 257 | Both of the above examples produce the same output: 258 | 259 | alt text 260 | 261 | 262 | 263 | ### Code ### 264 | 265 | In a regular paragraph, you can create code span by wrapping text in 266 | backtick quotes. Any ampersands (`&`) and angle brackets (`<` or 267 | `>`) will automatically be translated into HTML entities. This makes 268 | it easy to use Markdown to write about HTML example code: 269 | 270 | I strongly recommend against using any `` tags. 271 | 272 | I wish SmartyPants used named entities like `—` 273 | instead of decimal-encoded entites like `—`. 274 | 275 | Output: 276 | 277 |

    I strongly recommend against using any 278 | <blink> tags.

    279 | 280 |

    I wish SmartyPants used named entities like 281 | &mdash; instead of decimal-encoded 282 | entites like &#8212;.

    283 | 284 | 285 | To specify an entire block of pre-formatted code, indent every line of 286 | the block by 4 spaces or 1 tab. Just like with code spans, `&`, `<`, 287 | and `>` characters will be escaped automatically. 288 | 289 | Markdown: 290 | 291 | If you want your page to validate under XHTML 1.0 Strict, 292 | you've got to put paragraph tags in your blockquotes: 293 | 294 |
    295 |

    For example.

    296 |
    297 | 298 | Output: 299 | 300 |

    If you want your page to validate under XHTML 1.0 Strict, 301 | you've got to put paragraph tags in your blockquotes:

    302 | 303 |
    <blockquote>
    304 |         <p>For example.</p>
    305 |     </blockquote>
    306 |     
    307 | -------------------------------------------------------------------------------- /src/html_blocks.c: -------------------------------------------------------------------------------- 1 | /* ANSI-C code produced by gperf version 3.0.3 */ 2 | /* Command-line: gperf -L ANSI-C -N hoedown_find_block_tag -c -C -E -S 1 --ignore-case -m100 html_block_names.gperf */ 3 | /* Computed positions: -k'1-2' */ 4 | 5 | #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ 6 | && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ 7 | && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ 8 | && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ 9 | && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ 10 | && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ 11 | && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ 12 | && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ 13 | && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ 14 | && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ 15 | && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ 16 | && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ 17 | && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ 18 | && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ 19 | && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ 20 | && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ 21 | && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ 22 | && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ 23 | && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ 24 | && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ 25 | && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ 26 | && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ 27 | && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) 28 | /* The character set is not based on ISO-646. */ 29 | #error "gperf generated tables don't work with this execution character set. Please report a bug to ." 30 | #endif 31 | 32 | /* maximum key range = 24, duplicates = 0 */ 33 | 34 | #ifndef GPERF_DOWNCASE 35 | #define GPERF_DOWNCASE 1 36 | static unsigned char gperf_downcase[256] = 37 | { 38 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 39 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 40 | 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 41 | 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 42 | 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 43 | 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 44 | 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 45 | 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 46 | 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 47 | 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 48 | 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 49 | 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 50 | 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 51 | 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 52 | 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 53 | 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 54 | 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 55 | 255 56 | }; 57 | #endif 58 | 59 | #ifndef GPERF_CASE_STRNCMP 60 | #define GPERF_CASE_STRNCMP 1 61 | static int 62 | gperf_case_strncmp (register const char *s1, register const char *s2, register unsigned int n) 63 | { 64 | for (; n > 0;) 65 | { 66 | unsigned char c1 = gperf_downcase[(unsigned char)*s1++]; 67 | unsigned char c2 = gperf_downcase[(unsigned char)*s2++]; 68 | if (c1 != 0 && c1 == c2) 69 | { 70 | n--; 71 | continue; 72 | } 73 | return (int)c1 - (int)c2; 74 | } 75 | return 0; 76 | } 77 | #endif 78 | 79 | #ifdef __GNUC__ 80 | __inline 81 | #else 82 | #ifdef __cplusplus 83 | inline 84 | #endif 85 | #endif 86 | static unsigned int 87 | hash (register const char *str, register unsigned int len) 88 | { 89 | static const unsigned char asso_values[] = 90 | { 91 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 92 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 93 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 94 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 95 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 96 | 22, 21, 19, 18, 16, 0, 25, 25, 25, 25, 97 | 25, 25, 25, 25, 25, 25, 1, 25, 0, 25, 98 | 1, 0, 0, 13, 0, 25, 25, 11, 2, 1, 99 | 0, 25, 25, 5, 0, 2, 25, 25, 25, 25, 100 | 25, 25, 25, 25, 25, 25, 25, 25, 1, 25, 101 | 0, 25, 1, 0, 0, 13, 0, 25, 25, 11, 102 | 2, 1, 0, 25, 25, 5, 0, 2, 25, 25, 103 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 104 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 105 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 106 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 107 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 108 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 109 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 110 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 111 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 112 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 113 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 114 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 115 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 116 | 25, 25, 25, 25, 25, 25, 25 117 | }; 118 | register int hval = (int)len; 119 | 120 | switch (hval) 121 | { 122 | default: 123 | hval += asso_values[(unsigned char)str[1]+1]; 124 | /*FALLTHROUGH*/ 125 | case 1: 126 | hval += asso_values[(unsigned char)str[0]]; 127 | break; 128 | } 129 | return hval; 130 | } 131 | 132 | #ifdef __GNUC__ 133 | __inline 134 | #ifdef __GNUC_STDC_INLINE__ 135 | __attribute__ ((__gnu_inline__)) 136 | #endif 137 | #endif 138 | const char * 139 | hoedown_find_block_tag (register const char *str, register unsigned int len) 140 | { 141 | enum 142 | { 143 | TOTAL_KEYWORDS = 24, 144 | MIN_WORD_LENGTH = 1, 145 | MAX_WORD_LENGTH = 10, 146 | MIN_HASH_VALUE = 1, 147 | MAX_HASH_VALUE = 24 148 | }; 149 | 150 | if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) 151 | { 152 | register int key = hash (str, len); 153 | 154 | if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE) 155 | { 156 | register const char *resword; 157 | 158 | switch (key - 1) 159 | { 160 | case 0: 161 | resword = "p"; 162 | goto compare; 163 | case 1: 164 | resword = "h6"; 165 | goto compare; 166 | case 2: 167 | resword = "div"; 168 | goto compare; 169 | case 3: 170 | resword = "del"; 171 | goto compare; 172 | case 4: 173 | resword = "form"; 174 | goto compare; 175 | case 5: 176 | resword = "table"; 177 | goto compare; 178 | case 6: 179 | resword = "figure"; 180 | goto compare; 181 | case 7: 182 | resword = "pre"; 183 | goto compare; 184 | case 8: 185 | resword = "fieldset"; 186 | goto compare; 187 | case 9: 188 | resword = "noscript"; 189 | goto compare; 190 | case 10: 191 | resword = "script"; 192 | goto compare; 193 | case 11: 194 | resword = "style"; 195 | goto compare; 196 | case 12: 197 | resword = "dl"; 198 | goto compare; 199 | case 13: 200 | resword = "ol"; 201 | goto compare; 202 | case 14: 203 | resword = "ul"; 204 | goto compare; 205 | case 15: 206 | resword = "math"; 207 | goto compare; 208 | case 16: 209 | resword = "ins"; 210 | goto compare; 211 | case 17: 212 | resword = "h5"; 213 | goto compare; 214 | case 18: 215 | resword = "iframe"; 216 | goto compare; 217 | case 19: 218 | resword = "h4"; 219 | goto compare; 220 | case 20: 221 | resword = "h3"; 222 | goto compare; 223 | case 21: 224 | resword = "blockquote"; 225 | goto compare; 226 | case 22: 227 | resword = "h2"; 228 | goto compare; 229 | case 23: 230 | resword = "h1"; 231 | goto compare; 232 | } 233 | return 0; 234 | compare: 235 | if ((((unsigned char)*str ^ (unsigned char)*resword) & ~32) == 0 && !gperf_case_strncmp (str, resword, len) && resword[len] == '\0') 236 | return resword; 237 | } 238 | } 239 | return 0; 240 | } 241 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.html: -------------------------------------------------------------------------------- 1 |

    Markdown: Basics

    2 | 3 | 10 | 11 |

    Getting the Gist of Markdown's Formatting Syntax

    12 | 13 |

    This page offers a brief overview of what it's like to use Markdown. 14 | The syntax page provides complete, detailed documentation for 15 | every feature, but Markdown should be very easy to pick up simply by 16 | looking at a few examples of it in action. The examples on this page 17 | are written in a before/after style, showing example syntax and the 18 | HTML output produced by Markdown.

    19 | 20 |

    It's also helpful to simply try Markdown out; the Dingus is a 21 | web application that allows you type your own Markdown-formatted text 22 | and translate it to XHTML.

    23 | 24 |

    Note: This document is itself written using Markdown; you 25 | can see the source for it by adding '.text' to the URL.

    26 | 27 |

    Paragraphs, Headers, Blockquotes

    28 | 29 |

    A paragraph is simply one or more consecutive lines of text, separated 30 | by one or more blank lines. (A blank line is any line that looks like a 31 | blank line -- a line containing nothing spaces or tabs is considered 32 | blank.) Normal paragraphs should not be intended with spaces or tabs.

    33 | 34 |

    Markdown offers two styles of headers: Setext and atx. 35 | Setext-style headers for <h1> and <h2> are created by 36 | "underlining" with equal signs (=) and hyphens (-), respectively. 37 | To create an atx-style header, you put 1-6 hash marks (#) at the 38 | beginning of the line -- the number of hashes equals the resulting 39 | HTML header level.

    40 | 41 |

    Blockquotes are indicated using email-style '>' angle brackets.

    42 | 43 |

    Markdown:

    44 | 45 |
    A First Level Header
     46 | ====================
     47 | 
     48 | A Second Level Header
     49 | ---------------------
     50 | 
     51 | Now is the time for all good men to come to
     52 | the aid of their country. This is just a
     53 | regular paragraph.
     54 | 
     55 | The quick brown fox jumped over the lazy
     56 | dog's back.
     57 | 
     58 | ### Header 3
     59 | 
     60 | > This is a blockquote.
     61 | > 
     62 | > This is the second paragraph in the blockquote.
     63 | >
     64 | > ## This is an H2 in a blockquote
     65 | 
    66 | 67 |

    Output:

    68 | 69 |
    <h1>A First Level Header</h1>
     70 | 
     71 | <h2>A Second Level Header</h2>
     72 | 
     73 | <p>Now is the time for all good men to come to
     74 | the aid of their country. This is just a
     75 | regular paragraph.</p>
     76 | 
     77 | <p>The quick brown fox jumped over the lazy
     78 | dog's back.</p>
     79 | 
     80 | <h3>Header 3</h3>
     81 | 
     82 | <blockquote>
     83 |     <p>This is a blockquote.</p>
     84 | 
     85 |     <p>This is the second paragraph in the blockquote.</p>
     86 | 
     87 |     <h2>This is an H2 in a blockquote</h2>
     88 | </blockquote>
     89 | 
    90 | 91 |

    Phrase Emphasis

    92 | 93 |

    Markdown uses asterisks and underscores to indicate spans of emphasis.

    94 | 95 |

    Markdown:

    96 | 97 |
    Some of these words *are emphasized*.
     98 | Some of these words _are emphasized also_.
     99 | 
    100 | Use two asterisks for **strong emphasis**.
    101 | Or, if you prefer, __use two underscores instead__.
    102 | 
    103 | 104 |

    Output:

    105 | 106 |
    <p>Some of these words <em>are emphasized</em>.
    107 | Some of these words <em>are emphasized also</em>.</p>
    108 | 
    109 | <p>Use two asterisks for <strong>strong emphasis</strong>.
    110 | Or, if you prefer, <strong>use two underscores instead</strong>.</p>
    111 | 
    112 | 113 |

    Lists

    114 | 115 |

    Unordered (bulleted) lists use asterisks, pluses, and hyphens (*, 116 | +, and -) as list markers. These three markers are 117 | interchangable; this:

    118 | 119 |
    *   Candy.
    120 | *   Gum.
    121 | *   Booze.
    122 | 
    123 | 124 |

    this:

    125 | 126 |
    +   Candy.
    127 | +   Gum.
    128 | +   Booze.
    129 | 
    130 | 131 |

    and this:

    132 | 133 |
    -   Candy.
    134 | -   Gum.
    135 | -   Booze.
    136 | 
    137 | 138 |

    all produce the same output:

    139 | 140 |
    <ul>
    141 | <li>Candy.</li>
    142 | <li>Gum.</li>
    143 | <li>Booze.</li>
    144 | </ul>
    145 | 
    146 | 147 |

    Ordered (numbered) lists use regular numbers, followed by periods, as 148 | list markers:

    149 | 150 |
    1.  Red
    151 | 2.  Green
    152 | 3.  Blue
    153 | 
    154 | 155 |

    Output:

    156 | 157 |
    <ol>
    158 | <li>Red</li>
    159 | <li>Green</li>
    160 | <li>Blue</li>
    161 | </ol>
    162 | 
    163 | 164 |

    If you put blank lines between items, you'll get <p> tags for the 165 | list item text. You can create multi-paragraph list items by indenting 166 | the paragraphs by 4 spaces or 1 tab:

    167 | 168 |
    *   A list item.
    169 | 
    170 |     With multiple paragraphs.
    171 | 
    172 | *   Another item in the list.
    173 | 
    174 | 175 |

    Output:

    176 | 177 |
    <ul>
    178 | <li><p>A list item.</p>
    179 | <p>With multiple paragraphs.</p></li>
    180 | <li><p>Another item in the list.</p></li>
    181 | </ul>
    182 | 
    183 | 184 |

    Links

    185 | 186 |

    Markdown supports two styles for creating links: inline and 187 | reference. With both styles, you use square brackets to delimit the 188 | text you want to turn into a link.

    189 | 190 |

    Inline-style links use parentheses immediately after the link text. 191 | For example:

    192 | 193 |
    This is an [example link](http://example.com/).
    194 | 
    195 | 196 |

    Output:

    197 | 198 |
    <p>This is an <a href="http://example.com/">
    199 | example link</a>.</p>
    200 | 
    201 | 202 |

    Optionally, you may include a title attribute in the parentheses:

    203 | 204 |
    This is an [example link](http://example.com/ "With a Title").
    205 | 
    206 | 207 |

    Output:

    208 | 209 |
    <p>This is an <a href="http://example.com/" title="With a Title">
    210 | example link</a>.</p>
    211 | 
    212 | 213 |

    Reference-style links allow you to refer to your links by names, which 214 | you define elsewhere in your document:

    215 | 216 |
    I get 10 times more traffic from [Google][1] than from
    217 | [Yahoo][2] or [MSN][3].
    218 | 
    219 | [1]: http://google.com/        "Google"
    220 | [2]: http://search.yahoo.com/  "Yahoo Search"
    221 | [3]: http://search.msn.com/    "MSN Search"
    222 | 
    223 | 224 |

    Output:

    225 | 226 |
    <p>I get 10 times more traffic from <a href="http://google.com/"
    227 | title="Google">Google</a> than from <a href="http://search.yahoo.com/"
    228 | title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
    229 | title="MSN Search">MSN</a>.</p>
    230 | 
    231 | 232 |

    The title attribute is optional. Link names may contain letters, 233 | numbers and spaces, but are not case sensitive:

    234 | 235 |
    I start my morning with a cup of coffee and
    236 | [The New York Times][NY Times].
    237 | 
    238 | [ny times]: http://www.nytimes.com/
    239 | 
    240 | 241 |

    Output:

    242 | 243 |
    <p>I start my morning with a cup of coffee and
    244 | <a href="http://www.nytimes.com/">The New York Times</a>.</p>
    245 | 
    246 | 247 |

    Images

    248 | 249 |

    Image syntax is very much like link syntax.

    250 | 251 |

    Inline (titles are optional):

    252 | 253 |
    ![alt text](/path/to/img.jpg "Title")
    254 | 
    255 | 256 |

    Reference-style:

    257 | 258 |
    ![alt text][id]
    259 | 
    260 | [id]: /path/to/img.jpg "Title"
    261 | 
    262 | 263 |

    Both of the above examples produce the same output:

    264 | 265 |
    <img src="/path/to/img.jpg" alt="alt text" title="Title" />
    266 | 
    267 | 268 |

    Code

    269 | 270 |

    In a regular paragraph, you can create code span by wrapping text in 271 | backtick quotes. Any ampersands (&) and angle brackets (< or 272 | >) will automatically be translated into HTML entities. This makes 273 | it easy to use Markdown to write about HTML example code:

    274 | 275 |
    I strongly recommend against using any `<blink>` tags.
    276 | 
    277 | I wish SmartyPants used named entities like `&mdash;`
    278 | instead of decimal-encoded entites like `&#8212;`.
    279 | 
    280 | 281 |

    Output:

    282 | 283 |
    <p>I strongly recommend against using any
    284 | <code>&lt;blink&gt;</code> tags.</p>
    285 | 
    286 | <p>I wish SmartyPants used named entities like
    287 | <code>&amp;mdash;</code> instead of decimal-encoded
    288 | entites like <code>&amp;#8212;</code>.</p>
    289 | 
    290 | 291 |

    To specify an entire block of pre-formatted code, indent every line of 292 | the block by 4 spaces or 1 tab. Just like with code spans, &, <, 293 | and > characters will be escaped automatically.

    294 | 295 |

    Markdown:

    296 | 297 |
    If you want your page to validate under XHTML 1.0 Strict,
    298 | you've got to put paragraph tags in your blockquotes:
    299 | 
    300 |     <blockquote>
    301 |         <p>For example.</p>
    302 |     </blockquote>
    303 | 
    304 | 305 |

    Output:

    306 | 307 |
    <p>If you want your page to validate under XHTML 1.0 Strict,
    308 | you've got to put paragraph tags in your blockquotes:</p>
    309 | 
    310 | <pre><code>&lt;blockquote&gt;
    311 |     &lt;p&gt;For example.&lt;/p&gt;
    312 | &lt;/blockquote&gt;
    313 | </code></pre>
    314 | 
    315 | -------------------------------------------------------------------------------- /bin/hoedown.c: -------------------------------------------------------------------------------- 1 | #include "document.h" 2 | #include "html.h" 3 | 4 | #include "common.h" 5 | #include 6 | 7 | 8 | /* FEATURES INFO / DEFAULTS */ 9 | 10 | enum renderer_type { 11 | RENDERER_HTML, 12 | RENDERER_HTML_TOC 13 | }; 14 | 15 | struct extension_category_info { 16 | unsigned int flags; 17 | const char *option_name; 18 | const char *label; 19 | }; 20 | 21 | struct extension_info { 22 | unsigned int flag; 23 | const char *option_name; 24 | const char *description; 25 | }; 26 | 27 | struct html_flag_info { 28 | unsigned int flag; 29 | const char *option_name; 30 | const char *description; 31 | }; 32 | 33 | static struct extension_category_info categories_info[] = { 34 | {HOEDOWN_EXT_BLOCK, "block", "Block extensions"}, 35 | {HOEDOWN_EXT_SPAN, "span", "Span extensions"}, 36 | {HOEDOWN_EXT_FLAGS, "flags", "Other flags"}, 37 | {HOEDOWN_EXT_NEGATIVE, "negative", "Negative flags"}, 38 | }; 39 | 40 | static struct extension_info extensions_info[] = { 41 | {HOEDOWN_EXT_TABLES, "tables", "Parse PHP-Markdown style tables."}, 42 | {HOEDOWN_EXT_FENCED_CODE, "fenced-code", "Parse fenced code blocks."}, 43 | {HOEDOWN_EXT_FOOTNOTES, "footnotes", "Parse footnotes."}, 44 | 45 | {HOEDOWN_EXT_AUTOLINK, "autolink", "Automatically turn safe URLs into links."}, 46 | {HOEDOWN_EXT_STRIKETHROUGH, "strikethrough", "Parse ~~stikethrough~~ spans."}, 47 | {HOEDOWN_EXT_UNDERLINE, "underline", "Parse _underline_ instead of emphasis."}, 48 | {HOEDOWN_EXT_HIGHLIGHT, "highlight", "Parse ==highlight== spans."}, 49 | {HOEDOWN_EXT_QUOTE, "quote", "Render \"quotes\" as quotes."}, 50 | {HOEDOWN_EXT_SUPERSCRIPT, "superscript", "Parse super^script."}, 51 | {HOEDOWN_EXT_MATH, "math", "Parse TeX $$math$$ syntax, Kramdown style."}, 52 | 53 | {HOEDOWN_EXT_NO_INTRA_EMPHASIS, "disable-intra-emphasis", "Disable emphasis_between_words."}, 54 | {HOEDOWN_EXT_SPACE_HEADERS, "space-headers", "Require a space after '#' in headers."}, 55 | {HOEDOWN_EXT_MATH_EXPLICIT, "math-explicit", "Instead of guessing by context, parse $inline math$ and $$always block math$$ (requires --math)."}, 56 | 57 | {HOEDOWN_EXT_DISABLE_INDENTED_CODE, "disable-indented-code", "Don't parse indented code blocks."}, 58 | }; 59 | 60 | static struct html_flag_info html_flags_info[] = { 61 | {HOEDOWN_HTML_SKIP_HTML, "skip-html", "Strip all HTML tags."}, 62 | {HOEDOWN_HTML_ESCAPE, "escape", "Escape all HTML."}, 63 | {HOEDOWN_HTML_HARD_WRAP, "hard-wrap", "Render each linebreak as
    ."}, 64 | {HOEDOWN_HTML_USE_XHTML, "xhtml", "Render XHTML."}, 65 | }; 66 | 67 | static const char *category_prefix = "all-"; 68 | static const char *negative_prefix = "no-"; 69 | 70 | #define DEF_IUNIT 1024 71 | #define DEF_OUNIT 64 72 | #define DEF_MAX_NESTING 16 73 | 74 | 75 | /* PRINT HELP */ 76 | 77 | void 78 | print_help(const char *basename) 79 | { 80 | size_t i; 81 | size_t e; 82 | 83 | /* usage */ 84 | printf("Usage: %s [OPTION]... [FILE]\n\n", basename); 85 | 86 | /* description */ 87 | printf("Process the Markdown in FILE (or standard input) and render it to standard output, using the Hoedown library. " 88 | "Parsing and rendering can be customized through the options below. The default is to parse pure markdown and output HTML.\n\n"); 89 | 90 | /* main options */ 91 | printf("Main options:\n"); 92 | print_option('n', "max-nesting=N", "Maximum level of block nesting parsed. Default is " str(DEF_MAX_NESTING) "."); 93 | print_option('t', "toc-level=N", "Maximum level for headers included in the TOC. Zero disables TOC (the default)."); 94 | print_option( 0, "html", "Render (X)HTML. The default."); 95 | print_option( 0, "html-toc", "Render the Table of Contents in (X)HTML."); 96 | print_option('T', "time", "Show time spent in rendering."); 97 | print_option('i', "input-unit=N", "Reading block size. Default is " str(DEF_IUNIT) "."); 98 | print_option('o', "output-unit=N", "Writing block size. Default is " str(DEF_OUNIT) "."); 99 | print_option('h', "help", "Print this help text."); 100 | print_option('v', "version", "Print Hoedown version."); 101 | printf("\n"); 102 | 103 | /* extensions */ 104 | for (i = 0; i < count_of(categories_info); i++) { 105 | struct extension_category_info *category = categories_info+i; 106 | printf("%s (--%s%s):\n", category->label, category_prefix, category->option_name); 107 | for (e = 0; e < count_of(extensions_info); e++) { 108 | struct extension_info *extension = extensions_info+e; 109 | if (extension->flag & category->flags) { 110 | print_option( 0, extension->option_name, extension->description); 111 | } 112 | } 113 | printf("\n"); 114 | } 115 | 116 | /* html-specific */ 117 | printf("HTML-specific options:\n"); 118 | for (i = 0; i < count_of(html_flags_info); i++) { 119 | struct html_flag_info *html_flag = html_flags_info+i; 120 | print_option( 0, html_flag->option_name, html_flag->description); 121 | } 122 | printf("\n"); 123 | 124 | /* ending */ 125 | printf("Flags and extensions can be negated by prepending 'no' to them, as in '--no-tables', '--no-span' or '--no-escape'. " 126 | "Options are processed in order, so in case of contradictory options the last specified stands.\n\n"); 127 | 128 | printf("When FILE is '-', read standard input. If no FILE was given, read standard input. Use '--' to signal end of option parsing. " 129 | "Exit status is 0 if no errors occurred, 1 with option parsing errors, 4 with memory allocation errors or 5 with I/O errors.\n\n"); 130 | } 131 | 132 | 133 | /* OPTION PARSING */ 134 | 135 | struct option_data { 136 | char *basename; 137 | int done; 138 | 139 | /* time reporting */ 140 | int show_time; 141 | 142 | /* I/O */ 143 | size_t iunit; 144 | size_t ounit; 145 | const char *filename; 146 | 147 | /* renderer */ 148 | enum renderer_type renderer; 149 | int toc_level; 150 | hoedown_html_flags html_flags; 151 | 152 | /* parsing */ 153 | hoedown_extensions extensions; 154 | size_t max_nesting; 155 | }; 156 | 157 | int 158 | parse_short_option(char opt, char *next, void *opaque) 159 | { 160 | struct option_data *data = opaque; 161 | long int num; 162 | int isNum = next ? parseint(next, &num) : 0; 163 | 164 | if (opt == 'h') { 165 | print_help(data->basename); 166 | data->done = 1; 167 | return 0; 168 | } 169 | 170 | if (opt == 'v') { 171 | print_version(); 172 | data->done = 1; 173 | return 0; 174 | } 175 | 176 | if (opt == 'T') { 177 | data->show_time = 1; 178 | return 1; 179 | } 180 | 181 | /* options requiring value */ 182 | /* FIXME: add validation */ 183 | 184 | if (opt == 'n' && isNum) { 185 | data->max_nesting = num; 186 | return 2; 187 | } 188 | 189 | if (opt == 't' && isNum) { 190 | data->toc_level = num; 191 | return 2; 192 | } 193 | 194 | if (opt == 'i' && isNum) { 195 | data->iunit = num; 196 | return 2; 197 | } 198 | 199 | if (opt == 'o' && isNum) { 200 | data->ounit = num; 201 | return 2; 202 | } 203 | 204 | fprintf(stderr, "Wrong option '-%c' found.\n", opt); 205 | return 0; 206 | } 207 | 208 | int 209 | parse_category_option(char *opt, struct option_data *data) 210 | { 211 | size_t i; 212 | const char *name = strprefix(opt, category_prefix); 213 | if (!name) return 0; 214 | 215 | for (i = 0; i < count_of(categories_info); i++) { 216 | struct extension_category_info *category = &categories_info[i]; 217 | if (strcmp(name, category->option_name)==0) { 218 | data->extensions |= category->flags; 219 | return 1; 220 | } 221 | } 222 | 223 | return 0; 224 | } 225 | 226 | int 227 | parse_flag_option(char *opt, struct option_data *data) 228 | { 229 | size_t i; 230 | 231 | for (i = 0; i < count_of(extensions_info); i++) { 232 | struct extension_info *extension = &extensions_info[i]; 233 | if (strcmp(opt, extension->option_name)==0) { 234 | data->extensions |= extension->flag; 235 | return 1; 236 | } 237 | } 238 | 239 | for (i = 0; i < count_of(html_flags_info); i++) { 240 | struct html_flag_info *html_flag = &html_flags_info[i]; 241 | if (strcmp(opt, html_flag->option_name)==0) { 242 | data->html_flags |= html_flag->flag; 243 | return 1; 244 | } 245 | } 246 | 247 | return 0; 248 | } 249 | 250 | int 251 | parse_negative_option(char *opt, struct option_data *data) 252 | { 253 | size_t i; 254 | const char *name = strprefix(opt, negative_prefix); 255 | if (!name) return 0; 256 | 257 | for (i = 0; i < count_of(categories_info); i++) { 258 | struct extension_category_info *category = &categories_info[i]; 259 | if (strcmp(name, category->option_name)==0) { 260 | data->extensions &= ~(category->flags); 261 | return 1; 262 | } 263 | } 264 | 265 | for (i = 0; i < count_of(extensions_info); i++) { 266 | struct extension_info *extension = &extensions_info[i]; 267 | if (strcmp(name, extension->option_name)==0) { 268 | data->extensions &= ~(extension->flag); 269 | return 1; 270 | } 271 | } 272 | 273 | for (i = 0; i < count_of(html_flags_info); i++) { 274 | struct html_flag_info *html_flag = &html_flags_info[i]; 275 | if (strcmp(name, html_flag->option_name)==0) { 276 | data->html_flags &= ~(html_flag->flag); 277 | return 1; 278 | } 279 | } 280 | 281 | return 0; 282 | } 283 | 284 | int 285 | parse_long_option(char *opt, char *next, void *opaque) 286 | { 287 | struct option_data *data = opaque; 288 | long int num; 289 | int isNum = next ? parseint(next, &num) : 0; 290 | 291 | if (strcmp(opt, "help")==0) { 292 | print_help(data->basename); 293 | data->done = 1; 294 | return 0; 295 | } 296 | 297 | if (strcmp(opt, "version")==0) { 298 | print_version(); 299 | data->done = 1; 300 | return 0; 301 | } 302 | 303 | if (strcmp(opt, "time")==0) { 304 | data->show_time = 1; 305 | return 1; 306 | } 307 | 308 | /* FIXME: validation */ 309 | 310 | if (strcmp(opt, "max-nesting")==0 && isNum) { 311 | data->max_nesting = num; 312 | return 2; 313 | } 314 | if (strcmp(opt, "toc-level")==0 && isNum) { 315 | data->toc_level = num; 316 | return 2; 317 | } 318 | if (strcmp(opt, "input-unit")==0 && isNum) { 319 | data->iunit = num; 320 | return 2; 321 | } 322 | if (strcmp(opt, "output-unit")==0 && isNum) { 323 | data->ounit = num; 324 | return 2; 325 | } 326 | 327 | if (strcmp(opt, "html")==0) { 328 | data->renderer = RENDERER_HTML; 329 | return 1; 330 | } 331 | if (strcmp(opt, "html-toc")==0) { 332 | data->renderer = RENDERER_HTML_TOC; 333 | return 1; 334 | } 335 | 336 | if (parse_category_option(opt, data) || parse_flag_option(opt, data) || parse_negative_option(opt, data)) 337 | return 1; 338 | 339 | fprintf(stderr, "Wrong option '--%s' found.\n", opt); 340 | return 0; 341 | } 342 | 343 | int 344 | parse_argument(int argn, char *arg, int is_forced, void *opaque) 345 | { 346 | struct option_data *data = opaque; 347 | 348 | if (argn == 0) { 349 | /* Input file */ 350 | if (strcmp(arg, "-")!=0 || is_forced) data->filename = arg; 351 | return 1; 352 | } 353 | 354 | fprintf(stderr, "Too many arguments.\n"); 355 | return 0; 356 | } 357 | 358 | 359 | /* MAIN LOGIC */ 360 | 361 | int 362 | main(int argc, char **argv) 363 | { 364 | struct option_data data; 365 | clock_t t1, t2; 366 | FILE *file = stdin; 367 | hoedown_buffer *ib, *ob; 368 | hoedown_renderer *renderer = NULL; 369 | void (*renderer_free)(hoedown_renderer *) = NULL; 370 | hoedown_document *document; 371 | 372 | /* Parse options */ 373 | data.basename = argv[0]; 374 | data.done = 0; 375 | data.show_time = 0; 376 | data.iunit = DEF_IUNIT; 377 | data.ounit = DEF_OUNIT; 378 | data.filename = NULL; 379 | data.renderer = RENDERER_HTML; 380 | data.toc_level = 0; 381 | data.html_flags = 0; 382 | data.extensions = 0; 383 | data.max_nesting = DEF_MAX_NESTING; 384 | 385 | argc = parse_options(argc, argv, parse_short_option, parse_long_option, parse_argument, &data); 386 | if (data.done) return 0; 387 | if (!argc) return 1; 388 | 389 | /* Open input file, if needed */ 390 | if (data.filename) { 391 | file = fopen(data.filename, "r"); 392 | if (!file) { 393 | fprintf(stderr, "Unable to open input file \"%s\": %s\n", data.filename, strerror(errno)); 394 | return 5; 395 | } 396 | } 397 | 398 | /* Read everything */ 399 | ib = hoedown_buffer_new(data.iunit); 400 | 401 | if (hoedown_buffer_putf(ib, file)) { 402 | fprintf(stderr, "I/O errors found while reading input.\n"); 403 | return 5; 404 | } 405 | 406 | if (file != stdin) fclose(file); 407 | 408 | /* Create the renderer */ 409 | switch (data.renderer) { 410 | case RENDERER_HTML: 411 | renderer = hoedown_html_renderer_new(data.html_flags, data.toc_level); 412 | renderer_free = hoedown_html_renderer_free; 413 | break; 414 | case RENDERER_HTML_TOC: 415 | renderer = hoedown_html_toc_renderer_new(data.toc_level); 416 | renderer_free = hoedown_html_renderer_free; 417 | break; 418 | }; 419 | 420 | /* Perform Markdown rendering */ 421 | ob = hoedown_buffer_new(data.ounit); 422 | document = hoedown_document_new(renderer, data.extensions, data.max_nesting); 423 | 424 | t1 = clock(); 425 | hoedown_document_render(document, ob, ib->data, ib->size); 426 | t2 = clock(); 427 | 428 | /* Cleanup */ 429 | hoedown_buffer_free(ib); 430 | hoedown_document_free(document); 431 | renderer_free(renderer); 432 | 433 | /* Write the result to stdout */ 434 | (void)fwrite(ob->data, 1, ob->size, stdout); 435 | hoedown_buffer_free(ob); 436 | 437 | if (ferror(stdout)) { 438 | fprintf(stderr, "I/O errors found while writing output.\n"); 439 | return 5; 440 | } 441 | 442 | /* Show rendering time */ 443 | if (data.show_time) { 444 | double elapsed; 445 | 446 | if (t1 == ((clock_t) -1) || t2 == ((clock_t) -1)) { 447 | fprintf(stderr, "Failed to get the time.\n"); 448 | return 1; 449 | } 450 | 451 | elapsed = (double)(t2 - t1) / CLOCKS_PER_SEC; 452 | if (elapsed < 1) 453 | fprintf(stderr, "Time spent on rendering: %7.2f ms.\n", elapsed*1e3); 454 | else 455 | fprintf(stderr, "Time spent on rendering: %6.3f s.\n", elapsed); 456 | } 457 | 458 | return 0; 459 | } 460 | -------------------------------------------------------------------------------- /src/html_smartypants.c: -------------------------------------------------------------------------------- 1 | #include "html.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef _MSC_VER 9 | #define snprintf _snprintf 10 | #endif 11 | 12 | struct smartypants_data { 13 | int in_squote; 14 | int in_dquote; 15 | }; 16 | 17 | static size_t smartypants_cb__ltag(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); 18 | static size_t smartypants_cb__dquote(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); 19 | static size_t smartypants_cb__amp(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); 20 | static size_t smartypants_cb__period(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); 21 | static size_t smartypants_cb__number(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); 22 | static size_t smartypants_cb__dash(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); 23 | static size_t smartypants_cb__parens(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); 24 | static size_t smartypants_cb__squote(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); 25 | static size_t smartypants_cb__backtick(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); 26 | static size_t smartypants_cb__escape(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); 27 | 28 | static size_t (*smartypants_cb_ptrs[]) 29 | (hoedown_buffer *, struct smartypants_data *, uint8_t, const uint8_t *, size_t) = 30 | { 31 | NULL, /* 0 */ 32 | smartypants_cb__dash, /* 1 */ 33 | smartypants_cb__parens, /* 2 */ 34 | smartypants_cb__squote, /* 3 */ 35 | smartypants_cb__dquote, /* 4 */ 36 | smartypants_cb__amp, /* 5 */ 37 | smartypants_cb__period, /* 6 */ 38 | smartypants_cb__number, /* 7 */ 39 | smartypants_cb__ltag, /* 8 */ 40 | smartypants_cb__backtick, /* 9 */ 41 | smartypants_cb__escape, /* 10 */ 42 | }; 43 | 44 | static const uint8_t smartypants_cb_chars[UINT8_MAX+1] = { 45 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47 | 0, 0, 4, 0, 0, 0, 5, 3, 2, 0, 0, 0, 0, 1, 6, 0, 48 | 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 49 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 51 | 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61 | }; 62 | 63 | static int 64 | word_boundary(uint8_t c) 65 | { 66 | return c == 0 || isspace(c) || ispunct(c); 67 | } 68 | 69 | /* 70 | If 'text' begins with any kind of single quote (e.g. "'" or "'" etc.), 71 | returns the length of the sequence of characters that makes up the single- 72 | quote. Otherwise, returns zero. 73 | */ 74 | static size_t 75 | squote_len(const uint8_t *text, size_t size) 76 | { 77 | static char* single_quote_list[] = { "'", "'", "'", "'", NULL }; 78 | char** p; 79 | 80 | for (p = single_quote_list; *p; ++p) { 81 | size_t len = strlen(*p); 82 | if (size >= len && memcmp(text, *p, len) == 0) { 83 | return len; 84 | } 85 | } 86 | 87 | return 0; 88 | } 89 | 90 | /* Converts " or ' at very beginning or end of a word to left or right quote */ 91 | static int 92 | smartypants_quotes(hoedown_buffer *ob, uint8_t previous_char, uint8_t next_char, uint8_t quote, int *is_open) 93 | { 94 | char ent[8]; 95 | 96 | if (*is_open && !word_boundary(next_char)) 97 | return 0; 98 | 99 | if (!(*is_open) && !word_boundary(previous_char)) 100 | return 0; 101 | 102 | snprintf(ent, sizeof(ent), "&%c%cquo;", (*is_open) ? 'r' : 'l', quote); 103 | *is_open = !(*is_open); 104 | hoedown_buffer_puts(ob, ent); 105 | return 1; 106 | } 107 | 108 | /* 109 | Converts ' to left or right single quote; but the initial ' might be in 110 | different forms, e.g. ' or ' or '. 111 | 'squote_text' points to the original single quote, and 'squote_size' is its length. 112 | 'text' points at the last character of the single-quote, e.g. ' or ; 113 | */ 114 | static size_t 115 | smartypants_squote(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size, 116 | const uint8_t *squote_text, size_t squote_size) 117 | { 118 | if (size >= 2) { 119 | uint8_t t1 = tolower(text[1]); 120 | size_t next_squote_len = squote_len(text+1, size-1); 121 | 122 | /* convert '' to “ or ” */ 123 | if (next_squote_len > 0) { 124 | uint8_t next_char = (size > 1+next_squote_len) ? text[1+next_squote_len] : 0; 125 | if (smartypants_quotes(ob, previous_char, next_char, 'd', &smrt->in_dquote)) 126 | return next_squote_len; 127 | } 128 | 129 | /* Tom's, isn't, I'm, I'd */ 130 | if ((t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && 131 | (size == 3 || word_boundary(text[2]))) { 132 | HOEDOWN_BUFPUTSL(ob, "’"); 133 | return 0; 134 | } 135 | 136 | /* you're, you'll, you've */ 137 | if (size >= 3) { 138 | uint8_t t2 = tolower(text[2]); 139 | 140 | if (((t1 == 'r' && t2 == 'e') || 141 | (t1 == 'l' && t2 == 'l') || 142 | (t1 == 'v' && t2 == 'e')) && 143 | (size == 4 || word_boundary(text[3]))) { 144 | HOEDOWN_BUFPUTSL(ob, "’"); 145 | return 0; 146 | } 147 | } 148 | } 149 | 150 | if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote)) 151 | return 0; 152 | 153 | hoedown_buffer_put(ob, squote_text, squote_size); 154 | return 0; 155 | } 156 | 157 | /* Converts ' to left or right single quote. */ 158 | static size_t 159 | smartypants_cb__squote(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) 160 | { 161 | return smartypants_squote(ob, smrt, previous_char, text, size, text, 1); 162 | } 163 | 164 | /* Converts (c), (r), (tm) */ 165 | static size_t 166 | smartypants_cb__parens(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) 167 | { 168 | if (size >= 3) { 169 | uint8_t t1 = tolower(text[1]); 170 | uint8_t t2 = tolower(text[2]); 171 | 172 | if (t1 == 'c' && t2 == ')') { 173 | HOEDOWN_BUFPUTSL(ob, "©"); 174 | return 2; 175 | } 176 | 177 | if (t1 == 'r' && t2 == ')') { 178 | HOEDOWN_BUFPUTSL(ob, "®"); 179 | return 2; 180 | } 181 | 182 | if (size >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')') { 183 | HOEDOWN_BUFPUTSL(ob, "™"); 184 | return 3; 185 | } 186 | } 187 | 188 | hoedown_buffer_putc(ob, text[0]); 189 | return 0; 190 | } 191 | 192 | /* Converts "--" to em-dash, etc. */ 193 | static size_t 194 | smartypants_cb__dash(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) 195 | { 196 | if (size >= 3 && text[1] == '-' && text[2] == '-') { 197 | HOEDOWN_BUFPUTSL(ob, "—"); 198 | return 2; 199 | } 200 | 201 | if (size >= 2 && text[1] == '-') { 202 | HOEDOWN_BUFPUTSL(ob, "–"); 203 | return 1; 204 | } 205 | 206 | hoedown_buffer_putc(ob, text[0]); 207 | return 0; 208 | } 209 | 210 | /* Converts " etc. */ 211 | static size_t 212 | smartypants_cb__amp(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) 213 | { 214 | size_t len; 215 | if (size >= 6 && memcmp(text, """, 6) == 0) { 216 | if (smartypants_quotes(ob, previous_char, size >= 7 ? text[6] : 0, 'd', &smrt->in_dquote)) 217 | return 5; 218 | } 219 | 220 | len = squote_len(text, size); 221 | if (len > 0) { 222 | return (len-1) + smartypants_squote(ob, smrt, previous_char, text+(len-1), size-(len-1), text, len); 223 | } 224 | 225 | if (size >= 4 && memcmp(text, "�", 4) == 0) 226 | return 3; 227 | 228 | hoedown_buffer_putc(ob, '&'); 229 | return 0; 230 | } 231 | 232 | /* Converts "..." to ellipsis */ 233 | static size_t 234 | smartypants_cb__period(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) 235 | { 236 | if (size >= 3 && text[1] == '.' && text[2] == '.') { 237 | HOEDOWN_BUFPUTSL(ob, "…"); 238 | return 2; 239 | } 240 | 241 | if (size >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.') { 242 | HOEDOWN_BUFPUTSL(ob, "…"); 243 | return 4; 244 | } 245 | 246 | hoedown_buffer_putc(ob, text[0]); 247 | return 0; 248 | } 249 | 250 | /* Converts `` to opening double quote */ 251 | static size_t 252 | smartypants_cb__backtick(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) 253 | { 254 | if (size >= 2 && text[1] == '`') { 255 | if (smartypants_quotes(ob, previous_char, size >= 3 ? text[2] : 0, 'd', &smrt->in_dquote)) 256 | return 1; 257 | } 258 | 259 | hoedown_buffer_putc(ob, text[0]); 260 | return 0; 261 | } 262 | 263 | /* Converts 1/2, 1/4, 3/4 */ 264 | static size_t 265 | smartypants_cb__number(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) 266 | { 267 | if (word_boundary(previous_char) && size >= 3) { 268 | if (text[0] == '1' && text[1] == '/' && text[2] == '2') { 269 | if (size == 3 || word_boundary(text[3])) { 270 | HOEDOWN_BUFPUTSL(ob, "½"); 271 | return 2; 272 | } 273 | } 274 | 275 | if (text[0] == '1' && text[1] == '/' && text[2] == '4') { 276 | if (size == 3 || word_boundary(text[3]) || 277 | (size >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h')) { 278 | HOEDOWN_BUFPUTSL(ob, "¼"); 279 | return 2; 280 | } 281 | } 282 | 283 | if (text[0] == '3' && text[1] == '/' && text[2] == '4') { 284 | if (size == 3 || word_boundary(text[3]) || 285 | (size >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's')) { 286 | HOEDOWN_BUFPUTSL(ob, "¾"); 287 | return 2; 288 | } 289 | } 290 | } 291 | 292 | hoedown_buffer_putc(ob, text[0]); 293 | return 0; 294 | } 295 | 296 | /* Converts " to left or right double quote */ 297 | static size_t 298 | smartypants_cb__dquote(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) 299 | { 300 | if (!smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 'd', &smrt->in_dquote)) 301 | HOEDOWN_BUFPUTSL(ob, """); 302 | 303 | return 0; 304 | } 305 | 306 | static size_t 307 | smartypants_cb__ltag(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) 308 | { 309 | static const char *skip_tags[] = { 310 | "pre", "code", "var", "samp", "kbd", "math", "script", "style" 311 | }; 312 | static const size_t skip_tags_count = 8; 313 | 314 | size_t tag, i = 0; 315 | 316 | /* This is a comment. Copy everything verbatim until --> or EOF is seen. */ 317 | if (i + 4 < size && memcmp(text, "", 3) != 0) 320 | i++; 321 | i += 3; 322 | hoedown_buffer_put(ob, text, i + 1); 323 | return i; 324 | } 325 | 326 | while (i < size && text[i] != '>') 327 | i++; 328 | 329 | for (tag = 0; tag < skip_tags_count; ++tag) { 330 | if (hoedown_html_is_tag(text, size, skip_tags[tag]) == HOEDOWN_HTML_TAG_OPEN) 331 | break; 332 | } 333 | 334 | if (tag < skip_tags_count) { 335 | for (;;) { 336 | while (i < size && text[i] != '<') 337 | i++; 338 | 339 | if (i == size) 340 | break; 341 | 342 | if (hoedown_html_is_tag(text + i, size - i, skip_tags[tag]) == HOEDOWN_HTML_TAG_CLOSE) 343 | break; 344 | 345 | i++; 346 | } 347 | 348 | while (i < size && text[i] != '>') 349 | i++; 350 | } 351 | 352 | hoedown_buffer_put(ob, text, i + 1); 353 | return i; 354 | } 355 | 356 | static size_t 357 | smartypants_cb__escape(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) 358 | { 359 | if (size < 2) 360 | return 0; 361 | 362 | switch (text[1]) { 363 | case '\\': 364 | case '"': 365 | case '\'': 366 | case '.': 367 | case '-': 368 | case '`': 369 | hoedown_buffer_putc(ob, text[1]); 370 | return 1; 371 | 372 | default: 373 | hoedown_buffer_putc(ob, '\\'); 374 | return 0; 375 | } 376 | } 377 | 378 | #if 0 379 | static struct { 380 | uint8_t c0; 381 | const uint8_t *pattern; 382 | const uint8_t *entity; 383 | int skip; 384 | } smartypants_subs[] = { 385 | { '\'', "'s>", "’", 0 }, 386 | { '\'', "'t>", "’", 0 }, 387 | { '\'', "'re>", "’", 0 }, 388 | { '\'', "'ll>", "’", 0 }, 389 | { '\'', "'ve>", "’", 0 }, 390 | { '\'', "'m>", "’", 0 }, 391 | { '\'', "'d>", "’", 0 }, 392 | { '-', "--", "—", 1 }, 393 | { '-', "<->", "–", 0 }, 394 | { '.', "...", "…", 2 }, 395 | { '.', ". . .", "…", 4 }, 396 | { '(', "(c)", "©", 2 }, 397 | { '(', "(r)", "®", 2 }, 398 | { '(', "(tm)", "™", 3 }, 399 | { '3', "<3/4>", "¾", 2 }, 400 | { '3', "<3/4ths>", "¾", 2 }, 401 | { '1', "<1/2>", "½", 2 }, 402 | { '1', "<1/4>", "¼", 2 }, 403 | { '1', "<1/4th>", "¼", 2 }, 404 | { '&', "�", 0, 3 }, 405 | }; 406 | #endif 407 | 408 | void 409 | hoedown_html_smartypants(hoedown_buffer *ob, const uint8_t *text, size_t size) 410 | { 411 | size_t i; 412 | struct smartypants_data smrt = {0, 0}; 413 | 414 | if (!text) 415 | return; 416 | 417 | hoedown_buffer_grow(ob, size); 418 | 419 | for (i = 0; i < size; ++i) { 420 | size_t org; 421 | uint8_t action = 0; 422 | 423 | org = i; 424 | while (i < size && (action = smartypants_cb_chars[text[i]]) == 0) 425 | i++; 426 | 427 | if (i > org) 428 | hoedown_buffer_put(ob, text + org, i - org); 429 | 430 | if (i < size) { 431 | i += smartypants_cb_ptrs[(int)action] 432 | (ob, &smrt, i ? text[i - 1] : 0, text + i, size - i); 433 | } 434 | } 435 | } 436 | -------------------------------------------------------------------------------- /src/html.c: -------------------------------------------------------------------------------- 1 | #include "html.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "escape.h" 9 | 10 | #define USE_XHTML(opt) (opt->flags & HOEDOWN_HTML_USE_XHTML) 11 | 12 | hoedown_html_tag 13 | hoedown_html_is_tag(const uint8_t *data, size_t size, const char *tagname) 14 | { 15 | size_t i; 16 | int closed = 0; 17 | 18 | if (size < 3 || data[0] != '<') 19 | return HOEDOWN_HTML_TAG_NONE; 20 | 21 | i = 1; 22 | 23 | if (data[i] == '/') { 24 | closed = 1; 25 | i++; 26 | } 27 | 28 | for (; i < size; ++i, ++tagname) { 29 | if (*tagname == 0) 30 | break; 31 | 32 | if (data[i] != *tagname) 33 | return HOEDOWN_HTML_TAG_NONE; 34 | } 35 | 36 | if (i == size) 37 | return HOEDOWN_HTML_TAG_NONE; 38 | 39 | if (isspace(data[i]) || data[i] == '>') 40 | return closed ? HOEDOWN_HTML_TAG_CLOSE : HOEDOWN_HTML_TAG_OPEN; 41 | 42 | return HOEDOWN_HTML_TAG_NONE; 43 | } 44 | 45 | static void escape_html(hoedown_buffer *ob, const uint8_t *source, size_t length) 46 | { 47 | hoedown_escape_html(ob, source, length, 0); 48 | } 49 | 50 | static void escape_href(hoedown_buffer *ob, const uint8_t *source, size_t length) 51 | { 52 | hoedown_escape_href(ob, source, length); 53 | } 54 | 55 | /******************** 56 | * GENERIC RENDERER * 57 | ********************/ 58 | static int 59 | rndr_autolink(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data) 60 | { 61 | hoedown_html_renderer_state *state = data->opaque; 62 | 63 | if (!link || !link->size) 64 | return 0; 65 | 66 | HOEDOWN_BUFPUTSL(ob, "data, link->size); 70 | 71 | if (state->link_attributes) { 72 | hoedown_buffer_putc(ob, '\"'); 73 | state->link_attributes(ob, link, data); 74 | hoedown_buffer_putc(ob, '>'); 75 | } else { 76 | HOEDOWN_BUFPUTSL(ob, "\">"); 77 | } 78 | 79 | /* 80 | * Pretty printing: if we get an email address as 81 | * an actual URI, e.g. `mailto:foo@bar.com`, we don't 82 | * want to print the `mailto:` prefix 83 | */ 84 | if (hoedown_buffer_prefix(link, "mailto:") == 0) { 85 | escape_html(ob, link->data + 7, link->size - 7); 86 | } else { 87 | escape_html(ob, link->data, link->size); 88 | } 89 | 90 | HOEDOWN_BUFPUTSL(ob, ""); 91 | 92 | return 1; 93 | } 94 | 95 | static void 96 | rndr_blockcode(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data) 97 | { 98 | if (ob->size) hoedown_buffer_putc(ob, '\n'); 99 | 100 | if (lang) { 101 | HOEDOWN_BUFPUTSL(ob, "
    data, lang->size);
    103 | 		HOEDOWN_BUFPUTSL(ob, "\">");
    104 | 	} else {
    105 | 		HOEDOWN_BUFPUTSL(ob, "
    ");
    106 | 	}
    107 | 
    108 | 	if (text)
    109 | 		escape_html(ob, text->data, text->size);
    110 | 
    111 | 	HOEDOWN_BUFPUTSL(ob, "
    \n"); 112 | } 113 | 114 | static void 115 | rndr_blockquote(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 116 | { 117 | if (ob->size) hoedown_buffer_putc(ob, '\n'); 118 | HOEDOWN_BUFPUTSL(ob, "
    \n"); 119 | if (content) hoedown_buffer_put(ob, content->data, content->size); 120 | HOEDOWN_BUFPUTSL(ob, "
    \n"); 121 | } 122 | 123 | static int 124 | rndr_codespan(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data) 125 | { 126 | HOEDOWN_BUFPUTSL(ob, ""); 127 | if (text) escape_html(ob, text->data, text->size); 128 | HOEDOWN_BUFPUTSL(ob, ""); 129 | return 1; 130 | } 131 | 132 | static int 133 | rndr_strikethrough(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 134 | { 135 | if (!content || !content->size) 136 | return 0; 137 | 138 | HOEDOWN_BUFPUTSL(ob, ""); 139 | hoedown_buffer_put(ob, content->data, content->size); 140 | HOEDOWN_BUFPUTSL(ob, ""); 141 | return 1; 142 | } 143 | 144 | static int 145 | rndr_double_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 146 | { 147 | if (!content || !content->size) 148 | return 0; 149 | 150 | HOEDOWN_BUFPUTSL(ob, ""); 151 | hoedown_buffer_put(ob, content->data, content->size); 152 | HOEDOWN_BUFPUTSL(ob, ""); 153 | 154 | return 1; 155 | } 156 | 157 | static int 158 | rndr_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 159 | { 160 | if (!content || !content->size) return 0; 161 | HOEDOWN_BUFPUTSL(ob, ""); 162 | if (content) hoedown_buffer_put(ob, content->data, content->size); 163 | HOEDOWN_BUFPUTSL(ob, ""); 164 | return 1; 165 | } 166 | 167 | static int 168 | rndr_underline(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 169 | { 170 | if (!content || !content->size) 171 | return 0; 172 | 173 | HOEDOWN_BUFPUTSL(ob, ""); 174 | hoedown_buffer_put(ob, content->data, content->size); 175 | HOEDOWN_BUFPUTSL(ob, ""); 176 | 177 | return 1; 178 | } 179 | 180 | static int 181 | rndr_highlight(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 182 | { 183 | if (!content || !content->size) 184 | return 0; 185 | 186 | HOEDOWN_BUFPUTSL(ob, ""); 187 | hoedown_buffer_put(ob, content->data, content->size); 188 | HOEDOWN_BUFPUTSL(ob, ""); 189 | 190 | return 1; 191 | } 192 | 193 | static int 194 | rndr_quote(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 195 | { 196 | if (!content || !content->size) 197 | return 0; 198 | 199 | HOEDOWN_BUFPUTSL(ob, ""); 200 | hoedown_buffer_put(ob, content->data, content->size); 201 | HOEDOWN_BUFPUTSL(ob, ""); 202 | 203 | return 1; 204 | } 205 | 206 | static int 207 | rndr_linebreak(hoedown_buffer *ob, const hoedown_renderer_data *data) 208 | { 209 | hoedown_html_renderer_state *state = data->opaque; 210 | hoedown_buffer_puts(ob, USE_XHTML(state) ? "
    \n" : "
    \n"); 211 | return 1; 212 | } 213 | 214 | static void 215 | rndr_header(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data) 216 | { 217 | hoedown_html_renderer_state *state = data->opaque; 218 | 219 | if (ob->size) 220 | hoedown_buffer_putc(ob, '\n'); 221 | 222 | if (level <= state->toc_data.nesting_level) 223 | hoedown_buffer_printf(ob, "", level, state->toc_data.header_count++); 224 | else 225 | hoedown_buffer_printf(ob, "", level); 226 | 227 | if (content) hoedown_buffer_put(ob, content->data, content->size); 228 | hoedown_buffer_printf(ob, "\n", level); 229 | } 230 | 231 | static int 232 | rndr_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data) 233 | { 234 | hoedown_html_renderer_state *state = data->opaque; 235 | 236 | HOEDOWN_BUFPUTSL(ob, "size) 239 | escape_href(ob, link->data, link->size); 240 | 241 | if (title && title->size) { 242 | HOEDOWN_BUFPUTSL(ob, "\" title=\""); 243 | escape_html(ob, title->data, title->size); 244 | } 245 | 246 | if (state->link_attributes) { 247 | hoedown_buffer_putc(ob, '\"'); 248 | state->link_attributes(ob, link, data); 249 | hoedown_buffer_putc(ob, '>'); 250 | } else { 251 | HOEDOWN_BUFPUTSL(ob, "\">"); 252 | } 253 | 254 | if (content && content->size) hoedown_buffer_put(ob, content->data, content->size); 255 | HOEDOWN_BUFPUTSL(ob, ""); 256 | return 1; 257 | } 258 | 259 | static void 260 | rndr_list(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data) 261 | { 262 | if (ob->size) hoedown_buffer_putc(ob, '\n'); 263 | hoedown_buffer_put(ob, (const uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "
      \n" : "
        \n"), 5); 264 | if (content) hoedown_buffer_put(ob, content->data, content->size); 265 | hoedown_buffer_put(ob, (const uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "
    \n" : "\n"), 6); 266 | } 267 | 268 | static void 269 | rndr_listitem(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data) 270 | { 271 | HOEDOWN_BUFPUTSL(ob, "
  • "); 272 | if (content) { 273 | size_t size = content->size; 274 | while (size && content->data[size - 1] == '\n') 275 | size--; 276 | 277 | hoedown_buffer_put(ob, content->data, size); 278 | } 279 | HOEDOWN_BUFPUTSL(ob, "
  • \n"); 280 | } 281 | 282 | static void 283 | rndr_paragraph(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 284 | { 285 | hoedown_html_renderer_state *state = data->opaque; 286 | size_t i = 0; 287 | 288 | if (ob->size) hoedown_buffer_putc(ob, '\n'); 289 | 290 | if (!content || !content->size) 291 | return; 292 | 293 | while (i < content->size && isspace(content->data[i])) i++; 294 | 295 | if (i == content->size) 296 | return; 297 | 298 | HOEDOWN_BUFPUTSL(ob, "

    "); 299 | if (state->flags & HOEDOWN_HTML_HARD_WRAP) { 300 | size_t org; 301 | while (i < content->size) { 302 | org = i; 303 | while (i < content->size && content->data[i] != '\n') 304 | i++; 305 | 306 | if (i > org) 307 | hoedown_buffer_put(ob, content->data + org, i - org); 308 | 309 | /* 310 | * do not insert a line break if this newline 311 | * is the last character on the paragraph 312 | */ 313 | if (i >= content->size - 1) 314 | break; 315 | 316 | rndr_linebreak(ob, data); 317 | i++; 318 | } 319 | } else { 320 | hoedown_buffer_put(ob, content->data + i, content->size - i); 321 | } 322 | HOEDOWN_BUFPUTSL(ob, "

    \n"); 323 | } 324 | 325 | static void 326 | rndr_raw_block(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data) 327 | { 328 | size_t org, sz; 329 | 330 | if (!text) 331 | return; 332 | 333 | /* FIXME: Do we *really* need to trim the HTML? How does that make a difference? */ 334 | sz = text->size; 335 | while (sz > 0 && text->data[sz - 1] == '\n') 336 | sz--; 337 | 338 | org = 0; 339 | while (org < sz && text->data[org] == '\n') 340 | org++; 341 | 342 | if (org >= sz) 343 | return; 344 | 345 | if (ob->size) 346 | hoedown_buffer_putc(ob, '\n'); 347 | 348 | hoedown_buffer_put(ob, text->data + org, sz - org); 349 | hoedown_buffer_putc(ob, '\n'); 350 | } 351 | 352 | static int 353 | rndr_triple_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 354 | { 355 | if (!content || !content->size) return 0; 356 | HOEDOWN_BUFPUTSL(ob, ""); 357 | hoedown_buffer_put(ob, content->data, content->size); 358 | HOEDOWN_BUFPUTSL(ob, ""); 359 | return 1; 360 | } 361 | 362 | static void 363 | rndr_hrule(hoedown_buffer *ob, const hoedown_renderer_data *data) 364 | { 365 | hoedown_html_renderer_state *state = data->opaque; 366 | if (ob->size) hoedown_buffer_putc(ob, '\n'); 367 | hoedown_buffer_puts(ob, USE_XHTML(state) ? "
    \n" : "
    \n"); 368 | } 369 | 370 | static int 371 | rndr_image(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data) 372 | { 373 | hoedown_html_renderer_state *state = data->opaque; 374 | if (!link || !link->size) return 0; 375 | 376 | HOEDOWN_BUFPUTSL(ob, "data, link->size); 378 | HOEDOWN_BUFPUTSL(ob, "\" alt=\""); 379 | 380 | if (alt && alt->size) 381 | escape_html(ob, alt->data, alt->size); 382 | 383 | if (title && title->size) { 384 | HOEDOWN_BUFPUTSL(ob, "\" title=\""); 385 | escape_html(ob, title->data, title->size); } 386 | 387 | hoedown_buffer_puts(ob, USE_XHTML(state) ? "\"/>" : "\">"); 388 | return 1; 389 | } 390 | 391 | static int 392 | rndr_raw_html(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data) 393 | { 394 | hoedown_html_renderer_state *state = data->opaque; 395 | 396 | /* ESCAPE overrides SKIP_HTML. It doesn't look to see if 397 | * there are any valid tags, just escapes all of them. */ 398 | if((state->flags & HOEDOWN_HTML_ESCAPE) != 0) { 399 | escape_html(ob, text->data, text->size); 400 | return 1; 401 | } 402 | 403 | if ((state->flags & HOEDOWN_HTML_SKIP_HTML) != 0) 404 | return 1; 405 | 406 | hoedown_buffer_put(ob, text->data, text->size); 407 | return 1; 408 | } 409 | 410 | static void 411 | rndr_table(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 412 | { 413 | if (ob->size) hoedown_buffer_putc(ob, '\n'); 414 | HOEDOWN_BUFPUTSL(ob, "\n"); 415 | hoedown_buffer_put(ob, content->data, content->size); 416 | HOEDOWN_BUFPUTSL(ob, "
    \n"); 417 | } 418 | 419 | static void 420 | rndr_table_header(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 421 | { 422 | if (ob->size) hoedown_buffer_putc(ob, '\n'); 423 | HOEDOWN_BUFPUTSL(ob, "\n"); 424 | hoedown_buffer_put(ob, content->data, content->size); 425 | HOEDOWN_BUFPUTSL(ob, "\n"); 426 | } 427 | 428 | static void 429 | rndr_table_body(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 430 | { 431 | if (ob->size) hoedown_buffer_putc(ob, '\n'); 432 | HOEDOWN_BUFPUTSL(ob, "\n"); 433 | hoedown_buffer_put(ob, content->data, content->size); 434 | HOEDOWN_BUFPUTSL(ob, "\n"); 435 | } 436 | 437 | static void 438 | rndr_tablerow(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 439 | { 440 | HOEDOWN_BUFPUTSL(ob, "\n"); 441 | if (content) hoedown_buffer_put(ob, content->data, content->size); 442 | HOEDOWN_BUFPUTSL(ob, "\n"); 443 | } 444 | 445 | static void 446 | rndr_tablecell(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data) 447 | { 448 | if (flags & HOEDOWN_TABLE_HEADER) { 449 | HOEDOWN_BUFPUTSL(ob, ""); 457 | break; 458 | 459 | case HOEDOWN_TABLE_ALIGN_LEFT: 460 | HOEDOWN_BUFPUTSL(ob, " style=\"text-align: left\">"); 461 | break; 462 | 463 | case HOEDOWN_TABLE_ALIGN_RIGHT: 464 | HOEDOWN_BUFPUTSL(ob, " style=\"text-align: right\">"); 465 | break; 466 | 467 | default: 468 | HOEDOWN_BUFPUTSL(ob, ">"); 469 | } 470 | 471 | if (content) 472 | hoedown_buffer_put(ob, content->data, content->size); 473 | 474 | if (flags & HOEDOWN_TABLE_HEADER) { 475 | HOEDOWN_BUFPUTSL(ob, "\n"); 476 | } else { 477 | HOEDOWN_BUFPUTSL(ob, "\n"); 478 | } 479 | } 480 | 481 | static int 482 | rndr_superscript(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 483 | { 484 | if (!content || !content->size) return 0; 485 | HOEDOWN_BUFPUTSL(ob, ""); 486 | hoedown_buffer_put(ob, content->data, content->size); 487 | HOEDOWN_BUFPUTSL(ob, ""); 488 | return 1; 489 | } 490 | 491 | static void 492 | rndr_normal_text(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 493 | { 494 | if (content) 495 | escape_html(ob, content->data, content->size); 496 | } 497 | 498 | static void 499 | rndr_footnotes(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) 500 | { 501 | hoedown_html_renderer_state *state = data->opaque; 502 | 503 | if (ob->size) hoedown_buffer_putc(ob, '\n'); 504 | HOEDOWN_BUFPUTSL(ob, "
    \n"); 505 | hoedown_buffer_puts(ob, USE_XHTML(state) ? "
    \n" : "
    \n"); 506 | HOEDOWN_BUFPUTSL(ob, "
      \n"); 507 | 508 | if (content) hoedown_buffer_put(ob, content->data, content->size); 509 | 510 | HOEDOWN_BUFPUTSL(ob, "\n
    \n
    \n"); 511 | } 512 | 513 | static void 514 | rndr_footnote_def(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data) 515 | { 516 | size_t i = 0; 517 | int pfound = 0; 518 | 519 | /* insert anchor at the end of first paragraph block */ 520 | if (content) { 521 | while ((i+3) < content->size) { 522 | if (content->data[i++] != '<') continue; 523 | if (content->data[i++] != '/') continue; 524 | if (content->data[i++] != 'p' && content->data[i] != 'P') continue; 525 | if (content->data[i] != '>') continue; 526 | i -= 3; 527 | pfound = 1; 528 | break; 529 | } 530 | } 531 | 532 | hoedown_buffer_printf(ob, "\n
  • \n", num); 533 | if (pfound) { 534 | hoedown_buffer_put(ob, content->data, i); 535 | hoedown_buffer_printf(ob, " ", num); 536 | hoedown_buffer_put(ob, content->data + i, content->size - i); 537 | } else if (content) { 538 | hoedown_buffer_put(ob, content->data, content->size); 539 | } 540 | HOEDOWN_BUFPUTSL(ob, "
  • \n"); 541 | } 542 | 543 | static int 544 | rndr_footnote_ref(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data) 545 | { 546 | hoedown_buffer_printf(ob, "%d", num, num, num); 547 | return 1; 548 | } 549 | 550 | static int 551 | rndr_math(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data) 552 | { 553 | hoedown_buffer_put(ob, (const uint8_t *)(displaymode ? "\\[" : "\\("), 2); 554 | escape_html(ob, text->data, text->size); 555 | hoedown_buffer_put(ob, (const uint8_t *)(displaymode ? "\\]" : "\\)"), 2); 556 | return 1; 557 | } 558 | 559 | static void 560 | toc_header(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data) 561 | { 562 | hoedown_html_renderer_state *state = data->opaque; 563 | 564 | if (level <= state->toc_data.nesting_level) { 565 | /* set the level offset if this is the first header 566 | * we're parsing for the document */ 567 | if (state->toc_data.current_level == 0) 568 | state->toc_data.level_offset = level - 1; 569 | 570 | level -= state->toc_data.level_offset; 571 | 572 | if (level > state->toc_data.current_level) { 573 | while (level > state->toc_data.current_level) { 574 | HOEDOWN_BUFPUTSL(ob, "
      \n
    • \n"); 575 | state->toc_data.current_level++; 576 | } 577 | } else if (level < state->toc_data.current_level) { 578 | HOEDOWN_BUFPUTSL(ob, "
    • \n"); 579 | while (level < state->toc_data.current_level) { 580 | HOEDOWN_BUFPUTSL(ob, "
    \n
  • \n"); 581 | state->toc_data.current_level--; 582 | } 583 | HOEDOWN_BUFPUTSL(ob,"
  • \n"); 584 | } else { 585 | HOEDOWN_BUFPUTSL(ob,"
  • \n
  • \n"); 586 | } 587 | 588 | hoedown_buffer_printf(ob, "", state->toc_data.header_count++); 589 | if (content) hoedown_buffer_put(ob, content->data, content->size); 590 | HOEDOWN_BUFPUTSL(ob, "\n"); 591 | } 592 | } 593 | 594 | static int 595 | toc_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data) 596 | { 597 | if (content && content->size) hoedown_buffer_put(ob, content->data, content->size); 598 | return 1; 599 | } 600 | 601 | static void 602 | toc_finalize(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data) 603 | { 604 | hoedown_html_renderer_state *state; 605 | 606 | if (inline_render) 607 | return; 608 | 609 | state = data->opaque; 610 | 611 | while (state->toc_data.current_level > 0) { 612 | HOEDOWN_BUFPUTSL(ob, "
  • \n\n"); 613 | state->toc_data.current_level--; 614 | } 615 | 616 | state->toc_data.header_count = 0; 617 | } 618 | 619 | hoedown_renderer * 620 | hoedown_html_toc_renderer_new(int nesting_level) 621 | { 622 | static const hoedown_renderer cb_default = { 623 | NULL, 624 | 625 | NULL, 626 | NULL, 627 | toc_header, 628 | NULL, 629 | NULL, 630 | NULL, 631 | NULL, 632 | NULL, 633 | NULL, 634 | NULL, 635 | NULL, 636 | NULL, 637 | NULL, 638 | NULL, 639 | NULL, 640 | 641 | NULL, 642 | rndr_codespan, 643 | rndr_double_emphasis, 644 | rndr_emphasis, 645 | rndr_underline, 646 | rndr_highlight, 647 | rndr_quote, 648 | NULL, 649 | NULL, 650 | toc_link, 651 | rndr_triple_emphasis, 652 | rndr_strikethrough, 653 | rndr_superscript, 654 | NULL, 655 | NULL, 656 | NULL, 657 | 658 | NULL, 659 | rndr_normal_text, 660 | 661 | NULL, 662 | toc_finalize 663 | }; 664 | 665 | hoedown_html_renderer_state *state; 666 | hoedown_renderer *renderer; 667 | 668 | /* Prepare the state pointer */ 669 | state = hoedown_malloc(sizeof(hoedown_html_renderer_state)); 670 | memset(state, 0x0, sizeof(hoedown_html_renderer_state)); 671 | 672 | state->toc_data.nesting_level = nesting_level; 673 | 674 | /* Prepare the renderer */ 675 | renderer = hoedown_malloc(sizeof(hoedown_renderer)); 676 | memcpy(renderer, &cb_default, sizeof(hoedown_renderer)); 677 | 678 | renderer->opaque = state; 679 | return renderer; 680 | } 681 | 682 | hoedown_renderer * 683 | hoedown_html_renderer_new(hoedown_html_flags render_flags, int nesting_level) 684 | { 685 | static const hoedown_renderer cb_default = { 686 | NULL, 687 | 688 | rndr_blockcode, 689 | rndr_blockquote, 690 | rndr_header, 691 | rndr_hrule, 692 | rndr_list, 693 | rndr_listitem, 694 | rndr_paragraph, 695 | rndr_table, 696 | rndr_table_header, 697 | rndr_table_body, 698 | rndr_tablerow, 699 | rndr_tablecell, 700 | rndr_footnotes, 701 | rndr_footnote_def, 702 | rndr_raw_block, 703 | 704 | rndr_autolink, 705 | rndr_codespan, 706 | rndr_double_emphasis, 707 | rndr_emphasis, 708 | rndr_underline, 709 | rndr_highlight, 710 | rndr_quote, 711 | rndr_image, 712 | rndr_linebreak, 713 | rndr_link, 714 | rndr_triple_emphasis, 715 | rndr_strikethrough, 716 | rndr_superscript, 717 | rndr_footnote_ref, 718 | rndr_math, 719 | rndr_raw_html, 720 | 721 | NULL, 722 | rndr_normal_text, 723 | 724 | NULL, 725 | NULL 726 | }; 727 | 728 | hoedown_html_renderer_state *state; 729 | hoedown_renderer *renderer; 730 | 731 | /* Prepare the state pointer */ 732 | state = hoedown_malloc(sizeof(hoedown_html_renderer_state)); 733 | memset(state, 0x0, sizeof(hoedown_html_renderer_state)); 734 | 735 | state->flags = render_flags; 736 | state->toc_data.nesting_level = nesting_level; 737 | 738 | /* Prepare the renderer */ 739 | renderer = hoedown_malloc(sizeof(hoedown_renderer)); 740 | memcpy(renderer, &cb_default, sizeof(hoedown_renderer)); 741 | 742 | if (render_flags & HOEDOWN_HTML_SKIP_HTML || render_flags & HOEDOWN_HTML_ESCAPE) 743 | renderer->blockhtml = NULL; 744 | 745 | renderer->opaque = state; 746 | return renderer; 747 | } 748 | 749 | void 750 | hoedown_html_renderer_free(hoedown_renderer *renderer) 751 | { 752 | free(renderer->opaque); 753 | free(renderer); 754 | } 755 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Markdown Documentation - Syntax.text: -------------------------------------------------------------------------------- 1 | Markdown: Syntax 2 | ================ 3 | 4 | 11 | 12 | 13 | * [Overview](#overview) 14 | * [Philosophy](#philosophy) 15 | * [Inline HTML](#html) 16 | * [Automatic Escaping for Special Characters](#autoescape) 17 | * [Block Elements](#block) 18 | * [Paragraphs and Line Breaks](#p) 19 | * [Headers](#header) 20 | * [Blockquotes](#blockquote) 21 | * [Lists](#list) 22 | * [Code Blocks](#precode) 23 | * [Horizontal Rules](#hr) 24 | * [Span Elements](#span) 25 | * [Links](#link) 26 | * [Emphasis](#em) 27 | * [Code](#code) 28 | * [Images](#img) 29 | * [Miscellaneous](#misc) 30 | * [Backslash Escapes](#backslash) 31 | * [Automatic Links](#autolink) 32 | 33 | 34 | **Note:** This document is itself written using Markdown; you 35 | can [see the source for it by adding '.text' to the URL][src]. 36 | 37 | [src]: /projects/markdown/syntax.text 38 | 39 | * * * 40 | 41 |

    Overview

    42 | 43 |

    Philosophy

    44 | 45 | Markdown is intended to be as easy-to-read and easy-to-write as is feasible. 46 | 47 | Readability, however, is emphasized above all else. A Markdown-formatted 48 | document should be publishable as-is, as plain text, without looking 49 | like it's been marked up with tags or formatting instructions. While 50 | Markdown's syntax has been influenced by several existing text-to-HTML 51 | filters -- including [Setext] [1], [atx] [2], [Textile] [3], [reStructuredText] [4], 52 | [Grutatext] [5], and [EtText] [6] -- the single biggest source of 53 | inspiration for Markdown's syntax is the format of plain text email. 54 | 55 | [1]: http://docutils.sourceforge.net/mirror/setext.html 56 | [2]: http://www.aaronsw.com/2002/atx/ 57 | [3]: http://textism.com/tools/textile/ 58 | [4]: http://docutils.sourceforge.net/rst.html 59 | [5]: http://www.triptico.com/software/grutatxt.html 60 | [6]: http://ettext.taint.org/doc/ 61 | 62 | To this end, Markdown's syntax is comprised entirely of punctuation 63 | characters, which punctuation characters have been carefully chosen so 64 | as to look like what they mean. E.g., asterisks around a word actually 65 | look like \*emphasis\*. Markdown lists look like, well, lists. Even 66 | blockquotes look like quoted passages of text, assuming you've ever 67 | used email. 68 | 69 | 70 | 71 |

    Inline HTML

    72 | 73 | Markdown's syntax is intended for one purpose: to be used as a 74 | format for *writing* for the web. 75 | 76 | Markdown is not a replacement for HTML, or even close to it. Its 77 | syntax is very small, corresponding only to a very small subset of 78 | HTML tags. The idea is *not* to create a syntax that makes it easier 79 | to insert HTML tags. In my opinion, HTML tags are already easy to 80 | insert. The idea for Markdown is to make it easy to read, write, and 81 | edit prose. HTML is a *publishing* format; Markdown is a *writing* 82 | format. Thus, Markdown's formatting syntax only addresses issues that 83 | can be conveyed in plain text. 84 | 85 | For any markup that is not covered by Markdown's syntax, you simply 86 | use HTML itself. There's no need to preface it or delimit it to 87 | indicate that you're switching from Markdown to HTML; you just use 88 | the tags. 89 | 90 | The only restrictions are that block-level HTML elements -- e.g. `
    `, 91 | ``, `
    `, `

    `, etc. -- must be separated from surrounding 92 | content by blank lines, and the start and end tags of the block should 93 | not be indented with tabs or spaces. Markdown is smart enough not 94 | to add extra (unwanted) `

    ` tags around HTML block-level tags. 95 | 96 | For example, to add an HTML table to a Markdown article: 97 | 98 | This is a regular paragraph. 99 | 100 |

    101 | 102 | 103 | 104 |
    Foo
    105 | 106 | This is another regular paragraph. 107 | 108 | Note that Markdown formatting syntax is not processed within block-level 109 | HTML tags. E.g., you can't use Markdown-style `*emphasis*` inside an 110 | HTML block. 111 | 112 | Span-level HTML tags -- e.g. ``, ``, or `` -- can be 113 | used anywhere in a Markdown paragraph, list item, or header. If you 114 | want, you can even use HTML tags instead of Markdown formatting; e.g. if 115 | you'd prefer to use HTML `` or `` tags instead of Markdown's 116 | link or image syntax, go right ahead. 117 | 118 | Unlike block-level HTML tags, Markdown syntax *is* processed within 119 | span-level tags. 120 | 121 | 122 |

    Automatic Escaping for Special Characters

    123 | 124 | In HTML, there are two characters that demand special treatment: `<` 125 | and `&`. Left angle brackets are used to start tags; ampersands are 126 | used to denote HTML entities. If you want to use them as literal 127 | characters, you must escape them as entities, e.g. `<`, and 128 | `&`. 129 | 130 | Ampersands in particular are bedeviling for web writers. If you want to 131 | write about 'AT&T', you need to write '`AT&T`'. You even need to 132 | escape ampersands within URLs. Thus, if you want to link to: 133 | 134 | http://images.google.com/images?num=30&q=larry+bird 135 | 136 | you need to encode the URL as: 137 | 138 | http://images.google.com/images?num=30&q=larry+bird 139 | 140 | in your anchor tag `href` attribute. Needless to say, this is easy to 141 | forget, and is probably the single most common source of HTML validation 142 | errors in otherwise well-marked-up web sites. 143 | 144 | Markdown allows you to use these characters naturally, taking care of 145 | all the necessary escaping for you. If you use an ampersand as part of 146 | an HTML entity, it remains unchanged; otherwise it will be translated 147 | into `&`. 148 | 149 | So, if you want to include a copyright symbol in your article, you can write: 150 | 151 | © 152 | 153 | and Markdown will leave it alone. But if you write: 154 | 155 | AT&T 156 | 157 | Markdown will translate it to: 158 | 159 | AT&T 160 | 161 | Similarly, because Markdown supports [inline HTML](#html), if you use 162 | angle brackets as delimiters for HTML tags, Markdown will treat them as 163 | such. But if you write: 164 | 165 | 4 < 5 166 | 167 | Markdown will translate it to: 168 | 169 | 4 < 5 170 | 171 | However, inside Markdown code spans and blocks, angle brackets and 172 | ampersands are *always* encoded automatically. This makes it easy to use 173 | Markdown to write about HTML code. (As opposed to raw HTML, which is a 174 | terrible format for writing about HTML syntax, because every single `<` 175 | and `&` in your example code needs to be escaped.) 176 | 177 | 178 | * * * 179 | 180 | 181 |

    Block Elements

    182 | 183 | 184 |

    Paragraphs and Line Breaks

    185 | 186 | A paragraph is simply one or more consecutive lines of text, separated 187 | by one or more blank lines. (A blank line is any line that looks like a 188 | blank line -- a line containing nothing but spaces or tabs is considered 189 | blank.) Normal paragraphs should not be intended with spaces or tabs. 190 | 191 | The implication of the "one or more consecutive lines of text" rule is 192 | that Markdown supports "hard-wrapped" text paragraphs. This differs 193 | significantly from most other text-to-HTML formatters (including Movable 194 | Type's "Convert Line Breaks" option) which translate every line break 195 | character in a paragraph into a `
    ` tag. 196 | 197 | When you *do* want to insert a `
    ` break tag using Markdown, you 198 | end a line with two or more spaces, then type return. 199 | 200 | Yes, this takes a tad more effort to create a `
    `, but a simplistic 201 | "every line break is a `
    `" rule wouldn't work for Markdown. 202 | Markdown's email-style [blockquoting][bq] and multi-paragraph [list items][l] 203 | work best -- and look better -- when you format them with hard breaks. 204 | 205 | [bq]: #blockquote 206 | [l]: #list 207 | 208 | 209 | 210 | 211 | 212 | Markdown supports two styles of headers, [Setext] [1] and [atx] [2]. 213 | 214 | Setext-style headers are "underlined" using equal signs (for first-level 215 | headers) and dashes (for second-level headers). For example: 216 | 217 | This is an H1 218 | ============= 219 | 220 | This is an H2 221 | ------------- 222 | 223 | Any number of underlining `=`'s or `-`'s will work. 224 | 225 | Atx-style headers use 1-6 hash characters at the start of the line, 226 | corresponding to header levels 1-6. For example: 227 | 228 | # This is an H1 229 | 230 | ## This is an H2 231 | 232 | ###### This is an H6 233 | 234 | Optionally, you may "close" atx-style headers. This is purely 235 | cosmetic -- you can use this if you think it looks better. The 236 | closing hashes don't even need to match the number of hashes 237 | used to open the header. (The number of opening hashes 238 | determines the header level.) : 239 | 240 | # This is an H1 # 241 | 242 | ## This is an H2 ## 243 | 244 | ### This is an H3 ###### 245 | 246 | 247 |

    Blockquotes

    248 | 249 | Markdown uses email-style `>` characters for blockquoting. If you're 250 | familiar with quoting passages of text in an email message, then you 251 | know how to create a blockquote in Markdown. It looks best if you hard 252 | wrap the text and put a `>` before every line: 253 | 254 | > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, 255 | > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. 256 | > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. 257 | > 258 | > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse 259 | > id sem consectetuer libero luctus adipiscing. 260 | 261 | Markdown allows you to be lazy and only put the `>` before the first 262 | line of a hard-wrapped paragraph: 263 | 264 | > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, 265 | consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. 266 | Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. 267 | 268 | > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse 269 | id sem consectetuer libero luctus adipiscing. 270 | 271 | Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by 272 | adding additional levels of `>`: 273 | 274 | > This is the first level of quoting. 275 | > 276 | > > This is nested blockquote. 277 | > 278 | > Back to the first level. 279 | 280 | Blockquotes can contain other Markdown elements, including headers, lists, 281 | and code blocks: 282 | 283 | > ## This is a header. 284 | > 285 | > 1. This is the first list item. 286 | > 2. This is the second list item. 287 | > 288 | > Here's some example code: 289 | > 290 | > return shell_exec("echo $input | $markdown_script"); 291 | 292 | Any decent text editor should make email-style quoting easy. For 293 | example, with BBEdit, you can make a selection and choose Increase 294 | Quote Level from the Text menu. 295 | 296 | 297 |

    Lists

    298 | 299 | Markdown supports ordered (numbered) and unordered (bulleted) lists. 300 | 301 | Unordered lists use asterisks, pluses, and hyphens -- interchangably 302 | -- as list markers: 303 | 304 | * Red 305 | * Green 306 | * Blue 307 | 308 | is equivalent to: 309 | 310 | + Red 311 | + Green 312 | + Blue 313 | 314 | and: 315 | 316 | - Red 317 | - Green 318 | - Blue 319 | 320 | Ordered lists use numbers followed by periods: 321 | 322 | 1. Bird 323 | 2. McHale 324 | 3. Parish 325 | 326 | It's important to note that the actual numbers you use to mark the 327 | list have no effect on the HTML output Markdown produces. The HTML 328 | Markdown produces from the above list is: 329 | 330 |
      331 |
    1. Bird
    2. 332 |
    3. McHale
    4. 333 |
    5. Parish
    6. 334 |
    335 | 336 | If you instead wrote the list in Markdown like this: 337 | 338 | 1. Bird 339 | 1. McHale 340 | 1. Parish 341 | 342 | or even: 343 | 344 | 3. Bird 345 | 1. McHale 346 | 8. Parish 347 | 348 | you'd get the exact same HTML output. The point is, if you want to, 349 | you can use ordinal numbers in your ordered Markdown lists, so that 350 | the numbers in your source match the numbers in your published HTML. 351 | But if you want to be lazy, you don't have to. 352 | 353 | If you do use lazy list numbering, however, you should still start the 354 | list with the number 1. At some point in the future, Markdown may support 355 | starting ordered lists at an arbitrary number. 356 | 357 | List markers typically start at the left margin, but may be indented by 358 | up to three spaces. List markers must be followed by one or more spaces 359 | or a tab. 360 | 361 | To make lists look nice, you can wrap items with hanging indents: 362 | 363 | * Lorem ipsum dolor sit amet, consectetuer adipiscing elit. 364 | Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, 365 | viverra nec, fringilla in, laoreet vitae, risus. 366 | * Donec sit amet nisl. Aliquam semper ipsum sit amet velit. 367 | Suspendisse id sem consectetuer libero luctus adipiscing. 368 | 369 | But if you want to be lazy, you don't have to: 370 | 371 | * Lorem ipsum dolor sit amet, consectetuer adipiscing elit. 372 | Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, 373 | viverra nec, fringilla in, laoreet vitae, risus. 374 | * Donec sit amet nisl. Aliquam semper ipsum sit amet velit. 375 | Suspendisse id sem consectetuer libero luctus adipiscing. 376 | 377 | If list items are separated by blank lines, Markdown will wrap the 378 | items in `

    ` tags in the HTML output. For example, this input: 379 | 380 | * Bird 381 | * Magic 382 | 383 | will turn into: 384 | 385 |

      386 |
    • Bird
    • 387 |
    • Magic
    • 388 |
    389 | 390 | But this: 391 | 392 | * Bird 393 | 394 | * Magic 395 | 396 | will turn into: 397 | 398 |
      399 |
    • Bird

    • 400 |
    • Magic

    • 401 |
    402 | 403 | List items may consist of multiple paragraphs. Each subsequent 404 | paragraph in a list item must be intended by either 4 spaces 405 | or one tab: 406 | 407 | 1. This is a list item with two paragraphs. Lorem ipsum dolor 408 | sit amet, consectetuer adipiscing elit. Aliquam hendrerit 409 | mi posuere lectus. 410 | 411 | Vestibulum enim wisi, viverra nec, fringilla in, laoreet 412 | vitae, risus. Donec sit amet nisl. Aliquam semper ipsum 413 | sit amet velit. 414 | 415 | 2. Suspendisse id sem consectetuer libero luctus adipiscing. 416 | 417 | It looks nice if you indent every line of the subsequent 418 | paragraphs, but here again, Markdown will allow you to be 419 | lazy: 420 | 421 | * This is a list item with two paragraphs. 422 | 423 | This is the second paragraph in the list item. You're 424 | only required to indent the first line. Lorem ipsum dolor 425 | sit amet, consectetuer adipiscing elit. 426 | 427 | * Another item in the same list. 428 | 429 | To put a blockquote within a list item, the blockquote's `>` 430 | delimiters need to be indented: 431 | 432 | * A list item with a blockquote: 433 | 434 | > This is a blockquote 435 | > inside a list item. 436 | 437 | To put a code block within a list item, the code block needs 438 | to be indented *twice* -- 8 spaces or two tabs: 439 | 440 | * A list item with a code block: 441 | 442 | 443 | 444 | 445 | It's worth noting that it's possible to trigger an ordered list by 446 | accident, by writing something like this: 447 | 448 | 1986. What a great season. 449 | 450 | In other words, a *number-period-space* sequence at the beginning of a 451 | line. To avoid this, you can backslash-escape the period: 452 | 453 | 1986\. What a great season. 454 | 455 | 456 | 457 |

    Code Blocks

    458 | 459 | Pre-formatted code blocks are used for writing about programming or 460 | markup source code. Rather than forming normal paragraphs, the lines 461 | of a code block are interpreted literally. Markdown wraps a code block 462 | in both `
    ` and `` tags.
    463 | 
    464 | To produce a code block in Markdown, simply indent every line of the
    465 | block by at least 4 spaces or 1 tab. For example, given this input:
    466 | 
    467 |     This is a normal paragraph:
    468 | 
    469 |         This is a code block.
    470 | 
    471 | Markdown will generate:
    472 | 
    473 |     

    This is a normal paragraph:

    474 | 475 |
    This is a code block.
    476 |     
    477 | 478 | One level of indentation -- 4 spaces or 1 tab -- is removed from each 479 | line of the code block. For example, this: 480 | 481 | Here is an example of AppleScript: 482 | 483 | tell application "Foo" 484 | beep 485 | end tell 486 | 487 | will turn into: 488 | 489 |

    Here is an example of AppleScript:

    490 | 491 |
    tell application "Foo"
    492 |         beep
    493 |     end tell
    494 |     
    495 | 496 | A code block continues until it reaches a line that is not indented 497 | (or the end of the article). 498 | 499 | Within a code block, ampersands (`&`) and angle brackets (`<` and `>`) 500 | are automatically converted into HTML entities. This makes it very 501 | easy to include example HTML source code using Markdown -- just paste 502 | it and indent it, and Markdown will handle the hassle of encoding the 503 | ampersands and angle brackets. For example, this: 504 | 505 | 508 | 509 | will turn into: 510 | 511 |
    <div class="footer">
    512 |         &copy; 2004 Foo Corporation
    513 |     </div>
    514 |     
    515 | 516 | Regular Markdown syntax is not processed within code blocks. E.g., 517 | asterisks are just literal asterisks within a code block. This means 518 | it's also easy to use Markdown to write about Markdown's own syntax. 519 | 520 | 521 | 522 |

    Horizontal Rules

    523 | 524 | You can produce a horizontal rule tag (`
    `) by placing three or 525 | more hyphens, asterisks, or underscores on a line by themselves. If you 526 | wish, you may use spaces between the hyphens or asterisks. Each of the 527 | following lines will produce a horizontal rule: 528 | 529 | * * * 530 | 531 | *** 532 | 533 | ***** 534 | 535 | - - - 536 | 537 | --------------------------------------- 538 | 539 | _ _ _ 540 | 541 | 542 | * * * 543 | 544 |

    Span Elements

    545 | 546 | 547 | 548 | Markdown supports two style of links: *inline* and *reference*. 549 | 550 | In both styles, the link text is delimited by [square brackets]. 551 | 552 | To create an inline link, use a set of regular parentheses immediately 553 | after the link text's closing square bracket. Inside the parentheses, 554 | put the URL where you want the link to point, along with an *optional* 555 | title for the link, surrounded in quotes. For example: 556 | 557 | This is [an example](http://example.com/ "Title") inline link. 558 | 559 | [This link](http://example.net/) has no title attribute. 560 | 561 | Will produce: 562 | 563 |

    This is 564 | an example inline link.

    565 | 566 |

    This link has no 567 | title attribute.

    568 | 569 | If you're referring to a local resource on the same server, you can 570 | use relative paths: 571 | 572 | See my [About](/about/) page for details. 573 | 574 | Reference-style links use a second set of square brackets, inside 575 | which you place a label of your choosing to identify the link: 576 | 577 | This is [an example][id] reference-style link. 578 | 579 | You can optionally use a space to separate the sets of brackets: 580 | 581 | This is [an example] [id] reference-style link. 582 | 583 | Then, anywhere in the document, you define your link label like this, 584 | on a line by itself: 585 | 586 | [id]: http://example.com/ "Optional Title Here" 587 | 588 | That is: 589 | 590 | * Square brackets containing the link identifier (optionally 591 | indented from the left margin using up to three spaces); 592 | * followed by a colon; 593 | * followed by one or more spaces (or tabs); 594 | * followed by the URL for the link; 595 | * optionally followed by a title attribute for the link, enclosed 596 | in double or single quotes. 597 | 598 | The link URL may, optionally, be surrounded by angle brackets: 599 | 600 | [id]: "Optional Title Here" 601 | 602 | You can put the title attribute on the next line and use extra spaces 603 | or tabs for padding, which tends to look better with longer URLs: 604 | 605 | [id]: http://example.com/longish/path/to/resource/here 606 | "Optional Title Here" 607 | 608 | Link definitions are only used for creating links during Markdown 609 | processing, and are stripped from your document in the HTML output. 610 | 611 | Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are *not* case sensitive. E.g. these two links: 612 | 613 | [link text][a] 614 | [link text][A] 615 | 616 | are equivalent. 617 | 618 | The *implicit link name* shortcut allows you to omit the name of the 619 | link, in which case the link text itself is used as the name. 620 | Just use an empty set of square brackets -- e.g., to link the word 621 | "Google" to the google.com web site, you could simply write: 622 | 623 | [Google][] 624 | 625 | And then define the link: 626 | 627 | [Google]: http://google.com/ 628 | 629 | Because link names may contain spaces, this shortcut even works for 630 | multiple words in the link text: 631 | 632 | Visit [Daring Fireball][] for more information. 633 | 634 | And then define the link: 635 | 636 | [Daring Fireball]: http://daringfireball.net/ 637 | 638 | Link definitions can be placed anywhere in your Markdown document. I 639 | tend to put them immediately after each paragraph in which they're 640 | used, but if you want, you can put them all at the end of your 641 | document, sort of like footnotes. 642 | 643 | Here's an example of reference links in action: 644 | 645 | I get 10 times more traffic from [Google] [1] than from 646 | [Yahoo] [2] or [MSN] [3]. 647 | 648 | [1]: http://google.com/ "Google" 649 | [2]: http://search.yahoo.com/ "Yahoo Search" 650 | [3]: http://search.msn.com/ "MSN Search" 651 | 652 | Using the implicit link name shortcut, you could instead write: 653 | 654 | I get 10 times more traffic from [Google][] than from 655 | [Yahoo][] or [MSN][]. 656 | 657 | [google]: http://google.com/ "Google" 658 | [yahoo]: http://search.yahoo.com/ "Yahoo Search" 659 | [msn]: http://search.msn.com/ "MSN Search" 660 | 661 | Both of the above examples will produce the following HTML output: 662 | 663 |

    I get 10 times more traffic from Google than from 665 | Yahoo 666 | or MSN.

    667 | 668 | For comparison, here is the same paragraph written using 669 | Markdown's inline link style: 670 | 671 | I get 10 times more traffic from [Google](http://google.com/ "Google") 672 | than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or 673 | [MSN](http://search.msn.com/ "MSN Search"). 674 | 675 | The point of reference-style links is not that they're easier to 676 | write. The point is that with reference-style links, your document 677 | source is vastly more readable. Compare the above examples: using 678 | reference-style links, the paragraph itself is only 81 characters 679 | long; with inline-style links, it's 176 characters; and as raw HTML, 680 | it's 234 characters. In the raw HTML, there's more markup than there 681 | is text. 682 | 683 | With Markdown's reference-style links, a source document much more 684 | closely resembles the final output, as rendered in a browser. By 685 | allowing you to move the markup-related metadata out of the paragraph, 686 | you can add links without interrupting the narrative flow of your 687 | prose. 688 | 689 | 690 |

    Emphasis

    691 | 692 | Markdown treats asterisks (`*`) and underscores (`_`) as indicators of 693 | emphasis. Text wrapped with one `*` or `_` will be wrapped with an 694 | HTML `` tag; double `*`'s or `_`'s will be wrapped with an HTML 695 | `` tag. E.g., this input: 696 | 697 | *single asterisks* 698 | 699 | _single underscores_ 700 | 701 | **double asterisks** 702 | 703 | __double underscores__ 704 | 705 | will produce: 706 | 707 | single asterisks 708 | 709 | single underscores 710 | 711 | double asterisks 712 | 713 | double underscores 714 | 715 | You can use whichever style you prefer; the lone restriction is that 716 | the same character must be used to open and close an emphasis span. 717 | 718 | Emphasis can be used in the middle of a word: 719 | 720 | un*fucking*believable 721 | 722 | But if you surround an `*` or `_` with spaces, it'll be treated as a 723 | literal asterisk or underscore. 724 | 725 | To produce a literal asterisk or underscore at a position where it 726 | would otherwise be used as an emphasis delimiter, you can backslash 727 | escape it: 728 | 729 | \*this text is surrounded by literal asterisks\* 730 | 731 | 732 | 733 |

    Code

    734 | 735 | To indicate a span of code, wrap it with backtick quotes (`` ` ``). 736 | Unlike a pre-formatted code block, a code span indicates code within a 737 | normal paragraph. For example: 738 | 739 | Use the `printf()` function. 740 | 741 | will produce: 742 | 743 |

    Use the printf() function.

    744 | 745 | To include a literal backtick character within a code span, you can use 746 | multiple backticks as the opening and closing delimiters: 747 | 748 | ``There is a literal backtick (`) here.`` 749 | 750 | which will produce this: 751 | 752 |

    There is a literal backtick (`) here.

    753 | 754 | The backtick delimiters surrounding a code span may include spaces -- 755 | one after the opening, one before the closing. This allows you to place 756 | literal backtick characters at the beginning or end of a code span: 757 | 758 | A single backtick in a code span: `` ` `` 759 | 760 | A backtick-delimited string in a code span: `` `foo` `` 761 | 762 | will produce: 763 | 764 |

    A single backtick in a code span: `

    765 | 766 |

    A backtick-delimited string in a code span: `foo`

    767 | 768 | With a code span, ampersands and angle brackets are encoded as HTML 769 | entities automatically, which makes it easy to include example HTML 770 | tags. Markdown will turn this: 771 | 772 | Please don't use any `` tags. 773 | 774 | into: 775 | 776 |

    Please don't use any <blink> tags.

    777 | 778 | You can write this: 779 | 780 | `—` is the decimal-encoded equivalent of `—`. 781 | 782 | to produce: 783 | 784 |

    &#8212; is the decimal-encoded 785 | equivalent of &mdash;.

    786 | 787 | 788 | 789 |

    Images

    790 | 791 | Admittedly, it's fairly difficult to devise a "natural" syntax for 792 | placing images into a plain text document format. 793 | 794 | Markdown uses an image syntax that is intended to resemble the syntax 795 | for links, allowing for two styles: *inline* and *reference*. 796 | 797 | Inline image syntax looks like this: 798 | 799 | ![Alt text](/path/to/img.jpg) 800 | 801 | ![Alt text](/path/to/img.jpg "Optional title") 802 | 803 | That is: 804 | 805 | * An exclamation mark: `!`; 806 | * followed by a set of square brackets, containing the `alt` 807 | attribute text for the image; 808 | * followed by a set of parentheses, containing the URL or path to 809 | the image, and an optional `title` attribute enclosed in double 810 | or single quotes. 811 | 812 | Reference-style image syntax looks like this: 813 | 814 | ![Alt text][id] 815 | 816 | Where "id" is the name of a defined image reference. Image references 817 | are defined using syntax identical to link references: 818 | 819 | [id]: url/to/image "Optional title attribute" 820 | 821 | As of this writing, Markdown has no syntax for specifying the 822 | dimensions of an image; if this is important to you, you can simply 823 | use regular HTML `` tags. 824 | 825 | 826 | * * * 827 | 828 | 829 |

    Miscellaneous

    830 | 831 | 832 | 833 | Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this: 834 | 835 | 836 | 837 | Markdown will turn this into: 838 | 839 | http://example.com/ 840 | 841 | Automatic links for email addresses work similarly, except that 842 | Markdown will also perform a bit of randomized decimal and hex 843 | entity-encoding to help obscure your address from address-harvesting 844 | spambots. For example, Markdown will turn this: 845 | 846 | 847 | 848 | into something like this: 849 | 850 | address@exa 853 | mple.com 854 | 855 | which will render in a browser as a clickable link to "address@example.com". 856 | 857 | (This sort of entity-encoding trick will indeed fool many, if not 858 | most, address-harvesting bots, but it definitely won't fool all of 859 | them. It's better than nothing, but an address published in this way 860 | will probably eventually start receiving spam.) 861 | 862 | 863 | 864 |

    Backslash Escapes

    865 | 866 | Markdown allows you to use backslash escapes to generate literal 867 | characters which would otherwise have special meaning in Markdown's 868 | formatting syntax. For example, if you wanted to surround a word with 869 | literal asterisks (instead of an HTML `` tag), you can backslashes 870 | before the asterisks, like this: 871 | 872 | \*literal asterisks\* 873 | 874 | Markdown provides backslash escapes for the following characters: 875 | 876 | \ backslash 877 | ` backtick 878 | * asterisk 879 | _ underscore 880 | {} curly braces 881 | [] square brackets 882 | () parentheses 883 | # hash mark 884 | + plus sign 885 | - minus sign (hyphen) 886 | . dot 887 | ! exclamation mark 888 | 889 | --------------------------------------------------------------------------------