tight-redcarpet 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,141 @@
1
+ /* markdown.h - generic markdown parser */
2
+
3
+ /*
4
+ * Copyright (c) 2009, Natacha Porté
5
+ *
6
+ * Permission to use, copy, modify, and distribute this software for any
7
+ * purpose with or without fee is hereby granted, provided that the above
8
+ * copyright notice and this permission notice appear in all copies.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ */
18
+
19
+ #ifndef MARKDOWN_H__
20
+ #define MARKDOWN_H__
21
+
22
+ #include "buffer.h"
23
+ #include "autolink.h"
24
+
25
+ #ifdef __cplusplus
26
+ extern "C" {
27
+ #endif
28
+
29
+ /********************
30
+ * TYPE DEFINITIONS *
31
+ ********************/
32
+
33
+ /* mkd_autolink - type of autolink */
34
+ enum mkd_autolink {
35
+ MKDA_NOT_AUTOLINK, /* used internally when it is not an autolink*/
36
+ MKDA_NORMAL, /* normal http/http/ftp/mailto/etc link */
37
+ MKDA_EMAIL, /* e-mail link without explit mailto: */
38
+ };
39
+
40
+ enum mkd_tableflags {
41
+ MKD_TABLE_ALIGN_L = 1,
42
+ MKD_TABLE_ALIGN_R = 2,
43
+ MKD_TABLE_ALIGN_CENTER = 3,
44
+ MKD_TABLE_ALIGNMASK = 3,
45
+ MKD_TABLE_HEADER = 4
46
+ };
47
+
48
+ enum mkd_extensions {
49
+ MKDEXT_NO_INTRA_EMPHASIS = (1 << 0),
50
+ MKDEXT_TABLES = (1 << 1),
51
+ MKDEXT_FENCED_CODE = (1 << 2),
52
+ MKDEXT_AUTOLINK = (1 << 3),
53
+ MKDEXT_STRIKETHROUGH = (1 << 4),
54
+ MKDEXT_UNDERLINE = (1 << 5),
55
+ MKDEXT_SPACE_HEADERS = (1 << 6),
56
+ MKDEXT_SUPERSCRIPT = (1 << 7),
57
+ MKDEXT_LAX_SPACING = (1 << 8),
58
+ MKDEXT_DISABLE_INDENTED_CODE = (1 << 9),
59
+ MKDEXT_HIGHLIGHT = (1 << 10),
60
+ MKDEXT_FOOTNOTES = (1 << 11),
61
+ MKDEXT_QUOTE = (1 << 12)
62
+ };
63
+
64
+ /* sd_callbacks - functions for rendering parsed data */
65
+ struct sd_callbacks {
66
+ /* block level callbacks - NULL skips the block */
67
+ void (*blockcode)(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque);
68
+ void (*blockquote)(struct buf *ob, const struct buf *text, void *opaque);
69
+ void (*blockhtml)(struct buf *ob,const struct buf *text, void *opaque);
70
+ void (*header)(struct buf *ob, const struct buf *text, int level, void *opaque);
71
+ void (*hrule)(struct buf *ob, void *opaque);
72
+ void (*list)(struct buf *ob, const struct buf *text, int flags, void *opaque);
73
+ void (*listitem)(struct buf *ob, const struct buf *text, int flags, void *opaque);
74
+ void (*paragraph)(struct buf *ob, const struct buf *text, void *opaque);
75
+ void (*table)(struct buf *ob, const struct buf *header, const struct buf *body, void *opaque);
76
+ void (*table_row)(struct buf *ob, const struct buf *text, void *opaque);
77
+ void (*table_cell)(struct buf *ob, const struct buf *text, int flags, void *opaque);
78
+ void (*footnotes)(struct buf *ob, const struct buf *text, void *opaque);
79
+ void (*footnote_def)(struct buf *ob, const struct buf *text, unsigned int num, void *opaque);
80
+
81
+ /* span level callbacks - NULL or return 0 prints the span verbatim */
82
+ int (*autolink)(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque);
83
+ int (*codespan)(struct buf *ob, const struct buf *text, void *opaque);
84
+ int (*double_emphasis)(struct buf *ob, const struct buf *text, void *opaque);
85
+ int (*emphasis)(struct buf *ob, const struct buf *text, void *opaque);
86
+ int (*underline)(struct buf *ob, const struct buf *text, void *opaque);
87
+ int (*highlight)(struct buf *ob, const struct buf *text, void *opaque);
88
+ int (*quote)(struct buf *ob, const struct buf *text, void *opaque);
89
+ int (*image)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque);
90
+ int (*linebreak)(struct buf *ob, void *opaque);
91
+ int (*link)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque);
92
+ int (*raw_html_tag)(struct buf *ob, const struct buf *tag, void *opaque);
93
+ int (*triple_emphasis)(struct buf *ob, const struct buf *text, void *opaque);
94
+ int (*strikethrough)(struct buf *ob, const struct buf *text, void *opaque);
95
+ int (*superscript)(struct buf *ob, const struct buf *text, void *opaque);
96
+ int (*footnote_ref)(struct buf *ob, unsigned int num, void *opaque);
97
+
98
+ /* low level callbacks - NULL copies input directly into the output */
99
+ void (*entity)(struct buf *ob, const struct buf *entity, void *opaque);
100
+ void (*normal_text)(struct buf *ob, const struct buf *text, void *opaque);
101
+
102
+ /* header and footer */
103
+ void (*doc_header)(struct buf *ob, void *opaque);
104
+ void (*doc_footer)(struct buf *ob, void *opaque);
105
+ };
106
+
107
+ /* header methods used internally in Redcarpet */
108
+ char* header_anchor(struct buf *text);
109
+
110
+ struct sd_markdown;
111
+
112
+ /*********
113
+ * FLAGS *
114
+ *********/
115
+
116
+ /* list/listitem flags */
117
+ #define MKD_LIST_ORDERED 1
118
+ #define MKD_LI_BLOCK 2 /* <li> containing block data */
119
+
120
+ /**********************
121
+ * EXPORTED FUNCTIONS *
122
+ **********************/
123
+
124
+ extern struct sd_markdown *
125
+ sd_markdown_new(
126
+ unsigned int extensions,
127
+ size_t max_nesting,
128
+ const struct sd_callbacks *callbacks,
129
+ void *opaque);
130
+
131
+ extern void
132
+ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, struct sd_markdown *md);
133
+
134
+ extern void
135
+ sd_markdown_free(struct sd_markdown *md);
136
+
137
+ #ifdef __cplusplus
138
+ }
139
+ #endif
140
+
141
+ #endif
@@ -0,0 +1,165 @@
1
+ /*
2
+ * Copyright (c) 2011, Vicent Marti
3
+ *
4
+ * Permission to use, copy, modify, and distribute this software for any
5
+ * purpose with or without fee is hereby granted, provided that the above
6
+ * copyright notice and this permission notice appear in all copies.
7
+ *
8
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+ */
16
+ #include "redcarpet.h"
17
+
18
+ VALUE rb_mRedcarpet;
19
+ VALUE rb_cMarkdown;
20
+
21
+ extern VALUE rb_cRenderBase;
22
+
23
+ static void rb_redcarpet_md_flags(VALUE hash, unsigned int *enabled_extensions_p)
24
+ {
25
+ unsigned int extensions = 0;
26
+
27
+ Check_Type(hash, T_HASH);
28
+
29
+ /**
30
+ * Markdown extensions -- all disabled by default
31
+ */
32
+ if (rb_hash_lookup(hash, CSTR2SYM("no_intra_emphasis")) == Qtrue)
33
+ extensions |= MKDEXT_NO_INTRA_EMPHASIS;
34
+
35
+ if (rb_hash_lookup(hash, CSTR2SYM("tables")) == Qtrue)
36
+ extensions |= MKDEXT_TABLES;
37
+
38
+ if (rb_hash_lookup(hash, CSTR2SYM("fenced_code_blocks")) == Qtrue)
39
+ extensions |= MKDEXT_FENCED_CODE;
40
+
41
+ if (rb_hash_lookup(hash, CSTR2SYM("disable_indented_code_blocks")) == Qtrue)
42
+ extensions |= MKDEXT_DISABLE_INDENTED_CODE;
43
+
44
+ if (rb_hash_lookup(hash, CSTR2SYM("autolink")) == Qtrue)
45
+ extensions |= MKDEXT_AUTOLINK;
46
+
47
+ if (rb_hash_lookup(hash, CSTR2SYM("strikethrough")) == Qtrue)
48
+ extensions |= MKDEXT_STRIKETHROUGH;
49
+
50
+ if (rb_hash_lookup(hash, CSTR2SYM("underline")) == Qtrue)
51
+ extensions |= MKDEXT_UNDERLINE;
52
+
53
+ if (rb_hash_lookup(hash, CSTR2SYM("highlight")) == Qtrue)
54
+ extensions |= MKDEXT_HIGHLIGHT;
55
+
56
+ if (rb_hash_lookup(hash, CSTR2SYM("quote")) == Qtrue)
57
+ extensions |= MKDEXT_QUOTE;
58
+
59
+ if (rb_hash_lookup(hash, CSTR2SYM("lax_spacing")) == Qtrue)
60
+ extensions |= MKDEXT_LAX_SPACING;
61
+
62
+ if (rb_hash_lookup(hash, CSTR2SYM("space_after_headers")) == Qtrue)
63
+ extensions |= MKDEXT_SPACE_HEADERS;
64
+
65
+ if (rb_hash_lookup(hash, CSTR2SYM("superscript")) == Qtrue)
66
+ extensions |= MKDEXT_SUPERSCRIPT;
67
+
68
+ if (rb_hash_lookup(hash, CSTR2SYM("footnotes")) == Qtrue)
69
+ extensions |= MKDEXT_FOOTNOTES;
70
+
71
+ *enabled_extensions_p = extensions;
72
+ }
73
+
74
+ static void
75
+ rb_redcarpet_md__free(void *markdown)
76
+ {
77
+ sd_markdown_free((struct sd_markdown *)markdown);
78
+ }
79
+
80
+ static VALUE rb_redcarpet_md__new(int argc, VALUE *argv, VALUE klass)
81
+ {
82
+ VALUE rb_markdown, rb_rndr, hash;
83
+ unsigned int extensions = 0;
84
+
85
+ struct rb_redcarpet_rndr *rndr;
86
+ struct sd_markdown *markdown;
87
+
88
+ if (rb_scan_args(argc, argv, "11", &rb_rndr, &hash) == 2)
89
+ rb_redcarpet_md_flags(hash, &extensions);
90
+
91
+ if (rb_obj_is_kind_of(rb_rndr, rb_cClass))
92
+ rb_rndr = rb_funcall(rb_rndr, rb_intern("new"), 0);
93
+
94
+ if (!rb_obj_is_kind_of(rb_rndr, rb_cRenderBase))
95
+ rb_raise(rb_eTypeError, "Invalid Renderer instance given");
96
+
97
+ Data_Get_Struct(rb_rndr, struct rb_redcarpet_rndr, rndr);
98
+
99
+ markdown = sd_markdown_new(extensions, 16, &rndr->callbacks, &rndr->options);
100
+ if (!markdown)
101
+ rb_raise(rb_eRuntimeError, "Failed to create new Renderer class");
102
+
103
+ rb_markdown = Data_Wrap_Struct(klass, NULL, rb_redcarpet_md__free, markdown);
104
+ rb_iv_set(rb_markdown, "@renderer", rb_rndr);
105
+
106
+ return rb_markdown;
107
+ }
108
+
109
+ static VALUE rb_redcarpet_md_render(VALUE self, VALUE text)
110
+ {
111
+ VALUE rb_rndr;
112
+ struct buf *output_buf;
113
+ struct sd_markdown *markdown;
114
+
115
+ Check_Type(text, T_STRING);
116
+
117
+ rb_rndr = rb_iv_get(self, "@renderer");
118
+ Data_Get_Struct(self, struct sd_markdown, markdown);
119
+
120
+ if (rb_respond_to(rb_rndr, rb_intern("preprocess")))
121
+ text = rb_funcall(rb_rndr, rb_intern("preprocess"), 1, text);
122
+ if (NIL_P(text))
123
+ return Qnil;
124
+
125
+ #ifdef HAVE_RUBY_ENCODING_H
126
+ {
127
+ struct rb_redcarpet_rndr *renderer;
128
+ Data_Get_Struct(rb_rndr, struct rb_redcarpet_rndr, renderer);
129
+ renderer->options.active_enc = rb_enc_get(text);
130
+ }
131
+ #endif
132
+
133
+ /* initialize buffers */
134
+ output_buf = bufnew(128);
135
+
136
+ /* render the magic */
137
+ sd_markdown_render(
138
+ output_buf,
139
+ (const uint8_t*)RSTRING_PTR(text),
140
+ RSTRING_LEN(text),
141
+ markdown);
142
+
143
+ /* build the Ruby string */
144
+ text = rb_enc_str_new((const char*)output_buf->data, output_buf->size, rb_enc_get(text));
145
+
146
+ bufrelease(output_buf);
147
+
148
+ if (rb_respond_to(rb_rndr, rb_intern("postprocess")))
149
+ text = rb_funcall(rb_rndr, rb_intern("postprocess"), 1, text);
150
+
151
+ return text;
152
+ }
153
+
154
+ __attribute__((visibility("default")))
155
+ void Init_redcarpet()
156
+ {
157
+ rb_mRedcarpet = rb_define_module("Redcarpet");
158
+
159
+ rb_cMarkdown = rb_define_class_under(rb_mRedcarpet, "Markdown", rb_cObject);
160
+ rb_define_singleton_method(rb_cMarkdown, "new", rb_redcarpet_md__new, -1);
161
+ rb_define_method(rb_cMarkdown, "render", rb_redcarpet_md_render, 1);
162
+
163
+ Init_redcarpet_rndr();
164
+ }
165
+
@@ -0,0 +1,529 @@
1
+ /*
2
+ * Copyright (c) 2011, Vicent Marti
3
+ *
4
+ * Permission to use, copy, modify, and distribute this software for any
5
+ * purpose with or without fee is hereby granted, provided that the above
6
+ * copyright notice and this permission notice appear in all copies.
7
+ *
8
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+ */
16
+
17
+ #include "redcarpet.h"
18
+
19
+ #define SPAN_CALLBACK(method_name, ...) {\
20
+ struct redcarpet_renderopt *opt = opaque;\
21
+ VALUE ret = rb_funcall(opt->self, rb_intern(method_name), __VA_ARGS__);\
22
+ if (NIL_P(ret)) return 0;\
23
+ Check_Type(ret, T_STRING);\
24
+ bufput(ob, RSTRING_PTR(ret), RSTRING_LEN(ret));\
25
+ return 1;\
26
+ }
27
+
28
+ #define BLOCK_CALLBACK(method_name, ...) {\
29
+ struct redcarpet_renderopt *opt = opaque;\
30
+ VALUE ret = rb_funcall(opt->self, rb_intern(method_name), __VA_ARGS__);\
31
+ if (NIL_P(ret)) return;\
32
+ Check_Type(ret, T_STRING);\
33
+ bufput(ob, RSTRING_PTR(ret), RSTRING_LEN(ret));\
34
+ }
35
+
36
+ extern VALUE rb_mRedcarpet;
37
+ VALUE rb_mRender;
38
+ VALUE rb_cRenderBase;
39
+ VALUE rb_cRenderHTML;
40
+ VALUE rb_cRenderHTML_TOC;
41
+ VALUE rb_mSmartyPants;
42
+
43
+ #define buf2str(t) ((t) ? rb_enc_str_new((const char*)(t)->data, (t)->size, opt->active_enc) : Qnil)
44
+
45
+ static void
46
+ rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque)
47
+ {
48
+ BLOCK_CALLBACK("block_code", 2, buf2str(text), buf2str(lang));
49
+ }
50
+
51
+ static void
52
+ rndr_blockquote(struct buf *ob, const struct buf *text, void *opaque)
53
+ {
54
+ BLOCK_CALLBACK("block_quote", 1, buf2str(text));
55
+ }
56
+
57
+ static void
58
+ rndr_raw_block(struct buf *ob, const struct buf *text, void *opaque)
59
+ {
60
+ BLOCK_CALLBACK("block_html", 1, buf2str(text));
61
+ }
62
+
63
+ static void
64
+ rndr_header(struct buf *ob, const struct buf *text, int level, void *opaque)
65
+ {
66
+ BLOCK_CALLBACK("header", 2, buf2str(text), INT2FIX(level));
67
+ }
68
+
69
+ static void
70
+ rndr_hrule(struct buf *ob, void *opaque)
71
+ {
72
+ BLOCK_CALLBACK("hrule", 0);
73
+ }
74
+
75
+ static void
76
+ rndr_list(struct buf *ob, const struct buf *text, int flags, void *opaque)
77
+ {
78
+ BLOCK_CALLBACK("list", 2, buf2str(text),
79
+ (flags & MKD_LIST_ORDERED) ? CSTR2SYM("ordered") : CSTR2SYM("unordered"));
80
+ }
81
+
82
+ static void
83
+ rndr_listitem(struct buf *ob, const struct buf *text, int flags, void *opaque)
84
+ {
85
+ BLOCK_CALLBACK("list_item", 2, buf2str(text),
86
+ (flags & MKD_LIST_ORDERED) ? CSTR2SYM("ordered") : CSTR2SYM("unordered"));
87
+ }
88
+
89
+ static void
90
+ rndr_paragraph(struct buf *ob, const struct buf *text, void *opaque)
91
+ {
92
+ BLOCK_CALLBACK("paragraph", 1, buf2str(text));
93
+ }
94
+
95
+ static void
96
+ rndr_table(struct buf *ob, const struct buf *header, const struct buf *body, void *opaque)
97
+ {
98
+ BLOCK_CALLBACK("table", 2, buf2str(header), buf2str(body));
99
+ }
100
+
101
+ static void
102
+ rndr_tablerow(struct buf *ob, const struct buf *text, void *opaque)
103
+ {
104
+ BLOCK_CALLBACK("table_row", 1, buf2str(text));
105
+ }
106
+
107
+ static void
108
+ rndr_tablecell(struct buf *ob, const struct buf *text, int align, void *opaque)
109
+ {
110
+ VALUE rb_align;
111
+
112
+ switch (align) {
113
+ case MKD_TABLE_ALIGN_L:
114
+ rb_align = CSTR2SYM("left");
115
+ break;
116
+
117
+ case MKD_TABLE_ALIGN_R:
118
+ rb_align = CSTR2SYM("right");
119
+ break;
120
+
121
+ case MKD_TABLE_ALIGN_CENTER:
122
+ rb_align = CSTR2SYM("center");
123
+ break;
124
+
125
+ default:
126
+ rb_align = Qnil;
127
+ break;
128
+ }
129
+
130
+ BLOCK_CALLBACK("table_cell", 2, buf2str(text), rb_align);
131
+ }
132
+
133
+ static void
134
+ rndr_footnotes(struct buf *ob, const struct buf *text, void *opaque)
135
+ {
136
+ BLOCK_CALLBACK("footnotes", 1, buf2str(text));
137
+ }
138
+
139
+ static void
140
+ rndr_footnote_def(struct buf *ob, const struct buf *text, unsigned int num, void *opaque)
141
+ {
142
+ BLOCK_CALLBACK("footnote_def", 2, buf2str(text), INT2FIX(num));
143
+ }
144
+
145
+
146
+ /***
147
+ * SPAN LEVEL
148
+ */
149
+ static int
150
+ rndr_autolink(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque)
151
+ {
152
+ SPAN_CALLBACK("autolink", 2, buf2str(link),
153
+ type == MKDA_NORMAL ? CSTR2SYM("url") : CSTR2SYM("email"));
154
+ }
155
+
156
+ static int
157
+ rndr_codespan(struct buf *ob, const struct buf *text, void *opaque)
158
+ {
159
+ SPAN_CALLBACK("codespan", 1, buf2str(text));
160
+ }
161
+
162
+ static int
163
+ rndr_double_emphasis(struct buf *ob, const struct buf *text, void *opaque)
164
+ {
165
+ SPAN_CALLBACK("double_emphasis", 1, buf2str(text));
166
+ }
167
+
168
+ static int
169
+ rndr_emphasis(struct buf *ob, const struct buf *text, void *opaque)
170
+ {
171
+ SPAN_CALLBACK("emphasis", 1, buf2str(text));
172
+ }
173
+
174
+ static int
175
+ rndr_underline(struct buf *ob, const struct buf *text, void *opaque)
176
+ {
177
+ SPAN_CALLBACK("underline", 1, buf2str(text));
178
+ }
179
+
180
+ static int
181
+ rndr_highlight(struct buf *ob, const struct buf *text, void *opaque)
182
+ {
183
+ SPAN_CALLBACK("highlight", 1, buf2str(text));
184
+ }
185
+
186
+ static int
187
+ rndr_quote(struct buf *ob, const struct buf *text, void *opaque)
188
+ {
189
+ SPAN_CALLBACK("quote", 1, buf2str(text));
190
+ }
191
+
192
+ static int
193
+ rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque)
194
+ {
195
+ SPAN_CALLBACK("image", 3, buf2str(link), buf2str(title), buf2str(alt));
196
+ }
197
+
198
+ static int
199
+ rndr_linebreak(struct buf *ob, void *opaque)
200
+ {
201
+ SPAN_CALLBACK("linebreak", 0);
202
+ }
203
+
204
+ static int
205
+ rndr_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque)
206
+ {
207
+ SPAN_CALLBACK("link", 3, buf2str(link), buf2str(title), buf2str(content));
208
+ }
209
+
210
+ static int
211
+ rndr_raw_html(struct buf *ob, const struct buf *text, void *opaque)
212
+ {
213
+ SPAN_CALLBACK("raw_html", 1, buf2str(text));
214
+ }
215
+
216
+ static int
217
+ rndr_triple_emphasis(struct buf *ob, const struct buf *text, void *opaque)
218
+ {
219
+ SPAN_CALLBACK("triple_emphasis", 1, buf2str(text));
220
+ }
221
+
222
+ static int
223
+ rndr_strikethrough(struct buf *ob, const struct buf *text, void *opaque)
224
+ {
225
+ SPAN_CALLBACK("strikethrough", 1, buf2str(text));
226
+ }
227
+
228
+ static int
229
+ rndr_superscript(struct buf *ob, const struct buf *text, void *opaque)
230
+ {
231
+ SPAN_CALLBACK("superscript", 1, buf2str(text));
232
+ }
233
+
234
+ static int
235
+ rndr_footnote_ref(struct buf *ob, unsigned int num, void *opaque)
236
+ {
237
+ SPAN_CALLBACK("footnote_ref", 1, INT2FIX(num));
238
+ }
239
+
240
+ /**
241
+ * direct writes
242
+ */
243
+ static void
244
+ rndr_entity(struct buf *ob, const struct buf *text, void *opaque)
245
+ {
246
+ BLOCK_CALLBACK("entity", 1, buf2str(text));
247
+ }
248
+
249
+ static void
250
+ rndr_normal_text(struct buf *ob, const struct buf *text, void *opaque)
251
+ {
252
+ BLOCK_CALLBACK("normal_text", 1, buf2str(text));
253
+ }
254
+
255
+ static void
256
+ rndr_doc_header(struct buf *ob, void *opaque)
257
+ {
258
+ BLOCK_CALLBACK("doc_header", 0);
259
+ }
260
+
261
+ static void
262
+ rndr_doc_footer(struct buf *ob, void *opaque)
263
+ {
264
+ BLOCK_CALLBACK("doc_footer", 0);
265
+ }
266
+
267
+ static int
268
+ cb_link_attribute(VALUE key, VALUE val, VALUE payload)
269
+ {
270
+ struct buf *ob = (struct buf *)payload;
271
+ key = rb_obj_as_string(key);
272
+ val = rb_obj_as_string(val);
273
+ bufprintf(ob, " %s=\"%s\"", StringValueCStr(key), StringValueCStr(val));
274
+ return 0;
275
+ }
276
+
277
+ static void
278
+ rndr_link_attributes(struct buf *ob, const struct buf *url, void *opaque)
279
+ {
280
+ struct redcarpet_renderopt *opt = opaque;
281
+ struct rb_redcarpet_rndr *rndr;
282
+
283
+ Data_Get_Struct(opt->self, struct rb_redcarpet_rndr, rndr);
284
+ Check_Type(opt->link_attributes, T_HASH);
285
+ rb_hash_foreach(opt->link_attributes, &cb_link_attribute, (VALUE)ob);
286
+ }
287
+
288
+ static struct sd_callbacks rb_redcarpet_callbacks = {
289
+ rndr_blockcode,
290
+ rndr_blockquote,
291
+ rndr_raw_block,
292
+ rndr_header,
293
+ rndr_hrule,
294
+ rndr_list,
295
+ rndr_listitem,
296
+ rndr_paragraph,
297
+ rndr_table,
298
+ rndr_tablerow,
299
+ rndr_tablecell,
300
+ rndr_footnotes,
301
+ rndr_footnote_def,
302
+
303
+ rndr_autolink,
304
+ rndr_codespan,
305
+ rndr_double_emphasis,
306
+ rndr_emphasis,
307
+ rndr_underline,
308
+ rndr_highlight,
309
+ rndr_quote,
310
+ rndr_image,
311
+ rndr_linebreak,
312
+ rndr_link,
313
+ rndr_raw_html,
314
+ rndr_triple_emphasis,
315
+ rndr_strikethrough,
316
+ rndr_superscript,
317
+ rndr_footnote_ref,
318
+
319
+ rndr_entity,
320
+ rndr_normal_text,
321
+
322
+ rndr_doc_header,
323
+ rndr_doc_footer,
324
+ };
325
+
326
+ static const char *rb_redcarpet_method_names[] = {
327
+ "block_code",
328
+ "block_quote",
329
+ "block_html",
330
+ "header",
331
+ "hrule",
332
+ "list",
333
+ "list_item",
334
+ "paragraph",
335
+ "table",
336
+ "table_row",
337
+ "table_cell",
338
+ "footnotes",
339
+ "footnote_def",
340
+
341
+ "autolink",
342
+ "codespan",
343
+ "double_emphasis",
344
+ "emphasis",
345
+ "underline",
346
+ "highlight",
347
+ "quote",
348
+ "image",
349
+ "linebreak",
350
+ "link",
351
+ "raw_html",
352
+ "triple_emphasis",
353
+ "strikethrough",
354
+ "superscript",
355
+ "footnote_ref",
356
+
357
+ "entity",
358
+ "normal_text",
359
+
360
+ "doc_header",
361
+ "doc_footer"
362
+ };
363
+
364
+ static const size_t rb_redcarpet_method_count = sizeof(rb_redcarpet_method_names)/sizeof(char *);
365
+
366
+ static void rb_redcarpet_rbase_mark(struct rb_redcarpet_rndr *rndr)
367
+ {
368
+ if (rndr->options.link_attributes)
369
+ rb_gc_mark(rndr->options.link_attributes);
370
+ }
371
+
372
+ static VALUE rb_redcarpet_rbase_alloc(VALUE klass)
373
+ {
374
+ struct rb_redcarpet_rndr *rndr = ALLOC(struct rb_redcarpet_rndr);
375
+ memset(rndr, 0x0, sizeof(struct rb_redcarpet_rndr));
376
+ return Data_Wrap_Struct(klass, rb_redcarpet_rbase_mark, NULL, rndr);
377
+ }
378
+
379
+ static void rb_redcarpet__overload(VALUE self, VALUE base_class)
380
+ {
381
+ struct rb_redcarpet_rndr *rndr;
382
+
383
+ Data_Get_Struct(self, struct rb_redcarpet_rndr, rndr);
384
+ rndr->options.self = self;
385
+ rndr->options.base_class = base_class;
386
+
387
+ if (rb_obj_class(self) == rb_cRenderBase)
388
+ rb_raise(rb_eRuntimeError,
389
+ "The Redcarpet::Render::Base class cannot be instantiated. "
390
+ "Create an inheriting class instead to implement a custom renderer.");
391
+
392
+ if (rb_obj_class(self) != base_class) {
393
+ void **source = (void **)&rb_redcarpet_callbacks;
394
+ void **dest = (void **)&rndr->callbacks;
395
+ size_t i;
396
+
397
+ for (i = 0; i < rb_redcarpet_method_count; ++i) {
398
+ if (rb_respond_to(self, rb_intern(rb_redcarpet_method_names[i])))
399
+ dest[i] = source[i];
400
+ }
401
+ }
402
+ }
403
+
404
+ static VALUE rb_redcarpet_rbase_init(VALUE self)
405
+ {
406
+ rb_redcarpet__overload(self, rb_cRenderBase);
407
+ return Qnil;
408
+ }
409
+
410
+ static VALUE rb_redcarpet_html_init(int argc, VALUE *argv, VALUE self)
411
+ {
412
+ struct rb_redcarpet_rndr *rndr;
413
+ unsigned int render_flags = 0;
414
+ VALUE hash, link_attr = Qnil;
415
+
416
+ Data_Get_Struct(self, struct rb_redcarpet_rndr, rndr);
417
+
418
+ if (rb_scan_args(argc, argv, "01", &hash) == 1) {
419
+ Check_Type(hash, T_HASH);
420
+
421
+ /* escape_html */
422
+ if (rb_hash_aref(hash, CSTR2SYM("escape_html")) == Qtrue)
423
+ render_flags |= HTML_ESCAPE;
424
+
425
+ /* filter_html */
426
+ if (rb_hash_aref(hash, CSTR2SYM("filter_html")) == Qtrue)
427
+ render_flags |= HTML_SKIP_HTML;
428
+
429
+ /* no_image */
430
+ if (rb_hash_aref(hash, CSTR2SYM("no_images")) == Qtrue)
431
+ render_flags |= HTML_SKIP_IMAGES;
432
+
433
+ /* no_links */
434
+ if (rb_hash_aref(hash, CSTR2SYM("no_links")) == Qtrue)
435
+ render_flags |= HTML_SKIP_LINKS;
436
+
437
+ /* prettify */
438
+ if (rb_hash_aref(hash, CSTR2SYM("prettify")) == Qtrue)
439
+ render_flags |= HTML_PRETTIFY;
440
+
441
+ /* filter_style */
442
+ if (rb_hash_aref(hash, CSTR2SYM("no_styles")) == Qtrue)
443
+ render_flags |= HTML_SKIP_STYLE;
444
+
445
+ /* safelink */
446
+ if (rb_hash_aref(hash, CSTR2SYM("safe_links_only")) == Qtrue)
447
+ render_flags |= HTML_SAFELINK;
448
+
449
+ if (rb_hash_aref(hash, CSTR2SYM("with_toc_data")) == Qtrue)
450
+ render_flags |= HTML_TOC;
451
+
452
+ if (rb_hash_aref(hash, CSTR2SYM("hard_wrap")) == Qtrue)
453
+ render_flags |= HTML_HARD_WRAP;
454
+
455
+ if (rb_hash_aref(hash, CSTR2SYM("xhtml")) == Qtrue)
456
+ render_flags |= HTML_USE_XHTML;
457
+
458
+ link_attr = rb_hash_aref(hash, CSTR2SYM("link_attributes"));
459
+ }
460
+
461
+ sdhtml_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html, render_flags);
462
+ rb_redcarpet__overload(self, rb_cRenderHTML);
463
+
464
+ if (!NIL_P(link_attr)) {
465
+ rndr->options.link_attributes = link_attr;
466
+ rndr->options.html.link_attributes = &rndr_link_attributes;
467
+ }
468
+
469
+ return Qnil;
470
+ }
471
+
472
+ static VALUE rb_redcarpet_htmltoc_init(int argc, VALUE *argv, VALUE self)
473
+ {
474
+ struct rb_redcarpet_rndr *rndr;
475
+ int nesting_level = 6;
476
+ VALUE hash, key = Qnil;
477
+
478
+ Data_Get_Struct(self, struct rb_redcarpet_rndr, rndr);
479
+
480
+ if (rb_scan_args(argc, argv, "01", &hash) == 1) {
481
+ Check_Type(hash, T_HASH);
482
+
483
+ key = CSTR2SYM("nesting_level");
484
+
485
+ if (RTEST(rb_hash_aref(hash, key))) {
486
+ Check_Type(rb_hash_aref(hash, key), T_FIXNUM);
487
+ nesting_level = NUM2INT(rb_hash_aref(hash, key));
488
+ }
489
+ }
490
+
491
+ sdhtml_toc_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html, nesting_level);
492
+ rb_redcarpet__overload(self, rb_cRenderHTML_TOC);
493
+
494
+ return Qnil;
495
+ }
496
+
497
+ static VALUE rb_redcarpet_smartypants_render(VALUE self, VALUE text)
498
+ {
499
+ VALUE result;
500
+ struct buf *output_buf;
501
+
502
+ Check_Type(text, T_STRING);
503
+
504
+ output_buf = bufnew(128);
505
+
506
+ sdhtml_smartypants(output_buf, (const uint8_t*)RSTRING_PTR(text), RSTRING_LEN(text));
507
+ result = rb_enc_str_new((const char*)output_buf->data, output_buf->size, rb_enc_get(text));
508
+
509
+ bufrelease(output_buf);
510
+ return result;
511
+ }
512
+
513
+ void Init_redcarpet_rndr()
514
+ {
515
+ rb_mRender = rb_define_module_under(rb_mRedcarpet, "Render");
516
+
517
+ rb_cRenderBase = rb_define_class_under(rb_mRender, "Base", rb_cObject);
518
+ rb_define_alloc_func(rb_cRenderBase, rb_redcarpet_rbase_alloc);
519
+ rb_define_method(rb_cRenderBase, "initialize", rb_redcarpet_rbase_init, 0);
520
+
521
+ rb_cRenderHTML = rb_define_class_under(rb_mRender, "HTML", rb_cRenderBase);
522
+ rb_define_method(rb_cRenderHTML, "initialize", rb_redcarpet_html_init, -1);
523
+
524
+ rb_cRenderHTML_TOC = rb_define_class_under(rb_mRender, "HTML_TOC", rb_cRenderBase);
525
+ rb_define_method(rb_cRenderHTML_TOC, "initialize", rb_redcarpet_htmltoc_init, -1);
526
+
527
+ rb_mSmartyPants = rb_define_module_under(rb_mRender, "SmartyPants");
528
+ rb_define_method(rb_mSmartyPants, "postprocess", rb_redcarpet_smartypants_render, 1);
529
+ }