redcarpet 3.3.4 → 3.5.1

Sign up to get free protection for your applications and to get access to all the features.
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
-