redcarpet 3.3.4 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 22bddd1461e328aa2fbe6efb52ed876bb3ce23e5
4
- data.tar.gz: 88c87895f31eedbd763c33798725d1707319c85c
2
+ SHA256:
3
+ metadata.gz: 3e6ea78031a1e40620168cd57fcbfae06bec5bafabc8f6e600adc552a4fe5b40
4
+ data.tar.gz: 658dd33e836daa11effa88e0491d09387963ea349751efd278e9fbdac7026066
5
5
  SHA512:
6
- metadata.gz: 98be06e055fe5f742ca0113d7e88379238919893586378ff0ce765ed64cd44c676be362b8bb1626c01e2f3fc71bb3ff33cf267919163d82d80d50665b96a73aa
7
- data.tar.gz: fe463bbfb1e0d416c817faf851c1fcbcf91654906b844c0ad34a58cd612cdce5b3c4392016b34302e6672ad67a93a6a99556f35b7f3d193271fce547caf69857
6
+ metadata.gz: b17b0208c25d4e8566fb4a154d0f66e778b702abcf58d1d1227fa2510be421c7496e20fd6402066adba3485778e935b46aff73fd412802eedb89e44470a7ad94
7
+ data.tar.gz: 1e1c8dd559979b8bd5f4de2d20e1127b2a964c03a267133c3d9a3703f71bce44a2f4dc2efdb0dc0cc331e0ab779bfad23e9b62af0ffc4ee9078896376bd86865
data/Gemfile CHANGED
@@ -3,7 +3,7 @@ source "https://rubygems.org/"
3
3
  gemspec
4
4
 
5
5
  group :benchmark do
6
- gem "benchmark-ips", "~> 2.3.0"
6
+ gem "benchmark-ips", "~> 2.7.2"
7
7
  gem "bluecloth", "~> 2.2.0"
8
- gem "kramdown", "~> 1.8.0"
8
+ gem "kramdown", "~> 1.13.2"
9
9
  end
data/README.markdown CHANGED
@@ -3,6 +3,7 @@ Redcarpet is written with sugar, spice and everything nice
3
3
 
