redcarpet 2.2.2 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of redcarpet might be problematic. Click here for more details.

@@ -1,4 +1,4 @@
1
- /*
1
+ /*
2
2
  * Copyright (c) 2008, Natacha Porté
3
3
  * Copyright (c) 2011, Vicent Martí
4
4
  *
@@ -44,15 +44,7 @@ struct buf {
44
44
  size_t unit; /* reallocation unit size (0 = read-only buffer) */
45
45
  };
46
46
 
47
- /* CONST_BUF: global buffer from a string litteral */
48
- #define BUF_STATIC(string) \
49
- { (uint8_t *)string, sizeof string -1, sizeof string, 0, 0 }
50
-
51
- /* VOLATILE_BUF: macro for creating a volatile buffer on the stack */
52
- #define BUF_VOLATILE(strname) \
53
- { (uint8_t *)strname, strlen(strname), 0, 0, 0 }
54
-
55
- /* BUFPUTSL: optimized bufputs of a string litteral */
47
+ /* BUFPUTSL: optimized bufputs of a string literal */
56
48
  #define BUFPUTSL(output, literal) \
57
49
  bufput(output, literal, sizeof literal - 1)
58
50
 
@@ -94,3 +86,4 @@ void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf,
94
86
  #endif
95
87
 
96
88
  #endif
89
+
@@ -1,4 +1,6 @@
1
1
  require 'mkmf'
2
2
 
3
+ $CFLAGS << ' -fvisibility=hidden'
4
+
3
5
  dir_config('redcarpet')
4
6
  create_makefile('redcarpet')
@@ -118,11 +118,18 @@ rndr_autolink(struct buf *ob, const struct buf *link, enum mkd_autolink type, vo
118
118
  static void
119
119
  rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque)
120
120
  {
121
+ struct html_renderopt *options = opaque;
122
+
121
123
  if (ob->size) bufputc(ob, '\n');
122
124
 
123
125
  if (lang && lang->size) {
124
126
  size_t i, cls;
125
- BUFPUTSL(ob, "<pre><code class=\"");
127
+ if (options->flags & HTML_PRETTIFY) {
128
+ BUFPUTSL(ob, "<pre><code class=\"prettyprint");
129
+ cls++;
130
+ } else {
131
+ BUFPUTSL(ob, "<pre><code class=\"");
132
+ }
126
133
 
127
134
  for (i = 0, cls = 0; i < lang->size; ++i, ++cls) {
128
135
  while (i < lang->size && isspace(lang->data[i]))
@@ -142,8 +149,11 @@ rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, v
142
149
  }
143
150
 
144
151
  BUFPUTSL(ob, "\">");
145
- } else
152
+ } else if (options->flags & HTML_PRETTIFY) {
153
+ BUFPUTSL(ob, "<pre><code class=\"prettyprint\">");
154
+ } else {
146
155
  BUFPUTSL(ob, "<pre><code>");
156
+ }
147
157
 
148
158
  if (text)
149
159
  escape_html(ob, text->data, text->size);
@@ -163,7 +173,11 @@ rndr_blockquote(struct buf *ob, const struct buf *text, void *opaque)
163
173
  static int
164
174
  rndr_codespan(struct buf *ob, const struct buf *text, void *opaque)
165
175
  {
166
- BUFPUTSL(ob, "<code>");
176
+ struct html_renderopt *options = opaque;
177
+ if (options->flags & HTML_PRETTIFY)
178
+ BUFPUTSL(ob, "<code class=\"prettyprint\">");
179
+ else
180
+ BUFPUTSL(ob, "<code>");
167
181
  if (text) escape_html(ob, text->data, text->size);
168
182
  BUFPUTSL(ob, "</code>");
169
183
  return 1;
@@ -204,6 +218,19 @@ rndr_emphasis(struct buf *ob, const struct buf *text, void *opaque)
204
218
  return 1;
205
219
  }
206
220
 
221
+ static int
222
+ rndr_underline(struct buf *ob, const struct buf *text, void *opaque)
223
+ {
224
+ if (!text || !text->size)
225
+ return 0;
226
+
227
+ BUFPUTSL(ob, "<u>");
228
+ bufput(ob, text->data, text->size);
229
+ BUFPUTSL(ob, "</u>");
230
+
231
+ return 1;
232
+ }
233
+
207
234
  static int
