File Coverage

hoedown/src/html.c
Criterion Covered Total %
statement 83 324 25.6
branch 33 242 13.6
condition n/a
subroutine n/a
pod n/a
total 116 566 20.4


\n"); \n"); \n"); \n"); \n"); \n"); \n");
line stmt bran cond sub pod time code
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 0           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 0 0         if (size < 3 || data[0] != '<')
    0          
19             return HOEDOWN_HTML_TAG_NONE;
20              
21             i = 1;
22              
23 0 0         if (data[i] == '/') {
24             closed = 1;
25             i++;
26             }
27              
28 0 0         for (; i < size; ++i, ++tagname) {
29 0 0         if (*tagname == 0)
30             break;
31              
32 0 0         if (data[i] != *tagname)
33             return HOEDOWN_HTML_TAG_NONE;
34             }
35              
36 0 0         if (i == size)
37             return HOEDOWN_HTML_TAG_NONE;
38              
39 0 0         if (isspace(data[i]) || data[i] == '>')
    0          
40 0 0         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 25           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 1           hoedown_escape_href(ob, source, length);
53             }
54              
55             /********************
56             * GENERIC RENDERER *
57             ********************/
58             static int
59 1           rndr_autolink(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data)
60             {
61 1           hoedown_html_renderer_state *state = data->opaque;
62              
63 1 50         if (!link || !link->size)
    50          
64             return 0;
65              
66 1           HOEDOWN_BUFPUTSL(ob, "
67 1 50         if (type == HOEDOWN_AUTOLINK_EMAIL)
68 0           HOEDOWN_BUFPUTSL(ob, "mailto:");
69 1           escape_href(ob, link->data, link->size);
70              
71 1 50         if (state->link_attributes) {
72 0           hoedown_buffer_putc(ob, '\"');
73 0           state->link_attributes(ob, link, data);
74 0           hoedown_buffer_putc(ob, '>');
75             } else {
76 1           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 1 50         if (hoedown_buffer_prefix(link, "mailto:") == 0) {
85 0           escape_html(ob, link->data + 7, link->size - 7);
86             } else {
87 1           escape_html(ob, link->data, link->size);
88             }
89              
90 1           HOEDOWN_BUFPUTSL(ob, "");
91              
92 1           return 1;
93             }
94              
95             static void
96 0           rndr_blockcode(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data)
97             {
98 0 0         if (ob->size) hoedown_buffer_putc(ob, '\n');
99              
100 0 0         if (lang) {
101 0           HOEDOWN_BUFPUTSL(ob, "

102 0           escape_html(ob, lang->data, lang->size);
103 0           HOEDOWN_BUFPUTSL(ob, "\">");
104             } else {
105 0           HOEDOWN_BUFPUTSL(ob, "
"); 
106             }
107              
108 0 0         if (text)
109 0           escape_html(ob, text->data, text->size);
110              
111 0           HOEDOWN_BUFPUTSL(ob, "\n");
112 0           }
113              
114             static void
115 0           rndr_blockquote(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
116             {
117 0 0         if (ob->size) hoedown_buffer_putc(ob, '\n');
118 0           HOEDOWN_BUFPUTSL(ob, "
\n");
119 0 0         if (content) hoedown_buffer_put(ob, content->data, content->size);
120 0           HOEDOWN_BUFPUTSL(ob, "\n");
121 0           }
122              
123             static int
124 0           rndr_codespan(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)
125             {
126 0           HOEDOWN_BUFPUTSL(ob, "");
127 0 0         if (text) escape_html(ob, text->data, text->size);
128 0           HOEDOWN_BUFPUTSL(ob, "");
129 0           return 1;
130             }
131              
132             static int
133 0           rndr_strikethrough(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
134             {
135 0 0         if (!content || !content->size)
    0          
136             return 0;
137              
138 0           HOEDOWN_BUFPUTSL(ob, "");
139 0           hoedown_buffer_put(ob, content->data, content->size);
140 0           HOEDOWN_BUFPUTSL(ob, "");
141 0           return 1;
142             }
143              
144             static int
145 0           rndr_double_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
146             {
147 0 0         if (!content || !content->size)
    0          
148             return 0;
149              
150 0           HOEDOWN_BUFPUTSL(ob, "");
151 0           hoedown_buffer_put(ob, content->data, content->size);
152 0           HOEDOWN_BUFPUTSL(ob, "");
153              
154 0           return 1;
155             }
156              
157             static int
158 0           rndr_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
159             {
160 0 0         if (!content || !content->size) return 0;
    0          
161 0           HOEDOWN_BUFPUTSL(ob, "");
162 0 0         if (content) hoedown_buffer_put(ob, content->data, content->size);
163 0           HOEDOWN_BUFPUTSL(ob, "");
164 0           return 1;
165             }
166              
167             static int
168 0           rndr_underline(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
169             {
170 0 0         if (!content || !content->size)
    0          
171             return 0;
172              
173 0           HOEDOWN_BUFPUTSL(ob, "");
174 0           hoedown_buffer_put(ob, content->data, content->size);
175 0           HOEDOWN_BUFPUTSL(ob, "");
176              
177 0           return 1;
178             }
179              
180             static int
181 0           rndr_highlight(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
182             {
183 0 0         if (!content || !content->size)
    0          
184             return 0;
185              
186 0           HOEDOWN_BUFPUTSL(ob, "");
187 0           hoedown_buffer_put(ob, content->data, content->size);
188 0           HOEDOWN_BUFPUTSL(ob, "");
189              
190 0           return 1;
191             }
192              
193             static int
194 0           rndr_quote(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
195             {
196 0 0         if (!content || !content->size)
    0          
197             return 0;
198              
199 0           HOEDOWN_BUFPUTSL(ob, "");
200 0           hoedown_buffer_put(ob, content->data, content->size);
201 0           HOEDOWN_BUFPUTSL(ob, "");
202              
203 0           return 1;
204             }
205              
206             static int
207 0           rndr_linebreak(hoedown_buffer *ob, const hoedown_renderer_data *data)
208             {
209 0           hoedown_html_renderer_state *state = data->opaque;
210 0 0         hoedown_buffer_puts(ob, USE_XHTML(state) ? "
\n" : "
\n");
    0          
211 0           return 1;
212             }
213              
214             static void
215 16           rndr_header(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data)
216             {
217 16           hoedown_html_renderer_state *state = data->opaque;
218              
219 16 100         if (ob->size)
220 12           hoedown_buffer_putc(ob, '\n');
221              
222 16 100         if (level <= state->toc_data.nesting_level)
223 9           hoedown_buffer_printf(ob, "", level, state->toc_data.header_count++);
224             else
225 7           hoedown_buffer_printf(ob, "", level);
226              
227 16 50         if (content) hoedown_buffer_put(ob, content->data, content->size);
228 16           hoedown_buffer_printf(ob, "\n", level);
229 16           }
230              
231             static int
232 0           rndr_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data)
233             {
234 0           hoedown_html_renderer_state *state = data->opaque;
235              
236 0           HOEDOWN_BUFPUTSL(ob, "
237              
238 0 0         if (link && link->size)
    0          
239 0           escape_href(ob, link->data, link->size);
240              
241 0 0         if (title && title->size) {
    0          
242 0           HOEDOWN_BUFPUTSL(ob, "\" title=\"");
243 0           escape_html(ob, title->data, title->size);
244             }
245              
246 0 0         if (state->link_attributes) {
247 0           hoedown_buffer_putc(ob, '\"');
248 0           state->link_attributes(ob, link, data);
249 0           hoedown_buffer_putc(ob, '>');
250             } else {
251 0           HOEDOWN_BUFPUTSL(ob, "\">");
252             }
253              
254 0 0         if (content && content->size) hoedown_buffer_put(ob, content->data, content->size);
    0          
255 0           HOEDOWN_BUFPUTSL(ob, "");
256 0           return 1;
257             }
258              
259             static void
260 0           rndr_list(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data)
261             {
262 0 0         if (ob->size) hoedown_buffer_putc(ob, '\n');
263 0 0         hoedown_buffer_put(ob, (const uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "
    \n" : "
      \n"), 5);
264 0 0         if (content) hoedown_buffer_put(ob, content->data, content->size);
265 0 0         hoedown_buffer_put(ob, (const uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "\n" : "\n"), 6);
266 0           }
267              
268             static void
269 0           rndr_listitem(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data)
270             {
271 0           HOEDOWN_BUFPUTSL(ob, "
  • ");
  • 272 0 0         if (content) {
    273 0           size_t size = content->size;
    274 0 0         while (size && content->data[size - 1] == '\n')
        0          
    275             size--;
    276              
    277 0           hoedown_buffer_put(ob, content->data, size);
    278             }
    279 0           HOEDOWN_BUFPUTSL(ob, "\n");
    280 0           }
    281              
    282             static void
    283 1           rndr_paragraph(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
    284             {
    285 1           hoedown_html_renderer_state *state = data->opaque;
    286             size_t i = 0;
    287              
    288 1 50         if (ob->size) hoedown_buffer_putc(ob, '\n');
    289              
    290 1 50         if (!content || !content->size)
        50          
    291             return;
    292              
    293 1 50         while (i < content->size && isspace(content->data[i])) i++;
        50          
    294              
    295 1 50         if (i == content->size)
    296             return;
    297              
    298 1           HOEDOWN_BUFPUTSL(ob, "

    ");

    299 1 50         if (state->flags & HOEDOWN_HTML_HARD_WRAP) {
    300             size_t org;
    301 0 0         while (i < content->size) {
    302             org = i;
    303 0 0         while (i < content->size && content->data[i] != '\n')
        0          
    304 0           i++;
    305              
    306 0 0         if (i > org)
    307 0           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 0 0         if (i >= content->size - 1)
    314             break;
    315              
    316             rndr_linebreak(ob, data);
    317 0           i++;
    318             }
    319             } else {
    320 1           hoedown_buffer_put(ob, content->data + i, content->size - i);
    321             }
    322 1           HOEDOWN_BUFPUTSL(ob, "

    \n");
    323             }
    324              
    325             static void
    326 0           rndr_raw_block(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)
    327             {
    328             size_t org, sz;
    329              
    330 0 0         if (!text)
    331             return;
    332              
    333             /* FIXME: Do we *really* need to trim the HTML? How does that make a difference? */
    334 0           sz = text->size;
    335 0 0         while (sz > 0 && text->data[sz - 1] == '\n')
        0          
    336             sz--;
    337              
    338             org = 0;
    339 0 0         while (org < sz && text->data[org] == '\n')
        0          
    340 0           org++;
    341              
    342 0 0         if (org >= sz)
    343             return;
    344              
    345 0 0         if (ob->size)
    346 0           hoedown_buffer_putc(ob, '\n');
    347              
    348 0           hoedown_buffer_put(ob, text->data + org, sz - org);
    349 0           hoedown_buffer_putc(ob, '\n');
    350             }
    351              
    352             static int
    353 0           rndr_triple_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
    354             {
    355 0 0         if (!content || !content->size) return 0;
        0          
    356 0           HOEDOWN_BUFPUTSL(ob, "");
    357 0           hoedown_buffer_put(ob, content->data, content->size);
    358 0           HOEDOWN_BUFPUTSL(ob, "");
    359 0           return 1;
    360             }
    361              
    362             static void
    363 0           rndr_hrule(hoedown_buffer *ob, const hoedown_renderer_data *data)
    364             {
    365 0           hoedown_html_renderer_state *state = data->opaque;
    366 0 0         if (ob->size) hoedown_buffer_putc(ob, '\n');
    367 0 0         hoedown_buffer_puts(ob, USE_XHTML(state) ? "
    \n" : "
    \n");
    368 0           }
    369              
    370             static int
    371 0           rndr_image(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data)
    372             {
    373 0           hoedown_html_renderer_state *state = data->opaque;
    374 0 0         if (!link || !link->size) return 0;
        0          
    375              
    376 0           HOEDOWN_BUFPUTSL(ob, "
    377 0           escape_href(ob, link->data, link->size);
    378 0           HOEDOWN_BUFPUTSL(ob, "\" alt=\"");
    379              
    380 0 0         if (alt && alt->size)
        0          
    381 0           escape_html(ob, alt->data, alt->size);
    382              
    383 0 0         if (title && title->size) {
        0          
    384 0           HOEDOWN_BUFPUTSL(ob, "\" title=\"");
    385 0           escape_html(ob, title->data, title->size); }
    386              
    387 0 0         hoedown_buffer_puts(ob, USE_XHTML(state) ? "\"/>" : "\">");
    388 0           return 1;
    389             }
    390              
    391             static int
    392 0           rndr_raw_html(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)
    393             {
    394 0           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 0 0         if((state->flags & HOEDOWN_HTML_ESCAPE) != 0) {
    399 0           escape_html(ob, text->data, text->size);
    400 0           return 1;
    401             }
    402              
    403 0 0         if ((state->flags & HOEDOWN_HTML_SKIP_HTML) != 0)
    404             return 1;
    405              
    406 0           hoedown_buffer_put(ob, text->data, text->size);
    407 0           return 1;
    408             }
    409              
    410             static void
    411 0           rndr_table(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
    412             {
    413 0 0         if (ob->size) hoedown_buffer_putc(ob, '\n');
    414 0           HOEDOWN_BUFPUTSL(ob, "\n");
    415 0           hoedown_buffer_put(ob, content->data, content->size);
    416 0           HOEDOWN_BUFPUTSL(ob, "
    \n");
    417 0           }
    418              
    419             static void
    420 0           rndr_table_header(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
    421             {
    422 0 0         if (ob->size) hoedown_buffer_putc(ob, '\n');
    423 0           HOEDOWN_BUFPUTSL(ob, "
    424 0           hoedown_buffer_put(ob, content->data, content->size);
    425 0           HOEDOWN_BUFPUTSL(ob, "
    426 0           }
    427              
    428             static void
    429 0           rndr_table_body(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
    430             {
    431 0 0         if (ob->size) hoedown_buffer_putc(ob, '\n');
    432 0           HOEDOWN_BUFPUTSL(ob, "
    433 0           hoedown_buffer_put(ob, content->data, content->size);
    434 0           HOEDOWN_BUFPUTSL(ob, "
    435 0           }
    436              
    437             static void
    438 0           rndr_tablerow(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
    439             {
    440 0           HOEDOWN_BUFPUTSL(ob, "
    441 0 0         if (content) hoedown_buffer_put(ob, content->data, content->size);
    442 0           HOEDOWN_BUFPUTSL(ob, "
    443 0           }
    444              
    445             static void
    446 0           rndr_tablecell(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data)
    447             {
    448 0 0         if (flags & HOEDOWN_TABLE_HEADER) {
    449 0           HOEDOWN_BUFPUTSL(ob, "
    450             } else {
    451 0           HOEDOWN_BUFPUTSL(ob, "
    452             }
    453              
    454 0           switch (flags & HOEDOWN_TABLE_ALIGNMASK) {
    455             case HOEDOWN_TABLE_ALIGN_CENTER:
    456 0           HOEDOWN_BUFPUTSL(ob, " style=\"text-align: center\">");
    457 0           break;
    458              
    459             case HOEDOWN_TABLE_ALIGN_LEFT:
    460 0           HOEDOWN_BUFPUTSL(ob, " style=\"text-align: left\">");
    461 0           break;
    462              
    463             case HOEDOWN_TABLE_ALIGN_RIGHT:
    464 0           HOEDOWN_BUFPUTSL(ob, " style=\"text-align: right\">");
    465 0           break;
    466              
    467             default:
    468 0           HOEDOWN_BUFPUTSL(ob, ">");
    469             }
    470              
    471 0 0         if (content)
    472 0           hoedown_buffer_put(ob, content->data, content->size);
    473              
    474 0 0         if (flags & HOEDOWN_TABLE_HEADER) {
    475 0           HOEDOWN_BUFPUTSL(ob, "\n");
    476             } else {
    477 0           HOEDOWN_BUFPUTSL(ob, "
    478             }
    479 0           }
    480              
    481             static int
    482 0           rndr_superscript(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
    483             {
    484 0 0         if (!content || !content->size) return 0;
        0          
    485 0           HOEDOWN_BUFPUTSL(ob, "");
    486 0           hoedown_buffer_put(ob, content->data, content->size);
    487 0           HOEDOWN_BUFPUTSL(ob, "");
    488 0           return 1;
    489             }
    490              
    491             static void
    492 24           rndr_normal_text(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
    493             {
    494 24 50         if (content)
    495 24           escape_html(ob, content->data, content->size);
    496 24           }
    497              
    498             static void
    499 0           rndr_footnotes(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
    500             {
    501 0           hoedown_html_renderer_state *state = data->opaque;
    502              
    503 0 0         if (ob->size) hoedown_buffer_putc(ob, '\n');
    504 0           HOEDOWN_BUFPUTSL(ob, "
    \n");
    505 0 0         hoedown_buffer_puts(ob, USE_XHTML(state) ? "
    \n" : "
    \n");
    506 0           HOEDOWN_BUFPUTSL(ob, "
      \n");
    507              
    508 0 0         if (content) hoedown_buffer_put(ob, content->data, content->size);
    509              
    510 0           HOEDOWN_BUFPUTSL(ob, "\n\n\n");
    511 0           }
    512              
    513             static void
    514 0           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 0 0         if (content) {
    521 0 0         while ((i+3) < content->size) {
    522 0 0         if (content->data[i++] != '<') continue;
    523 0 0         if (content->data[i++] != '/') continue;
    524 0 0         if (content->data[i++] != 'p' && content->data[i] != 'P') continue;
        0          
    525 0 0         if (content->data[i] != '>') continue;
    526             i -= 3;
    527             pfound = 1;
    528             break;
    529             }
    530             }
    531              
    532 0           hoedown_buffer_printf(ob, "\n
  • \n", num);
  • 533 0 0         if (pfound) {
    534 0           hoedown_buffer_put(ob, content->data, i);
    535 0           hoedown_buffer_printf(ob, " ", num);
    536 0           hoedown_buffer_put(ob, content->data + i, content->size - i);
    537 0 0         } else if (content) {
    538 0           hoedown_buffer_put(ob, content->data, content->size);
    539             }
    540 0           HOEDOWN_BUFPUTSL(ob, "\n");
    541 0           }
    542              
    543             static int
    544 0           rndr_footnote_ref(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data)
    545             {
    546 0           hoedown_buffer_printf(ob, "%d", num, num, num);
    547 0           return 1;
    548             }
    549              
    550             static int
    551 0           rndr_math(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data)
    552             {
    553 0 0         hoedown_buffer_put(ob, (const uint8_t *)(displaymode ? "\\[" : "\\("), 2);
    554 0           escape_html(ob, text->data, text->size);
    555 0 0         hoedown_buffer_put(ob, (const uint8_t *)(displaymode ? "\\]" : "\\)"), 2);
    556 0           return 1;
    557             }
    558              
    559             static void
    560 7           toc_header(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data)
    561             {
    562 7           hoedown_html_renderer_state *state = data->opaque;
    563              
    564 7 50         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 7 100         if (state->toc_data.current_level == 0)
    568 1           state->toc_data.level_offset = level - 1;
    569              
    570 7           level -= state->toc_data.level_offset;
    571              
    572 7 100         if (level > state->toc_data.current_level) {
    573 10 100         while (level > state->toc_data.current_level) {
    574 5           HOEDOWN_BUFPUTSL(ob, "
      \n
    • \n");
    575 5           state->toc_data.current_level++;
    576             }
    577 2 50         } else if (level < state->toc_data.current_level) {
    578 2           HOEDOWN_BUFPUTSL(ob, "\n");
    579 5 100         while (level < state->toc_data.current_level) {
    580 3           HOEDOWN_BUFPUTSL(ob, "\n\n");
    581 3           state->toc_data.current_level--;
    582             }
    583 2           HOEDOWN_BUFPUTSL(ob,"
  • \n");
  • 584             } else {
    585 0           HOEDOWN_BUFPUTSL(ob,"\n
  • \n");
  • 586             }
    587              
    588 7           hoedown_buffer_printf(ob, "", state->toc_data.header_count++);
    589 7 50         if (content) hoedown_buffer_put(ob, content->data, content->size);
    590 7           HOEDOWN_BUFPUTSL(ob, "\n");
    591             }
    592 7           }
    593              
    594             static int
    595 0           toc_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data)
    596             {
    597 0 0         if (content && content->size) hoedown_buffer_put(ob, content->data, content->size);
        0          
    598 0           return 1;
    599             }
    600              
    601             static void
    602 1           toc_finalize(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data)
    603             {
    604             hoedown_html_renderer_state *state;
    605              
    606 1 50         if (inline_render)
    607             return;
    608              
    609 1           state = data->opaque;
    610              
    611 3 100         while (state->toc_data.current_level > 0) {
    612 2           HOEDOWN_BUFPUTSL(ob, "\n\n");
    613 2           state->toc_data.current_level--;
    614             }
    615              
    616 1           state->toc_data.header_count = 0;
    617             }
    618              
    619             hoedown_renderer *
    620 1           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 1           state = hoedown_malloc(sizeof(hoedown_html_renderer_state));
    670             memset(state, 0x0, sizeof(hoedown_html_renderer_state));
    671              
    672 1           state->toc_data.nesting_level = nesting_level;
    673              
    674             /* Prepare the renderer */
    675 1           renderer = hoedown_malloc(sizeof(hoedown_renderer));
    676             memcpy(renderer, &cb_default, sizeof(hoedown_renderer));
    677              
    678 1           renderer->opaque = state;
    679 1           return renderer;
    680             }
    681              
    682             hoedown_renderer *
    683 6           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 6           state = hoedown_malloc(sizeof(hoedown_html_renderer_state));
    733             memset(state, 0x0, sizeof(hoedown_html_renderer_state));
    734              
    735 6           state->flags = render_flags;
    736 6           state->toc_data.nesting_level = nesting_level;
    737              
    738             /* Prepare the renderer */
    739 6           renderer = hoedown_malloc(sizeof(hoedown_renderer));
    740             memcpy(renderer, &cb_default, sizeof(hoedown_renderer));
    741              
    742 6 50         if (render_flags & HOEDOWN_HTML_SKIP_HTML || render_flags & HOEDOWN_HTML_ESCAPE)
    743 0           renderer->blockhtml = NULL;
    744              
    745 6           renderer->opaque = state;
    746 6           return renderer;
    747             }
    748              
    749             void
    750 7           hoedown_html_renderer_free(hoedown_renderer *renderer)
    751             {
    752 7           free(renderer->opaque);
    753 7           free(renderer);
    754 7           }