4
4
  [![Build Status](https://travis-ci.org/vmg/redcarpet.svg?branch=master)](https://travis-ci.org/vmg/redcarpet)
5
5
  [![Dependency Status](https://www.versioneye.com/ruby/redcarpet/badge.svg)](https://www.versioneye.com/ruby/redcarpet)
6
+ [![Help Contribute to Open Source](https://www.codetriage.com/vmg/redcarpet/badges/users.svg)](https://www.codetriage.com/vmg/redcarpet)
6
7
 
7
8
  Redcarpet is a Ruby library for Markdown processing that smells like
8
9
  butterflies and popcorn.
@@ -25,7 +26,7 @@ Starting with Redcarpet 3.0, the minimum required Ruby version is 1.9.2 (or Rubi
25
26
 
26
27
  $ [sudo] gem install redcarpet
27
28
 
28
- If you need to use it with Ruby 1.8.7, you will need to stick with 2.3.0:
29
+ If you need to use it with Ruby 1.8.7, you will have to stick with 2.3.0:
29
30
 
30
31
  $ [sudo] gem install redcarpet -v 2.3.0
31
32
 
@@ -45,10 +46,10 @@ output.
45
46
  The `Redcarpet::Markdown` object is encouraged to be instantiated once with the
46
47
  required settings, and reused between parses.
47
48
 
48
- ~~~~~ ruby
49
+ ~~~~ ruby
49
50
  # Initializes a Markdown parser
50
51
  markdown = Redcarpet::Markdown.new(renderer, extensions = {})
51
- ~~~~~
52
+ ~~~~
52
53
 
53
54
  Here, the `renderer` variable refers to a renderer object, inheriting
54
55
  from `Redcarpet::Render::Base`. If the given object has not been
@@ -59,10 +60,10 @@ Unlike in the RedCloth API, the text to render is passed as an argument
59
60
  and not stored inside the `Markdown` instance, to encourage reusability.
60
61
  Example:
61
62
 
62
- ~~~~~ ruby
63
+ ~~~~ ruby
63
64
  markdown.render("This is *bongos*, indeed.")
64
65
  # => "<p>This is <em>bongos</em>, indeed.</p>"
65
- ~~~~~
66
+ ~~~~
66
67
 
67
68
  You can also specify a hash containing the Markdown extensions which the
68
69
  parser will identify. The following extensions are accepted:
@@ -119,9 +120,9 @@ within the document (e.g. `[^1]: This is a footnote.`).
119
120
 
120
121
  Example:
121
122
 
122
- ~~~ruby
123
+ ~~~~ ruby
123
124
  markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, autolink: true, tables: true)
124
- ~~~~~
125
+ ~~~~
125
126
 
126
127
  Darling, I packed you a couple renderers for lunch
127
128
  --------------------------------------------------
@@ -136,9 +137,9 @@ All the rendering flags that previously applied only to HTML output have
136
137
  now been moved to the `Redcarpet::Render::HTML` class, and may be enabled when
137
138
  instantiating the renderer:
138
139
 
139
- ~~~~~ ruby
140
+ ~~~~ ruby
140
141
  Redcarpet::Render::HTML.new(render_options = {})
141
- ~~~~~
142
+ ~~~~
142
143
 
143
144
  Initializes an HTML renderer. The following flags are available:
144
145
 
@@ -172,9 +173,9 @@ Markdown document had newlines (by default, Markdown ignores these newlines).
172
173
 
173
174
  Example:
174
175
 
175
- ~~~~~ ruby
176
+ ~~~~ ruby
176
177
  renderer = Redcarpet::Render::HTML.new(no_links: true, hard_wrap: true)
177
- ~~~~~
178
+ ~~~~
178
179
 
179
180
 
180
181
  The `HTML` renderer has an alternate version, `Redcarpet::Render::HTML_TOC`,
@@ -182,12 +183,21 @@ which will output a table of contents in HTML based on the headers of the
182
183
  Markdown document.
183
184
 
184
185
  When instantiating this render object, you can optionally pass a `nesting_level`
185
- option which takes an integer and allows you to make it render only headers
186
- until a specific level.
186
+ option which takes an integer or a range and allows you to make it render only
187
+ headers at certain levels.
187
188
 
188
- Furthermore, the abstract base class `Redcarpet::Render::Base` can be used
189
- to write a custom renderer purely in Ruby, or extending an existing renderer.
190
- See the following section for more information.
189
+ Redcarpet also includes a plaintext renderer, `Redcarpet::Render::StripDown`, that
190
+ strips out all the formatting:
191
+
192
+ ~~~~ ruby
193
+ require 'redcarpet'
194
+ require 'redcarpet/render_strip'
195
+
196
+ markdown = Redcarpet::Markdown.new(Redcarpet::Render::StripDown)
197
+
198
+ markdown.render("**This** _is_ an [example](http://example.org/).")
199
+ # => "This is an example (http://example.org/)."
200
+ ~~~~
191
201
 
192
202
 
193
203
  And you can even cook your own
@@ -196,25 +206,26 @@ And you can even cook your own
196
206
  Custom renderers are created by inheriting from an existing renderer. The
197
207
  built-in renderers, `HTML` and `XHTML` may be extended as such:
198
208
 
199
- ~~~~~ ruby
200
- # create a custom renderer that allows highlighting of code blocks
201
- class HTMLwithPygments < Redcarpet::Render::HTML
202
- def block_code(code, language)
203
- Pygments.highlight(code, lexer: language)
209
+ ~~~~ ruby
210
+ # Create a custom renderer that sets a custom class for block-quotes.
211
+ class CustomRender < Redcarpet::Render::HTML
212
+ def block_quote(quote)
213
+ %(<blockquote class="my-custom-class">#{quote}</blockquote>)
204
214
  end
205
215
  end
206
216
 
207
- markdown = Redcarpet::Markdown.new(HTMLwithPygments, fenced_code_blocks: true)
208
- ~~~~~
217
+ markdown = Redcarpet::Markdown.new(CustomRender, fenced_code_blocks: true)
218
+ ~~~~
209
219
 
210
- But new renderers can also be created from scratch (see `lib/redcarpet/render_man.rb` for
211
- an example implementation of a Manpage renderer)
220
+ But new renderers can also be created from scratch by extending the abstract
221
+ base class `Redcarpet::Render::Base` (see `lib/redcarpet/render_man.rb` for
222
+ an example implementation of a Manpage renderer):
212
223
 
213
- ~~~~~~ ruby
224
+ ~~~~ ruby
214
225
  class ManPage < Redcarpet::Render::Base
215
226
  # you get the drill -- keep going from here
216
227
  end
217
- ~~~~~
228
+ ~~~~
218
229
 
219
230
  The following instance methods may be implemented by the renderer:
220
231
 
@@ -302,7 +313,7 @@ or after the rendering process begins:
302
313
  * postprocess(full_document)
303
314
 
304
315
  You can look at
305
- ["How to extend the Redcarpet 2 Markdown library?"](http://dev.af83.com/2012/02/27/howto-extend-the-redcarpet2-markdown-lib.html)
316
+ ["How to extend the Redcarpet 2 Markdown library?"](https://web.archive.org/web/20170505231254/http://dev.af83.com/2012/02/27/howto-extend-the-redcarpet2-markdown-lib.html)
306
317
  for some more explanations.
307
318
 
308
319
  Also, now our Pants are much smarter
@@ -327,7 +338,7 @@ end
327
338
 
328
339
  # Standalone
329
340
  Redcarpet::Render::SmartyPants.render("<p>Oh SmartyPants, you're so crazy...</p>")
330
- ~~~~~
341
+ ~~~~
331
342
 
332
343
  SmartyPants works on top of already-rendered HTML, and will ignore replacements
333
344
  inside the content of HTML tags and inside specific HTML blocks such as
@@ -352,16 +363,16 @@ renderer-independent, the results will be completely unreliable!
352
363
  Still, if major forces (let's say, tornadoes or other natural disasters) force you
353
364
  to keep a Markdown-compatibility layer, Redcarpet also supports this:
354
365
 
355
- ~~~~~ ruby
366
+ ~~~~ ruby
356
367
  require 'redcarpet/compat'
357
- ~~~~~
368
+ ~~~~
358
369
 
359
370
  Requiring the compatibility library will declare a `Markdown` class with the
360
371
  classical RedCloth API, e.g.
361
372
 
362
- ~~~~~ ruby
373
+ ~~~~ ruby
363
374
  Markdown.new('this is my text').to_html
364
- ~~~~~
375
+ ~~~~
365
376
 
366
377
  This class renders 100% standards compliant Markdown with 0 extensions. Nada.
367
378
  Don't even try to enable extensions with a compatibility layer, because
@@ -373,7 +384,7 @@ monkeypatches the Markdown class, you're a terrible human being. Just saying.
373
384
  Boring legal stuff
374
385
  ------------------
375
386
 
376
- Copyright (c) 2011-2015, Vicent Martí
387
+ Copyright (c) 2011-2016, Vicent Martí
377
388
 
378
389
  Permission is hereby granted, free of charge, to any person obtaining a copy
379
390
  of this software and associated documentation files (the "Software"), to deal
@@ -294,9 +294,15 @@ sd_autolink__url(
294
294
  if (link_end == 0)
295
295
  return 0;
296
296
 
297
+ /**
298
+ * In certain cases, we may refer to a link at the end of a
299
+ * sentence so the period should not be part of the URL.
300
+ */
301
+ if (data[link_end - 1] == '.')
302
+ link_end--;
303
+
297
304
  bufput(link, data - rewind, link_end + rewind);
298
305
  *rewind_p = rewind;
299
306
 
300
307
  return link_end;
301
308
  }
302
-
@@ -86,4 +86,3 @@ void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf,
86
86
  #endif
87
87
 
88
88
  #endif
89
-
@@ -44,10 +44,10 @@
44
44
  * have its native function (i.e. as an URL
45
45
  * component/separator) and hence needs no escaping.
46
46
  *
47
- * There are two exceptions: the chacters & (amp)
48
- * and ' (single quote) do not appear in the table.
49
- * They are meant to appear in the URL as components,
50
- * yet they require special HTML-entity escaping
47
+ * There is one exception: the ' (single quote)
48
+ * character does not appear in the table.
49
+ * It is meant to appear in the URL as components,
50
+ * however it require special HTML-entity escaping
51
51
  * to generate valid HTML markup.
52
52
  *
53
53
  * All other characters will be escaped to %XX.
@@ -56,7 +56,7 @@
56
56
  static const char HREF_SAFE[] = {
57
57
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58
58
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59
- 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
59
+ 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
60
60
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
61
61
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
62
62
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
@@ -95,12 +95,6 @@ houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size)
95
95
  break;
96
96
 
97
97
  switch (src[i]) {
98
- /* amp appears all the time in URLs, but needs
99
- * HTML-entity escaping to be inside an href */
100
- case '&':
101
- BUFPUTSL(ob, "&amp;");
102
- break;
103
-
104
98
  /* the single quote is a valid URL character
105
99
  * according to the standard; it needs HTML
106
100
  * entity escaping too */
@@ -102,4 +102,3 @@ houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size)
102
102
  {
103
103
  houdini_escape_html0(ob, src, size, 1);
104
104
  }
105
-
data/ext/redcarpet/html.c CHANGED
@@ -255,8 +255,15 @@ rndr_quote(struct buf *ob, const struct buf *text, void *opaque)
255
255
  if (!text || !text->size)
256
256
  return 0;
257
257
 
258
+ struct html_renderopt *options = opaque;
259
+
258
260
  BUFPUTSL(ob, "<q>");
259
- bufput(ob, text->data, text->size);
261
+
262
+ if (options->flags & HTML_ESCAPE)
263
+ escape_html(ob, text->data, text->size);
264
+ else
265
+ bufput(ob, text->data, text->size);
266
+
260
267
  BUFPUTSL(ob, "</q>");
261
268
 
262
269
  return 1;
@@ -281,13 +288,20 @@ rndr_header_anchor(struct buf *out, const struct buf *anchor)
281
288
  int stripped = 0, inserted = 0;
282
289
 
283
290
  for (; i < size; ++i) {
291
+ // skip html tags
284
292
  if (a[i] == '<') {
285
293
  while (i < size && a[i] != '>')
286
294
  i++;
295
+ // skip html entities
296
+ } else if (a[i] == '&') {
297
+ while (i < size && a[i] != ';')
298
+ i++;
287
299
  }
300
+ // replace non-ascii or invalid characters with dashes
288
301
  else if (!isascii(a[i]) || strchr(STRIPPED, a[i])) {
289
302
  if (inserted && !stripped)
290
303
  bufputc(out, '-');
304
+ // and do it only once
291
305
  stripped = 1;
292
306
  }
293
307
  else {
@@ -297,8 +311,18 @@ rndr_header_anchor(struct buf *out, const struct buf *anchor)
297
311
  }
298
312
  }
299
313
 
300
- if (stripped)
314
+ // replace the last dash if there was anything added
315
+ if (stripped && inserted)
301
316
  out->size--;
317
+
318
+ // if anchor found empty, use djb2 hash for it
319
+ if (!inserted && anchor->size) {
320
+ unsigned long hash = 5381;
321
+ for (i = 0; i < size; ++i) {
322
+ hash = ((hash << 5) + hash) + a[i]; /* h * 33 + c */
323
+ }
324
+ bufprintf(out, "part-%lx", hash);
325
+ }
302
326
  }
303
327
 
304
328
  static void
@@ -309,7 +333,8 @@ rndr_header(struct buf *ob, const struct buf *text, int level, void *opaque)
309
333
  if (ob->size)
310
334
  bufputc(ob, '\n');
311
335
 
312
- if ((options->flags & HTML_TOC) && (level <= options->toc_data.nesting_level)) {
336
+ if ((options->flags & HTML_TOC) && level >= options->toc_data.nesting_bounds[0] &&
337
+ level <= options->toc_data.nesting_bounds[1]) {
313
338
  bufprintf(ob, "<h%d id=\"", level);
314
339
  rndr_header_anchor(ob, text);
315
340
  BUFPUTSL(ob, "\">");
@@ -638,7 +663,7 @@ rndr_footnote_def(struct buf *ob, const struct buf *text, unsigned int num, void
638
663
  bufprintf(ob, "\n<li id=\"fn%d\">\n", num);
639
664
  if (pfound) {
640
665
  bufput(ob, text->data, i);
641
- bufprintf(ob, "&nbsp;<a href=\"#fnref%d\" rev=\"footnote\">&#8617;</a>", num);
666
+ bufprintf(ob, "&nbsp;<a href=\"#fnref%d\">&#8617;</a>", num);
642
667
  bufput(ob, text->data + i, text->size - i);
643
668
  } else if (text) {
644
669
  bufput(ob, text->data, text->size);
@@ -649,7 +674,7 @@ rndr_footnote_def(struct buf *ob, const struct buf *text, unsigned int num, void
649
674
  static int
650
675
  rndr_footnote_ref(struct buf *ob, unsigned int num, void *opaque)
651
676
  {
652
- bufprintf(ob, "<sup id=\"fnref%d\"><a href=\"#fn%d\" rel=\"footnote\">%d</a></sup>", num, num, num);
677
+ bufprintf(ob, "<sup id=\"fnref%d\"><a href=\"#fn%d\">%d</a></sup>", num, num, num);
653
678
  return 1;
654
679
  }
655
680
 
@@ -658,7 +683,8 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
658
683
  {
659
684
  struct html_renderopt *options = opaque;
660
685
 
661
- if (level <= options->toc_data.nesting_level) {
686
+ if (level >= options->toc_data.nesting_bounds[0] &&
687
+ level <= options->toc_data.nesting_bounds[1]) {
662
688
  /* set the level offset if this is the first header
663
689
  * we're parsing for the document */
664
690
  if (options->toc_data.current_level == 0)
@@ -807,7 +833,8 @@ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options,
807
833
  /* Prepare the options pointer */
808
834
  memset(options, 0x0, sizeof(struct html_renderopt));
809
835
  options->flags = render_flags;
810
- options->toc_data.nesting_level = 99;
836
+ options->toc_data.nesting_bounds[0] = 1;
837
+ options->toc_data.nesting_bounds[1] = 6;
811
838
 
812
839
  /* Prepare the callbacks */
813
840
  memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks));
data/ext/redcarpet/html.h CHANGED
@@ -35,7 +35,7 @@ struct html_renderopt {
35
35
  struct {
36
36
  int current_level;
37
37
  int level_offset;
38
- int nesting_level;
38
+ int nesting_bounds[2];
39
39
  } toc_data;
40
40
 
41
41
  unsigned int flags;
@@ -81,4 +81,3 @@ sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size);
81
81
  #endif
82
82
 
83
83
  #endif
84
-
@@ -1,6 +1,6 @@
1
- /* C code produced by gperf version 3.0.4 */
1
+ /* C code produced by gperf version 3.0.3 */
2
2
  /* Command-line: gperf -N find_block_tag -H hash_block_tag -C -c -E --ignore-case html_block_names.txt */
3
- /* See http://git.io/RN0ncw for the list of recognized elements */
3
+ /* See https://git.io/vPLqa for the list of recognized elements */
4
4
  /* Computed positions: -k'1-2' */
5
5
 
6
6
  #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
@@ -30,7 +30,7 @@
30
30
  error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
31
31
  #endif
32
32
 
33
- /* maximum key range = 67, duplicates = 0 */
33
+ /* maximum key range = 72, duplicates = 0 */
34
34
 
35
35
  #ifndef GPERF_DOWNCASE
36
36
  #define GPERF_DOWNCASE 1
@@ -94,34 +94,34 @@ hash_block_tag (str, len)
94
94
  {
95
95
  static const unsigned char asso_values[] =
96
96
  {
97
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
98
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
99
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
100
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
101
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
102
- 55, 50, 45, 40, 35, 30, 68, 68, 68, 68,
103
- 68, 68, 68, 68, 68, 15, 10, 15, 15, 15,
104
- 0, 20, 10, 10, 5, 68, 68, 0, 20, 25,
105
- 0, 68, 68, 0, 25, 0, 15, 68, 68, 68,
106
- 68, 68, 68, 68, 68, 68, 68, 15, 10, 15,
107
- 15, 15, 0, 20, 10, 10, 5, 68, 68, 0,
108
- 20, 25, 0, 68, 68, 0, 25, 0, 15, 68,
109
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
110
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
111
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
112
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
113
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
114
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
115
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
116
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
117
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
118
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
119
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
120
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
121
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
122
- 68, 68, 68, 68, 68, 68, 68
97
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
98
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
99
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
100
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
101
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
102
+ 26, 60, 55, 45, 40, 35, 73, 73, 73, 73,
103
+ 73, 73, 73, 73, 73, 20, 15, 15, 0, 35,
104
+ 0, 25, 10, 10, 5, 73, 73, 0, 15, 15,
105
+ 0, 73, 73, 15, 20, 10, 10, 73, 73, 73,
106
+ 73, 73, 73, 73, 73, 73, 73, 20, 15, 15,
107
+ 0, 35, 0, 25, 10, 10, 5, 73, 73, 0,
108
+ 15, 15, 0, 73, 73, 15, 20, 10, 10, 73,
109
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
110
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
111
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
112
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
113
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
114
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
115
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
116
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
117
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
118
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
119
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
120
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
121
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
122
+ 73, 73, 73, 73, 73, 73, 73
123
123
  };
124
- register int hval = len;
124
+ register unsigned int hval = len;
125
125
 
126
126
  switch (hval)
127
127
  {
@@ -135,12 +135,6 @@ hash_block_tag (str, len)
135
135
  return hval;
136
136
  }
137
137
 
138
- #ifdef __GNUC__
139
- __inline
140
- #if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
141
- __attribute__ ((__gnu_inline__))
142
- #endif
143
- #endif
144
138
  const char *
145
139
  find_block_tag (str, len)
146
140
  register const char *str;
@@ -148,76 +142,80 @@ find_block_tag (str, len)
148
142
  {
149
143
  enum
150
144
  {
151
- TOTAL_KEYWORDS = 41,
145
+ TOTAL_KEYWORDS = 43,
152
146
  MIN_WORD_LENGTH = 1,
153
147
  MAX_WORD_LENGTH = 10,
154
148
  MIN_HASH_VALUE = 1,
155
- MAX_HASH_VALUE = 67
149
+ MAX_HASH_VALUE = 72
156
150
  };
157
151
 
158
152
  static const char * const wordlist[] =
159
153
  {
160
154
  "",
161
155
  "p",
162
- "ul",
163
- "pre",
156
+ "dl",
157
+ "del",
164
158
  "form",
165
- "style",
159
+ "",
166
160
  "footer",
167
- "section",
168
- "", "", "",
161
+ "details",
162
+ "div",
163
+ "", "",
169
164
  "figure",
170
- "hr",
165
+ "ul",
171
166
  "fieldset",
172
- "math",
167
+ "",
173
168
  "figcaption",
174
169
  "header",
175
- "dl",
176
- "del",
177
- "",
178
- "blockquote",
170
+ "ol",
171
+ "pre",
172
+ "math",
173
+ "video",
179
174
  "script",
180
- "article",
181
- "div",
175
+ "section",
176
+ "noscript",
182
177
  "",
183
- "video",
178
+ "blockquote",
184
179
  "hgroup",
185
- "ol",
186
- "noscript",
187
- "", "",
180
+ "hr",
181
+ "ins",
182
+ "",
183
+ "style",
184
+ "output",
185
+ "summary",
186
+ "nav",
187
+ "",
188
+ "audio",
188
189
  "canvas",
189
190
  "dd",
190
- "nav",
191
+ "h1",
191
192
  "abbr",
192
- "audio",
193
- "iframe",
194
- "address",
195
- "ins",
196
- "",
197
193
  "table",
198
- "",
199
- "h6",
194
+ "iframe",
195
+ "article",
200
196
  "", "",
201
197
  "aside",
202
- "output",
203
- "h5",
198
+ "",
199
+ "h6",
204
200
  "", "",
205
201
  "tfoot",
206
202
  "",
203
+ "h5",
204
+ "", "", "", "",
207
205
  "h4",
208
206
  "", "", "", "",
209
- "h3",
207
+ "address",
210
208
  "", "", "", "",
211
- "h2",
209
+ "h3",
212
210
  "", "", "", "",
213
- "h1"
211
+ "h2"
214
212
  };
215
213
 
216
214
  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
217
215
  {
218
- register int key = hash_block_tag (str, len);
216
+ unsigned int key = hash_block_tag (str, len);
219
217
 
220
- if (key <= MAX_HASH_VALUE && key >= 0)
218
+ if (key <= MAX_HASH_VALUE)
221
219
  {
222
220
  register const char *s = wordlist[key];
223
221
 
@@ -151,6 +151,9 @@ smartypants_squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previo
151
151
  return next_squote_len;
152
152
  }
153
153
 
154
+ if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote))
155
+ return 0;
156
+
154
157
  // trailing single quotes: students', tryin'
155
158
  if (word_boundary(t1)) {
156
159
  BUFPUTSL(ob, "&rsquo;");
@@ -178,9 +181,6 @@ smartypants_squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previo
178
181
  }
179
182
  }
180
183
 
181
- if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote))
182
- return 0;
183
-
184
184
  bufput(ob, squote_text, squote_size);
185
185
  return 0;
186
186
  }
@@ -341,6 +341,7 @@ smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t prev
341
341
  };
342
342
  static const size_t skip_tags_count = 8;
343
343
 
344
+ size_t next_to_closing_a = 0;
344
345
  size_t tag, i = 0;
345
346
 
346
347
  while (i < size && text[i] != '>')
@@ -369,7 +370,23 @@ smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t prev
369
370
  i++;
370
371
  }
371
372
 
373
+ if (sdhtml_is_tag(text, size, "a") == HTML_TAG_CLOSE) {
374
+ while (i < size && text[i] != '>')
375
+ i++;
376
+
377
+ next_to_closing_a = 1;
378
+ }
379
+
372
380
  bufput(ob, text, i + 1);
381
+
382
+ // Pretty tricky: since people may refer to something or someone
383
+ // with a link but use the possessive form right after it, we need
384
+ // to check whether a single quote is next to a closing "</a"> tag.
385
+ if (next_to_closing_a && strncmp("&#39;", text+(i+1), 5) == 0) {
386
+ bufput(ob, "&rsquo;", 7);
387
+ i += 5;
388
+ }
389
+
373
390
  return i;
374
391
  }
375
392
 
@@ -453,5 +470,3 @@ sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size)
453
470
  }
454
471
  }
455
472
  }
456
-
457
-