208
235
  rndr_linebreak(struct buf *ob, void *opaque)
209
236
  {
@@ -559,6 +586,7 @@ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *optio
559
586
  rndr_codespan,
560
587
  rndr_double_emphasis,
561
588
  rndr_emphasis,
589
+ rndr_underline,
562
590
  NULL,
563
591
  NULL,
564
592
  toc_link,
@@ -600,6 +628,7 @@ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options,
600
628
  rndr_codespan,
601
629
  rndr_double_emphasis,
602
630
  rndr_emphasis,
631
+ rndr_underline,
603
632
  rndr_image,
604
633
  rndr_linebreak,
605
634
  rndr_link,
@@ -49,6 +49,7 @@ typedef enum {
49
49
  HTML_HARD_WRAP = (1 << 7),
50
50
  HTML_USE_XHTML = (1 << 8),
51
51
  HTML_ESCAPE = (1 << 9),
52
+ HTML_PRETTIFY = (1 << 10),
52
53
  } html_render_mode;
53
54
 
54
55
  typedef enum {
@@ -83,6 +83,26 @@ word_boundary(uint8_t c)
83
83
  return c == 0 || isspace(c) || ispunct(c);
84
84
  }
85
85
 
86
+ // If 'text' begins with any kind of single quote (e.g. "'" or "&apos;" etc.),
87
+ // returns the length of the sequence of characters that makes up the single-
88
+ // quote. Otherwise, returns zero.
89
+ static size_t
90
+ squote_len(const uint8_t *text, size_t size)
91
+ {
92
+ static char* single_quote_list[] = { "'", "&#39;", "&#x27;", "&apos;", NULL };
93
+ char** p;
94
+
95
+ for (p = single_quote_list; *p; ++p) {
96
+ size_t len = strlen(*p);
97
+ if (size >= len && memcmp(text, *p, len) == 0) {
98
+ return len;
99
+ }
100
+ }
101
+
102
+ return 0;
103
+ }
104
+
105
+ // Converts " or ' at very beginning or end of a word to left or right quote
86
106
  static int
87
107
  smartypants_quotes(struct buf *ob, uint8_t previous_char, uint8_t next_char, uint8_t quote, int *is_open)
88
108
  {
@@ -100,23 +120,33 @@ smartypants_quotes(struct buf *ob, uint8_t previous_char, uint8_t next_char, uin
100
120
  return 1;
101
121
  }
102
122
 
123
+ // Converts ' to left or right single quote; but the initial ' might be in
124
+ // different forms, e.g. &apos; or &#39; or &#x27;.
125
+ // 'squote_text' points to the original single quote, and 'squote_size' is its length.
126
+ // 'text' points at the last character of the single-quote, e.g. ' or ;
103
127
  static size_t
104
- smartypants_cb__squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
128
+ smartypants_squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size,
129
+ const uint8_t *squote_text, size_t squote_size)
105
130
  {
106
131
  if (size >= 2) {
107
132
  uint8_t t1 = tolower(text[1]);
133
+ int next_squote_len = squote_len(text+1, size-1);
108
134
 
109
- if (t1 == '\'') {
110
- if (smartypants_quotes(ob, previous_char, size >= 3 ? text[2] : 0, 'd', &smrt->in_dquote))
111
- return 1;
135
+ // convert '' to &ldquo; or &rdquo;
136
+ if (next_squote_len > 0) {
137
+ uint8_t next_char = (size > 1+next_squote_len) ? text[1+next_squote_len] : 0;
138
+ if (smartypants_quotes(ob, previous_char, next_char, 'd', &smrt->in_dquote))
139
+ return next_squote_len;
112
140
  }
113
141
 
142
+ // Tom's, isn't, I'm, I'd
114
143
  if ((t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') &&
115
144
  (size == 3 || word_boundary(text[2]))) {
116
145
  BUFPUTSL(ob, "&rsquo;");
117
146
  return 0;
118
147
  }
119
148
 
149
+ // you're, you'll, you've
120
150
  if (size >= 3) {
121
151
  uint8_t t2 = tolower(text[2]);
122
152
 
@@ -133,10 +163,18 @@ smartypants_cb__squote(struct buf *ob, struct smartypants_data *smrt, uint8_t pr
133
163
  if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote))
134
164
  return 0;
135
165
 
136
- bufputc(ob, text[0]);
166
+ bufput(ob, squote_text, squote_size);
137
167
  return 0;
138
168
  }
139
169
 
170
+ // Converts ' to left or right single quote.
171
+ static size_t
172
+ smartypants_cb__squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
173
+ {
174
+ return smartypants_squote(ob, smrt, previous_char, text, size, text, 1);
175
+ }
176
+
177
+ // Converts (c), (r), (tm)
140
178
  static size_t
141
179
  smartypants_cb__parens(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
142
180
  {
@@ -164,6 +202,7 @@ smartypants_cb__parens(struct buf *ob, struct smartypants_data *smrt, uint8_t pr
164
202
  return 0;
165
203
  }
166
204
 
205
+ // Converts "--" to em-dash, etc.
167
206
  static size_t
168
207
  smartypants_cb__dash(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
169
208
  {
@@ -181,6 +220,7 @@ smartypants_cb__dash(struct buf *ob, struct smartypants_data *smrt, uint8_t prev
181
220
  return 0;
182
221
  }
183
222
 
223
+ // Converts &quot; etc.
184
224
  static size_t
185
225
  smartypants_cb__amp(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
186
226
  {
@@ -189,6 +229,11 @@ smartypants_cb__amp(struct buf *ob, struct smartypants_data *smrt, uint8_t previ
189
229
  return 5;
190
230
  }
191
231
 
232
+ int len = squote_len(text, size);
233
+ if (len > 0) {
234
+ return (len-1) + smartypants_squote(ob, smrt, previous_char, text+(len-1), size-(len-1), text, len);
235
+ }
236
+
192
237
  if (size >= 4 && memcmp(text, "&#0;", 4) == 0)
193
238
  return 3;
194
239
 
@@ -196,6 +241,7 @@ smartypants_cb__amp(struct buf *ob, struct smartypants_data *smrt, uint8_t previ
196
241
  return 0;
197
242
  }
198
243
 
244
+ // Converts "..." to ellipsis
199
245
  static size_t
200
246
  smartypants_cb__period(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
201
247
  {
@@ -213,6 +259,7 @@ smartypants_cb__period(struct buf *ob, struct smartypants_data *smrt, uint8_t pr
213
259
  return 0;
214
260
  }
215
261
 
262
+ // Converts `` to opening double quote
216
263
  static size_t
217
264
  smartypants_cb__backtick(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
218
265
  {
@@ -221,9 +268,11 @@ smartypants_cb__backtick(struct buf *ob, struct smartypants_data *smrt, uint8_t
221
268
  return 1;
222
269
  }
223
270
 
271
+ bufputc(ob, text[0]);
224
272
  return 0;
225
273
  }
226
274
 
275
+ // Converts 1/2, 1/4, 3/4
227
276
  static size_t
228
277
  smartypants_cb__number(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
229
278
  {
@@ -256,6 +305,7 @@ smartypants_cb__number(struct buf *ob, struct smartypants_data *smrt, uint8_t pr
256
305
  return 0;
257
306
  }
258
307
 
308
+ // Converts " to left or right double quote
259
309
  static size_t
260
310
  smartypants_cb__dquote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
261
311
  {
@@ -64,6 +64,7 @@ typedef size_t
64
64
  (*char_trigger)(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
65
65
 
66
66
  static size_t char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
67
+ static size_t char_underline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
67
68
  static size_t char_linebreak(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
68
69
  static size_t char_codespan(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
69
70
  static size_t char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
@@ -135,7 +136,7 @@ rndr_newbuf(struct sd_markdown *rndr, int type)
135
136
  work->size = 0;
136
137
  } else {
137
138
  work = bufnew(buf_size[type]);
138
- stack_push(pool, work);
139
+ redcarpet_stack_push(pool, work);
139
140
  }
140
141
 
141
142
  return work;
@@ -487,8 +488,6 @@ parse_emph1(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
487
488
  struct buf *work = 0;
488
489
  int r;
489
490
 
490
- if (!rndr->cb.emphasis) return 0;
491
-
492
491
  /* skipping one symbol if coming from emph3 */
493
492
  if (size > 1 && data[0] == c && data[1] == c) i = 1;
494
493
 
@@ -507,7 +506,12 @@ parse_emph1(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
507
506
 
508
507
  work = rndr_newbuf(rndr, BUFFER_SPAN);
509
508
  parse_inline(work, rndr, data, i);
510
- r = rndr->cb.emphasis(ob, work, rndr->opaque);
509
+
510
+ if (rndr->ext_flags & MKDEXT_UNDERLINE && c == '_')
511
+ r = rndr->cb.underline(ob, work, rndr->opaque);
512
+ else
513
+ r = rndr->cb.emphasis(ob, work, rndr->opaque);
514
+
511
515
  rndr_popbuf(rndr, BUFFER_SPAN);
512
516
  return r ? i + 1 : 0;
513
517
  }
@@ -520,16 +524,10 @@ parse_emph1(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
520
524
  static size_t
521
525
  parse_emph2(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, uint8_t c)
522
526
  {
523
- int (*render_method)(struct buf *ob, const struct buf *text, void *opaque);
524
527
  size_t i = 0, len;
525
528
  struct buf *work = 0;
526
529
  int r;
527
530
 
528
- render_method = (c == '~') ? rndr->cb.strikethrough : rndr->cb.double_emphasis;
529
-
530
- if (!render_method)
531
- return 0;
532
-
533
531
  while (i < size) {
534
532
  len = find_emph_char(data + i, size - i, c);
535
533
  if (!len) return 0;
@@ -538,7 +536,12 @@ parse_emph2(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
538
536
  if (i + 1 < size && data[i] == c && data[i + 1] == c && i && !_isspace(data[i - 1])) {
539
537
  work = rndr_newbuf(rndr, BUFFER_SPAN);
540
538
  parse_inline(work, rndr, data, i);
541
- r = render_method(ob, work, rndr->opaque);
539
+
540
+ if (c == '~')
541
+ r = rndr->cb.strikethrough(ob, work, rndr->opaque);
542
+ else
543
+ r = rndr->cb.double_emphasis(ob, work, rndr->opaque);
544
+
542
545
  rndr_popbuf(rndr, BUFFER_SPAN);
543
546
  return r ? i + 2 : 0;
544
547
  }
@@ -2102,7 +2105,7 @@ parse_table_header(
2102
2105
  while (i < under_end && data[i] == ' ')
2103
2106
  i++;
2104
2107
 
2105
- if (i < under_end && data[i] != '|')
2108
+ if (i < under_end && data[i] != '|' && data[i] != '+')
2106
2109
  break;
2107
2110
 
2108
2111
  if (dashes < 3)
@@ -2230,7 +2233,7 @@ parse_block(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
2230
2233
  else if (prefix_quote(txt_data, end))
2231
2234
  beg += parse_blockquote(ob, rndr, txt_data, end);
2232
2235
 
2233
- else if (prefix_code(txt_data, end))
2236
+ else if (!(rndr->ext_flags & MKDEXT_DISABLE_INDENTED_CODE) && prefix_code(txt_data, end))
2234
2237
  beg += parse_blockcode(ob, rndr, txt_data, end);
2235
2238
 
2236
2239
  else if (prefix_uli(txt_data, end))
@@ -2410,8 +2413,8 @@ sd_markdown_new(
2410
2413
 
2411
2414
  memcpy(&md->cb, callbacks, sizeof(struct sd_callbacks));
2412
2415
 
2413
- stack_init(&md->work_bufs[BUFFER_BLOCK], 4);
2414
- stack_init(&md->work_bufs[BUFFER_SPAN], 8);
2416
+ redcarpet_stack_init(&md->work_bufs[BUFFER_BLOCK], 4);
2417
+ redcarpet_stack_init(&md->work_bufs[BUFFER_SPAN], 8);
2415
2418
 
2416
2419
  memset(md->active_char, 0x0, 256);
2417
2420
 
@@ -2539,8 +2542,8 @@ sd_markdown_free(struct sd_markdown *md)
2539
2542
  for (i = 0; i < (size_t)md->work_bufs[BUFFER_BLOCK].asize; ++i)
2540
2543
  bufrelease(md->work_bufs[BUFFER_BLOCK].item[i]);
2541
2544
 
2542
- stack_free(&md->work_bufs[BUFFER_SPAN]);
2543
- stack_free(&md->work_bufs[BUFFER_BLOCK]);
2545
+ redcarpet_stack_free(&md->work_bufs[BUFFER_SPAN]);
2546
+ redcarpet_stack_free(&md->work_bufs[BUFFER_BLOCK]);
2544
2547
 
2545
2548
  free(md);
2546
2549
  }
@@ -56,9 +56,11 @@ enum mkd_extensions {
56
56
  MKDEXT_FENCED_CODE = (1 << 2),
57
57
  MKDEXT_AUTOLINK = (1 << 3),
58
58
  MKDEXT_STRIKETHROUGH = (1 << 4),
59
+ MKDEXT_UNDERLINE = (1 << 5),
59
60
  MKDEXT_SPACE_HEADERS = (1 << 6),
60
61
  MKDEXT_SUPERSCRIPT = (1 << 7),
61
62
  MKDEXT_LAX_SPACING = (1 << 8),
63
+ MKDEXT_DISABLE_INDENTED_CODE = (1 << 9),
62
64
  };
63
65
 
64
66
  /* sd_callbacks - functions for rendering parsed data */
@@ -82,6 +84,7 @@ struct sd_callbacks {
82
84
  int (*codespan)(struct buf *ob, const struct buf *text, void *opaque);
83
85
  int (*double_emphasis)(struct buf *ob, const struct buf *text, void *opaque);
84
86
  int (*emphasis)(struct buf *ob, const struct buf *text, void *opaque);
87
+ int (*underline)(struct buf *ob, const struct buf *text, void *opaque);
85
88
  int (*image)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque);
86
89
  int (*linebreak)(struct buf *ob, void *opaque);
87
90
  int (*link)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque);
@@ -38,12 +38,18 @@ static void rb_redcarpet_md_flags(VALUE hash, unsigned int *enabled_extensions_p
38
38
  if (rb_hash_lookup(hash, CSTR2SYM("fenced_code_blocks")) == Qtrue)
39
39
  extensions |= MKDEXT_FENCED_CODE;
40
40
 
41
+ if (rb_hash_lookup(hash, CSTR2SYM("disable_indented_code_blocks")) == Qtrue)
42
+ extensions |= MKDEXT_DISABLE_INDENTED_CODE;
43
+
41
44
  if (rb_hash_lookup(hash, CSTR2SYM("autolink")) == Qtrue)
42
45
  extensions |= MKDEXT_AUTOLINK;
43
46
 
44
47
  if (rb_hash_lookup(hash, CSTR2SYM("strikethrough")) == Qtrue)
45
48
  extensions |= MKDEXT_STRIKETHROUGH;
46
49
 
50
+ if (rb_hash_lookup(hash, CSTR2SYM("underline")) == Qtrue)
51
+ extensions |= MKDEXT_UNDERLINE;
52
+
47
53
  if (rb_hash_lookup(hash, CSTR2SYM("lax_spacing")) == Qtrue)
48
54
  extensions |= MKDEXT_LAX_SPACING;
49
55
 
@@ -121,12 +127,12 @@ static VALUE rb_redcarpet_md_render(VALUE self, VALUE text)
121
127
  /* render the magic */
122
128
  sd_markdown_render(
123
129
  output_buf,
124
- RSTRING_PTR(text),
130
+ (const uint8_t*)RSTRING_PTR(text),
125
131
  RSTRING_LEN(text),
126
132
  markdown);
127
133
 
128
134
  /* build the Ruby string */
129
- text = redcarpet_str_new(output_buf->data, output_buf->size, rb_enc_get(text));
135
+ text = redcarpet_str_new((const char*)output_buf->data, output_buf->size, rb_enc_get(text));
130
136
 
131
137
  bufrelease(output_buf);
132
138
 
@@ -136,6 +142,7 @@ static VALUE rb_redcarpet_md_render(VALUE self, VALUE text)
136
142
  return text;
137
143
  }
138
144
 
145
+ __attribute__((visibility("default")))
139
146
  void Init_redcarpet()
140
147
  {
141
148
  rb_mRedcarpet = rb_define_module("Redcarpet");
@@ -41,9 +41,9 @@ VALUE rb_cRenderHTML_TOC;
41
41
  VALUE rb_mSmartyPants;
42
42
 
43
43
  #ifdef HAVE_RUBY_ENCODING_H
44
- #define buf2str(t) ((t) ? redcarpet_str_new((t)->data, (t)->size, opt->active_enc) : Qnil)
44
+ #define buf2str(t) ((t) ? redcarpet_str_new((const char*)(t)->data, (t)->size, opt->active_enc) : Qnil)
45
45
  #else
46
- #define buf2str(t) ((t) ? redcarpet_str_new((t)->data, (t)->size, NULL) : Qnil)
46
+ #define buf2str(t) ((t) ? redcarpet_str_new((const char*)(t)->data, (t)->size, NULL) : Qnil)
47
47
  #endif
48
48
 
49
49
  static void
@@ -165,6 +165,12 @@ rndr_emphasis(struct buf *ob, const struct buf *text, void *opaque)
165
165
  SPAN_CALLBACK("emphasis", 1, buf2str(text));
166
166
  }
167
167
 
168
+ static int
169
+ rndr_underline(struct buf *ob, const struct buf *text, void *opaque)
170
+ {
171
+ SPAN_CALLBACK("underline", 1, buf2str(text));
172
+ }
173
+
168
174
  static int
169
175
  rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque)
170
176
  {
@@ -272,6 +278,7 @@ static struct sd_callbacks rb_redcarpet_callbacks = {
272
278
  rndr_codespan,
273
279
  rndr_double_emphasis,
274
280
  rndr_emphasis,
281
+ rndr_underline,
275
282
  rndr_image,
276
283
  rndr_linebreak,
277
284
  rndr_link,
@@ -304,6 +311,7 @@ static const char *rb_redcarpet_method_names[] = {
304
311
  "codespan",
305
312
  "double_emphasis",
306
313
  "emphasis",
314
+ "underline",
307
315
  "image",
308
316
  "linebreak",
309
317
  "link",
@@ -321,11 +329,17 @@ static const char *rb_redcarpet_method_names[] = {
321
329
 
322
330
  static const size_t rb_redcarpet_method_count = sizeof(rb_redcarpet_method_names)/sizeof(char *);
323
331
 
332
+ static void rb_redcarpet_rbase_mark(struct rb_redcarpet_rndr *rndr)
333
+ {
334
+ if (rndr->options.link_attributes)
335
+ rb_gc_mark(rndr->options.link_attributes);
336
+ }
337
+
324
338
  static VALUE rb_redcarpet_rbase_alloc(VALUE klass)
325
339
  {
326
340
  struct rb_redcarpet_rndr *rndr = ALLOC(struct rb_redcarpet_rndr);
327
341
  memset(rndr, 0x0, sizeof(struct rb_redcarpet_rndr));
328
- return Data_Wrap_Struct(klass, NULL, NULL, rndr);
342
+ return Data_Wrap_Struct(klass, rb_redcarpet_rbase_mark, NULL, rndr);
329
343
  }
330
344
 
331
345
  static void rb_redcarpet__overload(VALUE self, VALUE base_class)
@@ -386,6 +400,10 @@ static VALUE rb_redcarpet_html_init(int argc, VALUE *argv, VALUE self)
386
400
  if (rb_hash_aref(hash, CSTR2SYM("no_links")) == Qtrue)
387
401
  render_flags |= HTML_SKIP_LINKS;
388
402
 
403
+ /* prettify */
404
+ if (rb_hash_aref(hash, CSTR2SYM("prettify")) == Qtrue)
405
+ render_flags |= HTML_PRETTIFY;
406
+
389
407
  /* filter_style */
390
408
  if (rb_hash_aref(hash, CSTR2SYM("no_styles")) == Qtrue)
391
409
  render_flags |= HTML_SKIP_STYLE;
@@ -437,8 +455,8 @@ static VALUE rb_redcarpet_smartypants_render(VALUE self, VALUE text)
437
455
 
438
456
  output_buf = bufnew(128);
439
457
 
440
- sdhtml_smartypants(output_buf, RSTRING_PTR(text), RSTRING_LEN(text));
441
- result = redcarpet_str_new(output_buf->data, output_buf->size, rb_enc_get(text));
458
+ sdhtml_smartypants(output_buf, (const uint8_t*)RSTRING_PTR(text), RSTRING_LEN(text));
459
+ result = redcarpet_str_new((const char*)output_buf->data, output_buf->size, rb_enc_get(text));
442
460
 
443
461
  bufrelease(output_buf);
444
462
  return result;