redcarpet 1.15.2 → 1.16.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.

data/Rakefile CHANGED
@@ -116,10 +116,9 @@ task :gather => 'upskirt/src/markdown.h' do |t|
116
116
  files =
117
117
  FileList[
118
118
  'upskirt/src/{markdown,buffer,array}.h',
119
- 'upskirt/src/{markdown,buffer,array}.c',
120
- 'upskirt/render/html.c',
121
- 'upskirt/render/html_smartypants.c',
122
- 'upskirt/render/html.h',
119
+ 'upskirt/src/{markdown,buffer,array,autolink}.c',
120
+ 'upskirt/html/{html,html_smartypants,html_autolink}.c',
121
+ 'upskirt/html/html.h',
123
122
  ]
124
123
  cp files, 'ext/redcarpet/',
125
124
  :preserve => true,
@@ -0,0 +1,240 @@
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 "markdown.h"
18
+ #include "buffer.h"
19
+
20
+ #include <string.h>
21
+ #include <stdlib.h>
22
+ #include <stdio.h>
23
+ #include <ctype.h>
24
+
25
+ int
26
+ is_safe_link(const char *link, size_t link_len)
27
+ {
28
+ static const size_t valid_uris_count = 4;
29
+ static const char *valid_uris[] = {
30
+ "http://", "https://", "ftp://", "mailto://"
31
+ };
32
+
33
+ size_t i;
34
+
35
+ for (i = 0; i < valid_uris_count; ++i) {
36
+ size_t len = strlen(valid_uris[i]);
37
+
38
+ if (link_len > len &&
39
+ strncasecmp(link, valid_uris[i], len) == 0 &&
40
+ isalnum(link[len]))
41
+ return 1;
42
+ }
43
+
44
+ return 0;
45
+ }
46
+
47
+ static size_t
48
+ autolink_delim(char *data, size_t link_end, size_t offset, size_t size)
49
+ {
50
+ char cclose, copen = 0;
51
+
52
+ while (link_end > 0) {
53
+ if (strchr("?!.,", data[link_end - 1]) != NULL)
54
+ link_end--;
55
+
56
+ else if (data[link_end - 1] == ';') {
57
+ size_t new_end = link_end - 2;
58
+
59
+ while (new_end > 0 && isalpha(data[new_end]))
60
+ new_end--;
61
+
62
+ if (new_end < link_end - 2 && data[new_end] == '&')
63
+ link_end = new_end;
64
+ else
65
+ link_end--;
66
+ }
67
+
68
+ else if (data[link_end - 1] == '>') {
69
+ while (link_end > 0 && data[link_end] != '<')
70
+ link_end--;
71
+ }
72
+ else break;
73
+ }
74
+
75
+ if (link_end == 0)
76
+ return 0;
77
+
78
+ cclose = data[link_end - 1];
79
+
80
+ switch (cclose) {
81
+ case '"': copen = '"'; break;
82
+ case '\'': copen = '\''; break;
83
+ case ')': copen = '('; break;
84
+ case ']': copen = '['; break;
85
+ case '}': copen = '{'; break;
86
+ }
87
+
88
+ if (copen != 0) {
89
+ size_t closing = 0;
90
+ size_t opening = 0;
91
+ size_t i = 0;
92
+
93
+ /* Try to close the final punctuation sign in this same line;
94
+ * if we managed to close it outside of the URL, that means that it's
95
+ * not part of the URL. If it closes inside the URL, that means it
96
+ * is part of the URL.
97
+ *
98
+ * Examples:
99
+ *
100
+ * foo http://www.pokemon.com/Pikachu_(Electric) bar
101
+ * => http://www.pokemon.com/Pikachu_(Electric)
102
+ *
103
+ * foo (http://www.pokemon.com/Pikachu_(Electric)) bar
104
+ * => http://www.pokemon.com/Pikachu_(Electric)
105
+ *
106
+ * foo http://www.pokemon.com/Pikachu_(Electric)) bar
107
+ * => http://www.pokemon.com/Pikachu_(Electric))
108
+ *
109
+ * (foo http://www.pokemon.com/Pikachu_(Electric)) bar
110
+ * => foo http://www.pokemon.com/Pikachu_(Electric)
111
+ */
112
+
113
+ while (i < link_end) {
114
+ if (data[i] == copen)
115
+ opening++;
116
+ else if (data[i] == cclose)
117
+ closing++;
118
+
119
+ i++;
120
+ }
121
+
122
+ if (closing != opening)
123
+ link_end--;
124
+ }
125
+
126
+ return link_end;
127
+ }
128
+
129
+ size_t
130
+ ups_autolink__www(size_t *rewind_p, struct buf *link, char *data, size_t offset, size_t size)
131
+ {
132
+ size_t link_end;
133
+ int np = 0;
134
+
135
+ if (offset > 0 && !ispunct(data[-1]) && !isspace(data[-1]))
136
+ return 0;
137
+
138
+ if (size < 4 || memcmp(data, "www.", STRLEN("www.")) != 0)
139
+ return 0;
140
+
141
+ link_end = 0;
142
+ while (link_end < size && !isspace(data[link_end])) {
143
+ if (data[link_end] == '.')
144
+ np++;
145
+
146
+ link_end++;
147
+ }
148
+
149
+ if (np < 2)
150
+ return 0;
151
+
152
+ link_end = autolink_delim(data, link_end, offset, size);
153
+
154
+ if (link_end == 0)
155
+ return 0;
156
+
157
+ bufput(link, data, link_end);
158
+ *rewind_p = 0;
159
+
160
+ return (int)link_end;
161
+ }
162
+
163
+ size_t
164
+ ups_autolink__email(size_t *rewind_p, struct buf *link, char *data, size_t offset, size_t size)
165
+ {
166
+ size_t link_end, rewind;
167
+ int nb = 0, np = 0;
168
+
169
+ for (rewind = 0; rewind < offset; ++rewind) {
170
+ char c = data[-rewind - 1];
171
+
172
+ if (isalnum(c))
173
+ continue;
174
+
175
+ if (strchr(".+-_", c) != NULL)
176
+ continue;
177
+
178
+ break;
179
+ }
180
+
181
+ if (rewind == 0)
182
+ return 0;
183
+
184
+ for (link_end = 0; link_end < size; ++link_end) {
185
+ char c = data[link_end];
186
+
187
+ if (isalnum(c))
188
+ continue;
189
+
190
+ if (c == '@')
191
+ nb++;
192
+ else if (c == '.' && link_end < size - 1)
193
+ np++;
194
+ else if (c != '-' && c != '_')
195
+ break;
196
+ }
197
+
198
+ if (link_end < 2 || nb != 1 || np == 0)
199
+ return 0;
200
+
201
+ link_end = autolink_delim(data, link_end, offset, size);
202
+
203
+ if (link_end == 0)
204
+ return 0;
205
+
206
+ bufput(link, data - rewind, link_end + rewind);
207
+ *rewind_p = rewind;
208
+
209
+ return link_end;
210
+ }
211
+
212
+ size_t
213
+ ups_autolink__url(size_t *rewind_p, struct buf *link, char *data, size_t offset, size_t size)
214
+ {
215
+ size_t link_end, rewind = 0;
216
+
217
+ if (size < 4 || data[1] != '/' || data[2] != '/')
218
+ return 0;
219
+
220
+ while (rewind < offset && isalpha(data[-rewind - 1]))
221
+ rewind++;
222
+
223
+ if (!is_safe_link(data - rewind, size + rewind))
224
+ return 0;
225
+
226
+ link_end = 0;
227
+ while (link_end < size && !isspace(data[link_end]))
228
+ link_end++;
229
+
230
+ link_end = autolink_delim(data, link_end, offset, size);
231
+
232
+ if (link_end == 0)
233
+ return 0;
234
+
235
+ bufput(link, data - rewind, link_end + rewind);
236
+ *rewind_p = rewind;
237
+
238
+ return link_end;
239
+ }
240
+
@@ -45,9 +45,9 @@ put_scaped_char(struct buf *ob, char c)
45
45
  }
46
46
  }
47
47
 
48
- /* attr_escape • copy the buffer entity-escaping '<', '>', '&' and '"' */
49
- static void
50
- attr_escape(struct buf *ob, const char *src, size_t size)
48
+ /* upshtml_escape • copy the buffer entity-escaping '<', '>', '&' and '"' */
49
+ void
50
+ upshtml_escape(struct buf *ob, const char *src, size_t size)
51
51
  {
52
52
  size_t i = 0, org;
53
53
  while (i < size) {
@@ -127,9 +127,9 @@ rndr_autolink(struct buf *ob, struct buf *link, enum mkd_autolink type, void *op
127
127
  * want to print the `mailto:` prefix
128
128
  */
129
129
  if (bufprefix(link, "mailto:") == 0) {
130
- attr_escape(ob, link->data + 7, link->size - 7);
130
+ upshtml_escape(ob, link->data + 7, link->size - 7);
131
131
  } else {
132
- attr_escape(ob, link->data, link->size);
132
+ upshtml_escape(ob, link->data, link->size);
133
133
  }
134
134
 
135
135
  BUFPUTSL(ob, "</a>");
@@ -159,7 +159,7 @@ rndr_blockcode(struct buf *ob, struct buf *text, struct buf *lang, void *opaque)
159
159
  org++;
160
160
 
161
161
  if (cls) bufputc(ob, ' ');
162
- attr_escape(ob, lang->data + org, i - org);
162
+ upshtml_escape(ob, lang->data + org, i - org);
163
163
  }
164
164
  }
165
165
 
@@ -168,7 +168,7 @@ rndr_blockcode(struct buf *ob, struct buf *text, struct buf *lang, void *opaque)
168
168
  BUFPUTSL(ob, "<pre><code>");
169
169
 
170
170
  if (text)
171
- attr_escape(ob, text->data, text->size);
171
+ upshtml_escape(ob, text->data, text->size);
172
172
 
173
173
  BUFPUTSL(ob, "</code></pre>\n");
174
174
  }
@@ -204,16 +204,16 @@ rndr_blockcode_github(struct buf *ob, struct buf *text, struct buf *lang, void *
204
204
  i++;
205
205
 
206
206
  if (lang->data[0] == '.')
207
- attr_escape(ob, lang->data + 1, i - 1);
207
+ upshtml_escape(ob, lang->data + 1, i - 1);
208
208
  else
209
- attr_escape(ob, lang->data, i);
209
+ upshtml_escape(ob, lang->data, i);
210
210
 
211
211
  BUFPUTSL(ob, "\"><code>");
212
212
  } else
213
213
  BUFPUTSL(ob, "<pre><code>");
214
214
 
215
215
  if (text)
216
- attr_escape(ob, text->data, text->size);
216
+ upshtml_escape(ob, text->data, text->size);
217
217
 
218
218
  BUFPUTSL(ob, "</code></pre>\n");
219
219
  }
@@ -230,7 +230,7 @@ static int
230
230
  rndr_codespan(struct buf *ob, struct buf *text, void *opaque)
231
231
  {
232
232
  BUFPUTSL(ob, "<code>");
233
- if (text) attr_escape(ob, text->data, text->size);
233
+ if (text) upshtml_escape(ob, text->data, text->size);
234
234
  BUFPUTSL(ob, "</code>");
235
235
  return 1;
236
236
  }
@@ -299,7 +299,7 @@ rndr_link(struct buf *ob, struct buf *link, struct buf *title, struct buf *conte
299
299
  if (link && link->size) bufput(ob, link->data, link->size);
300
300
  if (title && title->size) {
301
301
  BUFPUTSL(ob, "\" title=\"");
302
- attr_escape(ob, title->data, title->size); }
302
+ upshtml_escape(ob, title->data, title->size); }
303
303
  BUFPUTSL(ob, "\">");
304
304
  if (content && content->size) bufput(ob, content->data, content->size);
305
305
  BUFPUTSL(ob, "</a>");
@@ -406,13 +406,13 @@ rndr_image(struct buf *ob, struct buf *link, struct buf *title, struct buf *alt,
406
406
  struct html_renderopt *options = opaque;
407
407
  if (!link || !link->size) return 0;
408
408
  BUFPUTSL(ob, "<img src=\"");
409
- attr_escape(ob, link->data, link->size);
409
+ upshtml_escape(ob, link->data, link->size);
410
410
  BUFPUTSL(ob, "\" alt=\"");
411
411
  if (alt && alt->size)
412
- attr_escape(ob, alt->data, alt->size);
412
+ upshtml_escape(ob, alt->data, alt->size);
413
413
  if (title && title->size) {
414
414
  BUFPUTSL(ob, "\" title=\"");
415
- attr_escape(ob, title->data, title->size); }
415
+ upshtml_escape(ob, title->data, title->size); }
416
416
 
417
417
  bufputc(ob, '"');
418
418
  bufputs(ob, options->close_tag);
@@ -503,7 +503,7 @@ static void
503
503
  rndr_normal_text(struct buf *ob, struct buf *text, void *opaque)
504
504
  {
505
505
  if (text)
506
- attr_escape(ob, text->data, text->size);
506
+ upshtml_escape(ob, text->data, text->size);
507
507
  }
508
508
 
509
509
  static void
@@ -18,6 +18,8 @@
18
18
  #define UPSKIRT_HTML_H
19
19
 
20
20
  #include "markdown.h"
21
+ #include "buffer.h"
22
+ #include <stdlib.h>
21
23
 
22
24
  typedef enum {
23
25
  HTML_SKIP_HTML = (1 << 0),
@@ -32,6 +34,15 @@ typedef enum {
32
34
  HTML_USE_XHTML = (1 << 11),
33
35
  } render_mode;
34
36
 
37
+ typedef enum {
38
+ AUTOLINK_URLS = (1 << 0),
39
+ AUTOLINK_EMAILS = (1 << 1),
40
+ AUTOLINK_ALL = AUTOLINK_URLS|AUTOLINK_EMAILS
41
+ } autolink_mode;
42
+
43
+ void
44
+ upshtml_escape(struct buf *ob, const char *src, size_t size);
45
+
35
46
  extern void
36
47
  upshtml_renderer(struct mkd_renderer *renderer, unsigned int render_flags);
37
48
 
@@ -44,5 +55,9 @@ upshtml_free_renderer(struct mkd_renderer *renderer);
44
55
  extern void
45
56
  upshtml_smartypants(struct buf *ob, struct buf *text);
46
57
 
58
+ extern void
59
+ upshtml_autolink(struct buf *ob, struct buf *text, unsigned int autolink_flags);
60
+
61
+
47
62
  #endif
48
63
 
@@ -0,0 +1,174 @@
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 "markdown.h"
18
+ #include "buffer.h"
19
+ #include "html.h"
20
+
21
+ #include <string.h>
22
+ #include <stdlib.h>
23
+ #include <stdio.h>
24
+ #include <ctype.h>
25
+
26
+ static inline int
27
+ is_closing_a(const char *tag, size_t size)
28
+ {
29
+ size_t i;
30
+
31
+ if (tag[0] != '<' || size < STRLEN("</a>") || tag[1] != '/')
32
+ return 0;
33
+
34
+ i = 2;
35
+
36
+ while (i < size && isspace(tag[i]))
37
+ i++;
38
+
39
+ if (i == size || tag[i] != 'a')
40
+ return 0;
41
+
42
+ i++;
43
+
44
+ while (i < size && isspace(tag[i]))
45
+ i++;
46
+
47
+ if (i == size || tag[i] != '>')
48
+ return 0;
49
+
50
+ return i;
51
+ }
52
+
53
+ static size_t
54
+ skip_tags(struct buf *ob, const char *text, size_t size)
55
+ {
56
+ size_t i = 0;
57
+
58
+ while (i < size && text[i] != '>')
59
+ i++;
60
+
61
+ if (size > 3 && text[1] == 'a' && isspace(text[2])) {
62
+ while (i < size) {
63
+ size_t tag_len = is_closing_a(text + i, size - i);
64
+ if (tag_len) {
65
+ i += tag_len;
66
+ break;
67
+ }
68
+ i++;
69
+ }
70
+ }
71
+
72
+ bufput(ob, text, i + 1);
73
+ return i + 1;
74
+ }
75
+
76
+ void
77
+ upshtml_autolink(struct buf *ob, struct buf *text, unsigned int flags)
78
+ {
79
+ size_t i, end;
80
+ struct buf *link = bufnew(16);
81
+ const char *active_chars;
82
+
83
+ if (!text || text->size == 0)
84
+ return;
85
+
86
+ switch (flags) {
87
+ case AUTOLINK_EMAILS:
88
+ active_chars = "<@";
89
+ break;
90
+
91
+ case AUTOLINK_URLS:
92
+ active_chars = "<w:";
93
+
94
+ case AUTOLINK_ALL:
95
+ active_chars = "<@w:";
96
+ break;
97
+
98
+ default:
99
+ return;
100
+ }
101
+
102
+ bufgrow(ob, text->size);
103
+
104
+ i = end = 0;
105
+
106
+ while (i < text->size) {
107
+ size_t rewind;
108
+
109
+ while (end < text->size && strchr(active_chars, text->data[end]) == NULL)
110
+ end++;
111
+
112
+ bufput(ob, text->data + i, end - i);
113
+
114
+ if (end >= text->size)
115
+ break;
116
+
117
+ i = end;
118
+ link->size = 0;
119
+
120
+ switch (text->data[i]) {
121
+ case '@':
122
+ end = ups_autolink__email(&rewind, link, text->data + i, i, text->size - i);
123
+ if (end > 0) {
124
+ ob->size -= rewind;
125
+ BUFPUTSL(ob, "<a href=\"mailto:");
126
+ bufput(ob, link->data, link->size);
127
+ BUFPUTSL(ob, "\">");
128
+ upshtml_escape(ob, link->data, link->size);
129
+ BUFPUTSL(ob, "</a>");
130
+ }
131
+ break;
132
+
133
+ case 'w':
134
+ end = ups_autolink__www(&rewind, link, text->data + i, i, text->size - i);
135
+ if (end > 0) {
136
+ BUFPUTSL(ob, "<a href=\"http://");
137
+ bufput(ob, link->data, link->size);
138
+ BUFPUTSL(ob, "\">");
139
+ upshtml_escape(ob, link->data, link->size);
140
+ BUFPUTSL(ob, "</a>");
141
+ }
142
+ break;
143
+
144
+ case ':':
145
+ end = ups_autolink__url(&rewind, link, text->data + i, i, text->size - i);
146
+ if (end > 0) {
147
+ ob->size -= rewind;
148
+ BUFPUTSL(ob, "<a href=\"");
149
+ bufput(ob, link->data, link->size);
150
+ BUFPUTSL(ob, "\">");
151
+ upshtml_escape(ob, link->data, link->size);
152
+ BUFPUTSL(ob, "</a>");
153
+ }
154
+ break;
155
+
156
+ case '<':
157
+ end = skip_tags(ob, text->data + i, text->size - i);
158
+ break;
159
+
160
+ default:
161
+ end = 0;
162
+ break;
163
+ }
164
+
165
+ if (!end)
166
+ end = i + 1;
167
+ else {
168
+ i += end;
169
+ end = i;
170
+ }
171
+ }
172
+ }
173
+
174
+
@@ -165,28 +165,6 @@ static struct html_tag block_tags[] = {
165
165
  /***************************
166
166
  * HELPER FUNCTIONS *
167
167
  ***************************/
168
- int
169
- is_safe_link(const char *link, size_t link_len)
170
- {
171
- static const size_t valid_uris_count = 4;
172
- static const char *valid_uris[] = {
173
- "http://", "https://", "ftp://", "mailto://"
174
- };
175
-
176
- size_t i;
177
-
178
- for (i = 0; i < valid_uris_count; ++i) {
179
- size_t len = strlen(valid_uris[i]);
180
-
181
- if (link_len > len &&
182
- strncasecmp(link, valid_uris[i], len) == 0 &&
183
- isalnum(link[len]))
184
- return 1;
185
- }
186
-
187
- return 0;
188
- }
189
-
190
168
  static void
191
169
  unscape_text(struct buf *ob, struct buf *src)
192
170
  {
@@ -730,237 +708,69 @@ char_langle_tag(struct buf *ob, struct render *rndr, char *data, size_t offset,
730
708
  else return end;
731
709
  }
732
710
 
733
- static size_t
734
- autolink_delim(char *data, size_t link_end, size_t offset, size_t size)
735
- {
736
- char cclose, copen = 0;
737
-
738
- /* See if the link finishes with a punctuation sign that can be skipped. */
739
- switch (data[link_end - 1]) {
740
- case '?':
741
- case '!':
742
- case '.':
743
- case ',':
744
- link_end--;
745
- break;
746
-
747
- case ';':
748
- {
749
- size_t new_end = link_end - 2;
750
-
751
- while (new_end > 0 && isalpha(data[new_end]))
752
- new_end--;
753
-
754
- if (new_end < link_end - 2 && data[new_end] == '&')
755
- link_end = new_end;
756
- else
757
- link_end--;
758
-
759
- break;
760
- }
761
-
762
- case '>':
763
- while (link_end > 0 && data[link_end] != '<')
764
- link_end--;
765
-
766
- if (link_end == 0)
767
- return 0;
768
-
769
- break;
770
- }
771
-
772
- cclose = data[link_end - 1];
773
-
774
- switch (cclose) {
775
- case '"': copen = '"'; break;
776
- case '\'': copen = '\''; break;
777
- case ')': copen = '('; break;
778
- case ']': copen = '['; break;
779
- case '}': copen = '{'; break;
780
- }
781
-
782
- if (copen != 0) {
783
- size_t closing = 0;
784
- size_t opening = 0;
785
- size_t i = 0;
786
-
787
- /* Try to close the final punctuation sign in this same line;
788
- * if we managed to close it outside of the URL, that means that it's
789
- * not part of the URL. If it closes inside the URL, that means it
790
- * is part of the URL.
791
- *
792
- * Examples:
793
- *
794
- * foo http://www.pokemon.com/Pikachu_(Electric) bar
795
- * => http://www.pokemon.com/Pikachu_(Electric)
796
- *
797
- * foo (http://www.pokemon.com/Pikachu_(Electric)) bar
798
- * => http://www.pokemon.com/Pikachu_(Electric)
799
- *
800
- * foo http://www.pokemon.com/Pikachu_(Electric)) bar
801
- * => http://www.pokemon.com/Pikachu_(Electric))
802
- *
803
- * (foo http://www.pokemon.com/Pikachu_(Electric)) bar
804
- * => foo http://www.pokemon.com/Pikachu_(Electric)
805
- */
806
-
807
- while (i < link_end) {
808
- if (data[i] == copen)
809
- opening++;
810
- else if (data[i] == cclose)
811
- closing++;
812
-
813
- i++;
814
- }
815
-
816
- if (closing != opening)
817
- link_end--;
818
- }
819
-
820
- return link_end;
821
- }
822
-
823
-
824
711
  static size_t
825
712
  char_autolink_www(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
826
713
  {
827
- struct buf work = { 0, 0, 0, 0, 0 };
828
- size_t link_end;
829
- int np = 0;
830
-
831
- if (offset > 0 && !ispunct(data[-1]) && !isspace(data[-1]))
832
- return 0;
833
-
834
- if (size < 4 || memcmp(data, "www.", STRLEN("www.")) != 0)
835
- return 0;
836
-
837
- link_end = 0;
838
- while (link_end < size && !isspace(data[link_end])) {
839
- if (data[link_end] == '.')
840
- np++;
841
-
842
- link_end++;
843
- }
714
+ struct buf *link, *link_url;
715
+ size_t link_len, rewind;
844
716
 
845
- if (np < 2)
717
+ if (!rndr->make.link)
846
718
  return 0;
847
719
 
848
- link_end = autolink_delim(data, link_end, offset, size);
720
+ link = rndr_newbuf(rndr, BUFFER_SPAN);
849
721
 
850
- if (link_end == 0)
851
- return 0;
852
-
853
- work.size = link_end;
854
- work.data = data;
855
-
856
- if (rndr->make.link) {
857
- struct buf *u_link = rndr_newbuf(rndr, BUFFER_SPAN);
858
- BUFPUTSL(u_link, "http://");
859
- unscape_text(u_link, &work);
722
+ if ((link_len = ups_autolink__www(&rewind, link, data, offset, size)) > 0) {
723
+ link_url = rndr_newbuf(rndr, BUFFER_SPAN);
724
+ BUFPUTSL(link_url, "http://");
725
+ bufput(link_url, link->data, link->size);
860
726
 
861
- rndr->make.link(ob, u_link, NULL, &work, rndr->make.opaque);
727
+ ob->size -= rewind;
728
+ rndr->make.link(ob, link_url, NULL, link, rndr->make.opaque);
862
729
  rndr_popbuf(rndr, BUFFER_SPAN);
863
730
  }
864
731
 
865
- return link_end;
732
+ rndr_popbuf(rndr, BUFFER_SPAN);
733
+ return link_len;
866
734
  }
867
735
 
868
736
  static size_t
869
737
  char_autolink_email(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
870
738
  {
871
- struct buf work = { 0, 0, 0, 0, 0 };
872
- size_t link_end, rewind;
873
- int nb = 0, np = 0;
874
-
875
- for (rewind = 0; rewind < offset; ++rewind) {
876
- char c = data[-rewind - 1];
877
-
878
- if (isalnum(c))
879
- continue;
880
-
881
- if (strchr(".+-_", c) != NULL)
882
- continue;
883
-
884
- break;
885
- }
886
-
887
- if (rewind == 0)
888
- return 0;
889
-
890
- for (link_end = 0; link_end < size; ++link_end) {
891
- char c = data[link_end];
892
-
893
- if (isalnum(c))
894
- continue;
895
-
896
- if (c == '@')
897
- nb++;
898
- else if (c == '.' && link_end < size - 1)
899
- np++;
900
- else if (c != '-' && c != '_')
901
- break;
902
- }
903
-
904
- if (link_end < 2 || nb != 1 || np == 0)
905
- return 0;
906
-
907
- link_end = autolink_delim(data, link_end, offset, size);
739
+ struct buf *link;
740
+ size_t link_len, rewind;
908
741
 
909
- if (link_end == 0)
742
+ if (!rndr->make.autolink)
910
743
  return 0;
911
744
 
912
- work.size = link_end + rewind;
913
- work.data = data - rewind;
914
-
915
- if (rndr->make.autolink) {
916
- struct buf *u_link = rndr_newbuf(rndr, BUFFER_SPAN);
917
- unscape_text(u_link, &work);
745
+ link = rndr_newbuf(rndr, BUFFER_SPAN);
918
746
 
747
+ if ((link_len = ups_autolink__email(&rewind, link, data, offset, size)) > 0) {
919
748
  ob->size -= rewind;
920
- rndr->make.autolink(ob, u_link, MKDA_EMAIL, rndr->make.opaque);
921
- rndr_popbuf(rndr, BUFFER_SPAN);
922
- }
749
+ rndr->make.autolink(ob, link, MKDA_EMAIL, rndr->make.opaque);
750
+ }
923
751
 
924
- return link_end;
752
+ rndr_popbuf(rndr, BUFFER_SPAN);
753
+ return link_len;
925
754
  }
926
755
 
927
756
  static size_t
928
757
  char_autolink_url(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
929
758
  {
930
- struct buf work = { 0, 0, 0, 0, 0 };
931
- size_t link_end, rewind = 0;
932
-
933
- if (size < 4 || data[1] != '/' || data[2] != '/')
934
- return 0;
935
-
936
- while (rewind < offset && isalpha(data[-rewind - 1]))
937
- rewind++;
938
-
939
- if (!is_safe_link(data - rewind, size + rewind))
940
- return 0;
941
-
942
- link_end = 0;
943
- while (link_end < size && !isspace(data[link_end]))
944
- link_end++;
945
-
946
- link_end = autolink_delim(data, link_end, offset, size);
759
+ struct buf *link;
760
+ size_t link_len, rewind;
947
761
 
948
- if (link_end == 0)
762
+ if (!rndr->make.autolink)
949
763
  return 0;
950
764
 
951
- work.size = link_end + rewind;
952
- work.data = data - rewind;
953
-
954
- if (rndr->make.autolink) {
955
- struct buf *u_link = rndr_newbuf(rndr, BUFFER_SPAN);
956
- unscape_text(u_link, &work);
765
+ link = rndr_newbuf(rndr, BUFFER_SPAN);
957
766
 
767
+ if ((link_len = ups_autolink__url(&rewind, link, data, offset, size)) > 0) {
958
768
  ob->size -= rewind;
959
- rndr->make.autolink(ob, u_link, MKDA_NORMAL, rndr->make.opaque);
960
- rndr_popbuf(rndr, BUFFER_SPAN);
769
+ rndr->make.autolink(ob, link, MKDA_NORMAL, rndr->make.opaque);
961
770
  }
962
771
 
963
- return link_end;
772
+ rndr_popbuf(rndr, BUFFER_SPAN);
773
+ return link_len;
964
774
  }
965
775
 
966
776
  /* char_link • '[': parsing a link or an image */
@@ -105,6 +105,15 @@ struct mkd_renderer {
105
105
  int
106
106
  is_safe_link(const char *link, size_t link_len);
107
107
 
108
+ size_t
109
+ ups_autolink__www(size_t *rewind_p, struct buf *link, char *data, size_t offset, size_t size);
110
+
111
+ size_t
112
+ ups_autolink__email(size_t *rewind_p, struct buf *link, char *data, size_t offset, size_t size);
113
+
114
+ size_t
115
+ ups_autolink__url(size_t *rewind_p, struct buf *link, char *data, size_t offset, size_t size);
116
+
108
117
  /**********************
109
118
  * EXPORTED FUNCTIONS *
110
119
  **********************/
@@ -79,6 +79,31 @@ static void rb_redcarpet__get_flags(VALUE ruby_obj,
79
79
  *render_flags_p = render_flags;
80
80
  }
81
81
 
82
+ static VALUE rb_redcarpet_autolink(VALUE self, VALUE text)
83
+ {
84
+ VALUE result;
85
+ struct buf input_buf, *output_buf;
86
+
87
+ memset(&input_buf, 0x0, sizeof(struct buf));
88
+ input_buf.data = RSTRING_PTR(text);
89
+ input_buf.size = RSTRING_LEN(text);
90
+
91
+ output_buf = bufnew(128);
92
+
93
+ upshtml_autolink(output_buf, &input_buf, AUTOLINK_ALL);
94
+ result = rb_str_new(output_buf->data, output_buf->size);
95
+
96
+ bufrelease(output_buf);
97
+
98
+ /* force the input encoding */
99
+ if (rb_respond_to(text, rb_intern("encoding"))) {
100
+ VALUE encoding = rb_funcall(text, rb_intern("encoding"), 0);
101
+ rb_funcall(result, rb_intern("force_encoding"), 1, encoding);
102
+ }
103
+
104
+ return result;
105
+ }
106
+
82
107
  static VALUE rb_redcarpet__render(VALUE self, RendererType render_type)
83
108
  {
84
109
  VALUE text = rb_funcall(self, rb_intern("text"), 0);
@@ -152,5 +177,7 @@ void Init_redcarpet()
152
177
  rb_cRedcarpet = rb_define_class("Redcarpet", rb_cObject);
153
178
  rb_define_method(rb_cRedcarpet, "to_html", rb_redcarpet_to_html, -1);
154
179
  rb_define_method(rb_cRedcarpet, "toc_content", rb_redcarpet_toc, -1);
180
+
181
+ rb_define_singleton_method(rb_cRedcarpet, "auto_link", rb_redcarpet_autolink, 1);
155
182
  }
156
183
 
@@ -26,7 +26,7 @@
26
26
  # end
27
27
  #
28
28
  class Redcarpet
29
- VERSION = '1.15.2'
29
+ VERSION = '1.16.0'
30
30
 
31
31
  # Original Markdown formatted text.
32
32
  attr_reader :text
@@ -1,9 +1,9 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'redcarpet'
3
- s.version = '1.15.2'
3
+ s.version = '1.16.0'
4
4
  s.summary = "Ruby bindings for libupskirt"
5
5
  s.description = 'A fast and safe Markdown to (X)HTML parser'
6
- s.date = '2011-06-02'
6
+ s.date = '2011-06-08'
7
7
  s.email = 'vicent@github.com'
8
8
  s.homepage = 'http://github.com/tanoku/redcarpet'
9
9
  s.authors = ["Natacha Porté", "Vicent Martí"]
@@ -15,11 +15,13 @@ Gem::Specification.new do |s|
15
15
  bin/redcarpet
16
16
  ext/redcarpet/array.c
17
17
  ext/redcarpet/array.h
18
+ ext/redcarpet/autolink.c
18
19
  ext/redcarpet/buffer.c
19
20
  ext/redcarpet/buffer.h
20
21
  ext/redcarpet/extconf.rb
21
22
  ext/redcarpet/html.c
22
23
  ext/redcarpet/html.h
24
+ ext/redcarpet/html_autolink.c
23
25
  ext/redcarpet/html_smartypants.c
24
26
  ext/redcarpet/markdown.c
25
27
  ext/redcarpet/markdown.h
@@ -27,10 +29,10 @@ Gem::Specification.new do |s|
27
29
  lib/markdown.rb
28
30
  lib/redcarpet.rb
29
31
  redcarpet.gemspec
32
+ test/autolink_test.rb
30
33
  test/benchmark.rb
31
34
  test/benchmark.txt
32
35
  test/markdown_test.rb
33
- test/rails_test.rb
34
36
  test/redcarpet_test.rb
35
37
  upskirt
36
38
  ]
@@ -6,17 +6,17 @@ require 'test/unit'
6
6
  require 'cgi'
7
7
  require 'redcarpet'
8
8
 
9
- class RedcarpetRailsTest < Test::Unit::TestCase
9
+ class RedcarpetAutolinkTest < Test::Unit::TestCase
10
10
  def assert_linked(expected, url)
11
- assert_equal "<p>#{expected}</p>", Redcarpet.new(url, :autolink).to_html.strip
11
+ assert_equal expected, Redcarpet.auto_link(url)
12
12
  end
13
13
 
14
- def test_auto_link_works
14
+ def test_autolink_works
15
15
  url = "http://example.com/"
16
16
  assert_linked "<a href=\"#{url}\">#{url}</a>", url
17
17
  end
18
18
 
19
- def test_does_not_autolink_www
19
+ def test_not_autolink_www
20
20
  assert_linked "Awww... man", "Awww... man"
21
21
  end
22
22
 
@@ -25,8 +25,8 @@ class RedcarpetRailsTest < Test::Unit::TestCase
25
25
  assert_linked "<a href=\"#{url}\">#{url}</a>", url
26
26
  end
27
27
 
28
- def test_does_not_include_gt
29
- url = "http://example.com/"
28
+ def test_does_not_include_trailing_gt
29
+ url = "http://example.com"
30
30
  assert_linked "&lt;<a href=\"#{url}\">#{url}</a>&gt;", "&lt;#{url}&gt;"
31
31
  end
32
32
 
@@ -60,60 +60,60 @@ class RedcarpetRailsTest < Test::Unit::TestCase
60
60
  end
61
61
  end
62
62
 
63
- def test_like_rails_rules
63
+ def test_links_like_autolink_rails
64
64
  email_raw = 'david@loudthinking.com'
65
65
  email_result = %{<a href="mailto:#{email_raw}">#{email_raw}</a>}
66
66
  email2_raw = '+david@loudthinking.com'
67
67
  email2_result = %{<a href="mailto:#{email2_raw}">#{email2_raw}</a>}
68
68
  link_raw = 'http://www.rubyonrails.com'
69
69
  link_result = %{<a href="#{link_raw}">#{link_raw}</a>}
70
- link_result_with_options = %{<a href="#{link_raw}" target="_blank">#{CGI.escapeHTML(link_raw)}</a>}
70
+ link_result_with_options = %{<a href="#{link_raw}" target="_blank">#{link_raw}</a>}
71
71
  link2_raw = 'www.rubyonrails.com'
72
- link2_result = %{<a href="http://#{link2_raw}">#{CGI.escapeHTML(link2_raw)}</a>}
72
+ link2_result = %{<a href="http://#{link2_raw}">#{link2_raw}</a>}
73
73
  link3_raw = 'http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281'
74
- link3_result = %{<a href="#{link3_raw}">#{CGI.escapeHTML(link3_raw)}</a>}
74
+ link3_result = %{<a href="#{link3_raw}">#{link3_raw}</a>}
75
75
  link4_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor123'
76
76
  link4_result = %{<a href="#{link4_raw}">#{CGI.escapeHTML(link4_raw)}</a>}
77
77
  link5_raw = 'http://foo.example.com:3000/controller/action'
78
- link5_result = %{<a href="#{link5_raw}">#{CGI.escapeHTML(link5_raw)}</a>}
78
+ link5_result = %{<a href="#{link5_raw}">#{link5_raw}</a>}
79
79
  link6_raw = 'http://foo.example.com:3000/controller/action+pack'
80
- link6_result = %{<a href="#{link6_raw}">#{CGI.escapeHTML(link6_raw)}</a>}
80
+ link6_result = %{<a href="#{link6_raw}">#{link6_raw}</a>}
81
81
  link7_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor-123'
82
82
  link7_result = %{<a href="#{link7_raw}">#{CGI.escapeHTML(link7_raw)}</a>}
83
83
  link8_raw = 'http://foo.example.com:3000/controller/action.html'
84
- link8_result = %{<a href="#{link8_raw}">#{CGI.escapeHTML(link8_raw)}</a>}
84
+ link8_result = %{<a href="#{link8_raw}">#{link8_raw}</a>}
85
85
  link9_raw = 'http://business.timesonline.co.uk/article/0,,9065-2473189,00.html'
86
- link9_result = %{<a href="#{link9_raw}">#{CGI.escapeHTML(link9_raw)}</a>}
86
+ link9_result = %{<a href="#{link9_raw}">#{link9_raw}</a>}
87
87
  link10_raw = 'http://www.mail-archive.com/ruby-talk@ruby-lang.org/'
88
- link10_result = %{<a href="#{link10_raw}">#{CGI.escapeHTML(link10_raw)}</a>}
88
+ link10_result = %{<a href="#{link10_raw}">#{link10_raw}</a>}
89
89
 
90
90
  assert_linked %(Go to #{link_result} and say hello to #{email_result}), "Go to #{link_raw} and say hello to #{email_raw}"
91
- assert_linked %(Link #{link_result}), "Link #{link_raw}"
92
- assert_linked %(#{link_result} Link), "#{link_raw} Link"
91
+ assert_linked %(<p>Link #{link_result}</p>), "<p>Link #{link_raw}</p>"
92
+ assert_linked %(<p>#{link_result} Link</p>), "<p>#{link_raw} Link</p>"
93
93
  assert_linked %(Go to #{link_result}.), %(Go to #{link_raw}.)
94
- assert_linked %(Go to #{link_result}, then say hello to #{email_result}.), %(Go to #{link_raw}, then say hello to #{email_raw}.)
95
- assert_linked %(Link #{link2_result}), "Link #{link2_raw}"
96
- assert_linked %(#{link2_result} Link), "#{link2_raw} Link"
94
+ assert_linked %(<p>Go to #{link_result}, then say hello to #{email_result}.</p>), %(<p>Go to #{link_raw}, then say hello to #{email_raw}.</p>)
95
+ assert_linked %(<p>Link #{link2_result}</p>), "<p>Link #{link2_raw}</p>"
96
+ assert_linked %(<p>#{link2_result} Link</p>), "<p>#{link2_raw} Link</p>"
97
97
  assert_linked %(Go to #{link2_result}.), %(Go to #{link2_raw}.)
98
- assert_linked %(Say hello to #{email_result}, then go to #{link2_result}.), %(Say hello to #{email_raw}, then go to #{link2_raw}.)
99
- assert_linked %(Link #{link3_result}), "Link #{link3_raw}"
100
- assert_linked %(#{link3_result} Link), "#{link3_raw} Link"
98
+ # assert_linked %(<p>Say hello to #{email_result}, then go to #{link2_result},</p>), %(<p>Say hello to #{email_raw}, then go to #{link2_raw},</p>)
99
+ assert_linked %(<p>Link #{link3_result}</p>), "<p>Link #{link3_raw}</p>"
100
+ assert_linked %(<p>#{link3_result} Link</p>), "<p>#{link3_raw} Link</p>"
101
101
  assert_linked %(Go to #{link3_result}.), %(Go to #{link3_raw}.)
102
- assert_linked %(Go to #{link3_result}. seriously, #{link3_result}? i think I'll say hello to #{email_result}. instead.), %(Go to #{link3_raw}. seriously, #{link3_raw}? i think I'll say hello to #{email_raw}. instead.)
103
- assert_linked %(Link #{link4_result}), "Link #{link4_raw}"
104
- assert_linked %(#{link4_result} Link), "#{link4_raw} Link"
105
- assert_linked %(#{link5_result} Link), "#{link5_raw} Link"
106
- assert_linked %(#{link6_result} Link), "#{link6_raw} Link"
107
- assert_linked %(#{link7_result} Link), "#{link7_raw} Link"
108
- assert_linked %(Link #{link8_result}), "Link #{link8_raw}"
109
- assert_linked %(#{link8_result} Link), "#{link8_raw} Link"
102
+ assert_linked %(<p>Go to #{link3_result}. seriously, #{link3_result}? i think I'll say hello to #{email_result}. instead.</p>), %(<p>Go to #{link3_raw}. seriously, #{link3_raw}? i think I'll say hello to #{email_raw}. instead.</p>)
103
+ assert_linked %(<p>Link #{link4_result}</p>), "<p>Link #{link4_raw}</p>"
104
+ assert_linked %(<p>#{link4_result} Link</p>), "<p>#{link4_raw} Link</p>"
105
+ assert_linked %(<p>#{link5_result} Link</p>), "<p>#{link5_raw} Link</p>"
106
+ assert_linked %(<p>#{link6_result} Link</p>), "<p>#{link6_raw} Link</p>"
107
+ assert_linked %(<p>#{link7_result} Link</p>), "<p>#{link7_raw} Link</p>"
108
+ assert_linked %(<p>Link #{link8_result}</p>), "<p>Link #{link8_raw}</p>"
109
+ assert_linked %(<p>#{link8_result} Link</p>), "<p>#{link8_raw} Link</p>"
110
110
  assert_linked %(Go to #{link8_result}.), %(Go to #{link8_raw}.)
111
- assert_linked %(Go to #{link8_result}. seriously, #{link8_result}? i think I'll say hello to #{email_result}. instead.), %(Go to #{link8_raw}. seriously, #{link8_raw}? i think I'll say hello to #{email_raw}. instead.)
112
- assert_linked %(Link #{link9_result}), "Link #{link9_raw}"
113
- #assert_linked %(#{link9_result} Link), "#{link9_raw} Link"
111
+ assert_linked %(<p>Go to #{link8_result}. seriously, #{link8_result}? i think I'll say hello to #{email_result}. instead.</p>), %(<p>Go to #{link8_raw}. seriously, #{link8_raw}? i think I'll say hello to #{email_raw}. instead.</p>)
112
+ assert_linked %(<p>Link #{link9_result}</p>), "<p>Link #{link9_raw}</p>"
113
+ assert_linked %(<p>#{link9_result} Link</p>), "<p>#{link9_raw} Link</p>"
114
114
  assert_linked %(Go to #{link9_result}.), %(Go to #{link9_raw}.)
115
- #assert_linked %(Go to #{link9_result}. seriously, #{link9_result}? i think I'll say hello to #{email_result}. instead.), %(Go to #{link9_raw}. seriously, #{link9_raw}? i think I'll say hello to #{email_raw}. instead.)
116
- #assert_linked %(#{link10_result} Link), "#{link10_raw} Link"
115
+ assert_linked %(<p>Go to #{link9_result}. seriously, #{link9_result}? i think I'll say hello to #{email_result}. instead.</p>), %(<p>Go to #{link9_raw}. seriously, #{link9_raw}? i think I'll say hello to #{email_raw}. instead.</p>)
116
+ assert_linked %(<p>#{link10_result} Link</p>), "<p>#{link10_raw} Link</p>"
117
117
  assert_linked email2_result, email2_raw
118
118
  assert_linked "#{link_result} #{link_result} #{link_result}", "#{link_raw} #{link_raw} #{link_raw}"
119
119
  assert_linked '<a href="http://www.rubyonrails.com">Ruby On Rails</a>', '<a href="http://www.rubyonrails.com">Ruby On Rails</a>'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redcarpet
3
3
  version: !ruby/object:Gem::Version
4
- hash: 47
4
+ hash: 87
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 15
9
- - 2
10
- version: 1.15.2
8
+ - 16
9
+ - 0
10
+ version: 1.16.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - "Natacha Port\xC3\xA9"
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-06-02 00:00:00 +02:00
19
+ date: 2011-06-08 00:00:00 +02:00
20
20
  default_executable:
21
21
  dependencies: []
22
22
 
@@ -35,11 +35,13 @@ files:
35
35
  - bin/redcarpet
36
36
  - ext/redcarpet/array.c
37
37
  - ext/redcarpet/array.h
38
+ - ext/redcarpet/autolink.c
38
39
  - ext/redcarpet/buffer.c
39
40
  - ext/redcarpet/buffer.h
40
41
  - ext/redcarpet/extconf.rb
41
42
  - ext/redcarpet/html.c
42
43
  - ext/redcarpet/html.h
44
+ - ext/redcarpet/html_autolink.c
43
45
  - ext/redcarpet/html_smartypants.c
44
46
  - ext/redcarpet/markdown.c
45
47
  - ext/redcarpet/markdown.h
@@ -47,10 +49,10 @@ files:
47
49
  - lib/markdown.rb
48
50
  - lib/redcarpet.rb
49
51
  - redcarpet.gemspec
52
+ - test/autolink_test.rb
50
53
  - test/benchmark.rb
51
54
  - test/benchmark.txt
52
55
  - test/markdown_test.rb
53
- - test/rails_test.rb
54
56
  - test/redcarpet_test.rb
55
57
  has_rdoc: true
56
58
  homepage: http://github.com/tanoku/redcarpet