github-markdown 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,87 @@
1
+ require 'date'
2
+ require 'rake/clean'
3
+ require 'rake/extensiontask'
4
+ require 'digest/md5'
5
+
6
+ task :default => :test
7
+
8
+ # ==========================================================
9
+ # Ruby Extension
10
+ # ==========================================================
11
+
12
+ Rake::ExtensionTask.new('markdown') do |ext|
13
+ ext.ext_dir = 'ext/markdown'
14
+ ext.lib_dir = 'lib/github'
15
+ end
16
+
17
+ # ==========================================================
18
+ # Testing
19
+ # ==========================================================
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new('test') do |t|
23
+ t.test_files = FileList['test/*_test.rb']
24
+ t.ruby_opts += ['-rubygems'] if defined? Gem
25
+ end
26
+ task 'test' => [:compile]
27
+
28
+ # PACKAGING =================================================================
29
+
30
+ require 'rubygems'
31
+ $spec = eval(File.read('github-markdown.gemspec'))
32
+
33
+ def package(ext='')
34
+ "pkg/github-markdown-#{$spec.version}" + ext
35
+ end
36
+
37
+ desc 'Build packages'
38
+ task :package => package('.gem')
39
+
40
+ directory 'pkg/'
41
+
42
+ file package('.gem') => %w[pkg/ github-markdown.gemspec] + $spec.files do |f|
43
+ sh "gem build github-markdown.gemspec"
44
+ mv File.basename(f.name), f.name
45
+ end
46
+
47
+ # GEMSPEC HELPERS ==========================================================
48
+
49
+ task :update_gem do
50
+ # read spec file and split out manifest section
51
+ GEMFILE = 'github-markdown.gemspec'
52
+ spec = File.read(GEMFILE)
53
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
54
+ head.sub!(/\.date = '.*'/, ".date = '#{Date.today.to_s}'")
55
+ # determine file list from git ls-files
56
+ files = `git ls-files`.
57
+ split("\n").
58
+ sort.
59
+ reject{ |file| file =~ /^\./ || file =~ /^test\/MarkdownTest/ }.
60
+ map{ |file| " #{file}" }.
61
+ join("\n")
62
+ # piece file back together and write...
63
+ manifest = " s.files = %w[\n#{files}\n ]\n"
64
+ spec = [head,manifest,tail].join(" # = MANIFEST =\n")
65
+ File.open(GEMFILE, 'w') { |io| io.write(spec) }
66
+ puts "updated #{GEMFILE}"
67
+ end
68
+
69
+ desc 'Gather required Sundown sources into extension directory'
70
+ task :gather => 'sundown/src/markdown.h' do |t|
71
+ files =
72
+ FileList[
73
+ 'sundown/src/{markdown,buffer,stack,autolink,html_blocks}.h',
74
+ 'sundown/src/{markdown,buffer,stack,autolink}.c',
75
+ 'sundown/html/{html,houdini_html_e,houdini_href_e}.c',
76
+ 'sundown/html/{html,houdini}.h',
77
+ ]
78
+ cp files, 'ext/markdown/',
79
+ :preserve => true,
80
+ :verbose => true
81
+ end
82
+
83
+ file 'sundown/src/markdown.h' do |t|
84
+ abort "The Sundown submodule is required."
85
+ end
86
+
87
+
data/bin/gfm ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ HELP = <<-help
4
+ Usage: gfm [--readme] [<file>]
5
+ Convert a GitHub-Flavored Markdown file to HTML and write to standard output.
6
+ With no <file> or when <file> is '-', read Markdown source text from standard input.
7
+ With `--readme`, the files are parsed like README.md files in GitHub.com. By default,
8
+ the files are parsed with all the GFM extensions.
9
+ help
10
+
11
+ if ARGV.include?('--help')
12
+ puts HELP
13
+ exit 0
14
+ end
15
+
16
+ root = File.expand_path('../../', __FILE__)
17
+ $:.unshift File.expand_path('lib', root)
18
+
19
+ require 'github/markdown'
20
+
21
+ mode = :gfm
22
+ if ARGV.delete('--readme')
23
+ mode = :markdown
24
+ end
25
+
26
+ STDOUT.write(GitHub::Markdown.to_html(ARGF.read, mode))
@@ -0,0 +1,264 @@
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 "buffer.h"
18
+
19
+ #include <string.h>
20
+ #include <stdlib.h>
21
+ #include <stdio.h>
22
+ #include <ctype.h>
23
+
24
+ #if defined(_WIN32)
25
+ #define strncasecmp _strnicmp
26
+ #endif
27
+
28
+ int
29
+ sd_autolink_issafe(const uint8_t *link, size_t link_len)
30
+ {
31
+ static const size_t valid_uris_count = 5;
32
+ static const char *valid_uris[] = {
33
+ "/", "http://", "https://", "ftp://", "mailto:"
34
+ };
35
+
36
+ size_t i;
37
+
38
+ for (i = 0; i < valid_uris_count; ++i) {
39
+ size_t len = strlen(valid_uris[i]);
40
+
41
+ if (link_len > len &&
42
+ strncasecmp((char *)link, valid_uris[i], len) == 0 &&
43
+ isalnum(link[len]))
44
+ return 1;
45
+ }
46
+
47
+ return 0;
48
+ }
49
+
50
+ static size_t
51
+ autolink_delim(uint8_t *data, size_t link_end, size_t offset, size_t size)
52
+ {
53
+ uint8_t cclose, copen = 0;
54
+ size_t i;
55
+
56
+ for (i = 0; i < link_end; ++i)
57
+ if (data[i] == '<') {
58
+ link_end = i;
59
+ break;
60
+ }
61
+
62
+ while (link_end > 0) {
63
+ if (strchr("?!.,", data[link_end - 1]) != NULL)
64
+ link_end--;
65
+
66
+ else if (data[link_end - 1] == ';') {
67
+ size_t new_end = link_end - 2;
68
+
69
+ while (new_end > 0 && isalpha(data[new_end]))
70
+ new_end--;
71
+
72
+ if (new_end < link_end - 2 && data[new_end] == '&')
73
+ link_end = new_end;
74
+ else
75
+ link_end--;
76
+ }
77
+ else break;
78
+ }
79
+
80
+ if (link_end == 0)
81
+ return 0;
82
+
83
+ cclose = data[link_end - 1];
84
+
85
+ switch (cclose) {
86
+ case '"': copen = '"'; break;
87
+ case '\'': copen = '\''; break;
88
+ case ')': copen = '('; break;
89
+ case ']': copen = '['; break;
90
+ case '}': copen = '{'; break;
91
+ }
92
+
93
+ if (copen != 0) {
94
+ size_t closing = 0;
95
+ size_t opening = 0;
96
+ size_t i = 0;
97
+
98
+ /* Try to close the final punctuation sign in this same line;
99
+ * if we managed to close it outside of the URL, that means that it's
100
+ * not part of the URL. If it closes inside the URL, that means it
101
+ * is part of the URL.
102
+ *
103
+ * Examples:
104
+ *
105
+ * foo http://www.pokemon.com/Pikachu_(Electric) bar
106
+ * => http://www.pokemon.com/Pikachu_(Electric)
107
+ *
108
+ * foo (http://www.pokemon.com/Pikachu_(Electric)) bar
109
+ * => http://www.pokemon.com/Pikachu_(Electric)
110
+ *
111
+ * foo http://www.pokemon.com/Pikachu_(Electric)) bar
112
+ * => http://www.pokemon.com/Pikachu_(Electric))
113
+ *
114
+ * (foo http://www.pokemon.com/Pikachu_(Electric)) bar
115
+ * => foo http://www.pokemon.com/Pikachu_(Electric)
116
+ */
117
+
118
+ while (i < link_end) {
119
+ if (data[i] == copen)
120
+ opening++;
121
+ else if (data[i] == cclose)
122
+ closing++;
123
+
124
+ i++;
125
+ }
126
+
127
+ if (closing != opening)
128
+ link_end--;
129
+ }
130
+
131
+ return link_end;
132
+ }
133
+
134
+ static size_t
135
+ check_domain(uint8_t *data, size_t size)
136
+ {
137
+ size_t i, np = 0;
138
+
139
+ if (!isalnum(data[0]))
140
+ return 0;
141
+
142
+ for (i = 1; i < size - 1; ++i) {
143
+ if (data[i] == '.') np++;
144
+ else if (!isalnum(data[i]) && data[i] != '-') break;
145
+ }
146
+
147
+ /* a valid domain needs to have at least a dot.
148
+ * that's as far as we get */
149
+ return np ? i : 0;
150
+ }
151
+
152
+ size_t
153
+ sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)
154
+ {
155
+ size_t link_end;
156
+
157
+ if (offset > 0 && !ispunct(data[-1]) && !isspace(data[-1]))
158
+ return 0;
159
+
160
+ if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0)
161
+ return 0;
162
+
163
+ link_end = check_domain(data, size);
164
+
165
+ if (link_end == 0)
166
+ return 0;
167
+
168
+ while (link_end < size && !isspace(data[link_end]))
169
+ link_end++;
170
+
171
+ link_end = autolink_delim(data, link_end, offset, size);
172
+
173
+ if (link_end == 0)
174
+ return 0;
175
+
176
+ bufput(link, data, link_end);
177
+ *rewind_p = 0;
178
+
179
+ return (int)link_end;
180
+ }
181
+
182
+ size_t
183
+ sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)
184
+ {
185
+ size_t link_end, rewind;
186
+ int nb = 0, np = 0;
187
+
188
+ for (rewind = 0; rewind < offset; ++rewind) {
189
+ uint8_t c = data[-rewind - 1];
190
+
191
+ if (isalnum(c))
192
+ continue;
193
+
194
+ if (strchr(".+-_", c) != NULL)
195
+ continue;
196
+
197
+ break;
198
+ }
199
+
200
+ if (rewind == 0)
201
+ return 0;
202
+
203
+ for (link_end = 0; link_end < size; ++link_end) {
204
+ uint8_t c = data[link_end];
205
+
206
+ if (isalnum(c))
207
+ continue;
208
+
209
+ if (c == '@')
210
+ nb++;
211
+ else if (c == '.' && link_end < size - 1)
212
+ np++;
213
+ else if (c != '-' && c != '_')
214
+ break;
215
+ }
216
+
217
+ if (link_end < 2 || nb != 1 || np == 0)
218
+ return 0;
219
+
220
+ link_end = autolink_delim(data, link_end, offset, size);
221
+
222
+ if (link_end == 0)
223
+ return 0;
224
+
225
+ bufput(link, data - rewind, link_end + rewind);
226
+ *rewind_p = rewind;
227
+
228
+ return link_end;
229
+ }
230
+
231
+ size_t
232
+ sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)
233
+ {
234
+ size_t link_end, rewind = 0, domain_len;
235
+
236
+ if (size < 4 || data[1] != '/' || data[2] != '/')
237
+ return 0;
238
+
239
+ while (rewind < offset && isalpha(data[-rewind - 1]))
240
+ rewind++;
241
+
242
+ if (!sd_autolink_issafe(data - rewind, size + rewind))
243
+ return 0;
244
+ link_end = strlen("://");
245
+
246
+ domain_len = check_domain(data + link_end, size - link_end);
247
+ if (domain_len == 0)
248
+ return 0;
249
+
250
+ link_end += domain_len;
251
+ while (link_end < size && !isspace(data[link_end]))
252
+ link_end++;
253
+
254
+ link_end = autolink_delim(data, link_end, offset, size);
255
+
256
+ if (link_end == 0)
257
+ return 0;
258
+
259
+ bufput(link, data - rewind, link_end + rewind);
260
+ *rewind_p = rewind;
261
+
262
+ return link_end;
263
+ }
264
+
@@ -0,0 +1,36 @@
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
+ #ifndef UPSKIRT_AUTOLINK_H
18
+ #define UPSKIRT_AUTOLINK_H
19
+
20
+ #include "buffer.h"
21
+
22
+ extern int
23
+ sd_autolink_issafe(const uint8_t *link, size_t link_len);
24
+
25
+ extern size_t
26
+ sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);
27
+
28
+ extern size_t
29
+ sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);
30
+
31
+ extern size_t
32
+ sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);
33
+
34
+ #endif
35
+
36
+ /* vim: set filetype=c: */
@@ -0,0 +1,223 @@
1
+ /*
2
+ * Copyright (c) 2008, Natacha Porté
3
+ * Copyright (c) 2011, Vicent Martí
4
+ *
5
+ * Permission to use, copy, modify, and distribute this software for any
6
+ * purpose with or without fee is hereby granted, provided that the above
7
+ * copyright notice and this permission notice appear in all copies.
8
+ *
9
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ */
17
+
18
+ #define BUFFER_MAX_ALLOC_SIZE (1024 * 1024 * 16) //16mb
19
+
20
+ #include "buffer.h"
21
+
22
+ #include <stdio.h>
23
+ #include <stdlib.h>
24
+ #include <string.h>
25
+ #include <assert.h>
26
+
27
+ /* MSVC compat */
28
+ #if defined(_MSC_VER)
29
+ # define _buf_vsnprintf _vsnprintf
30
+ #else
31
+ # define _buf_vsnprintf vsnprintf
32
+ #endif
33
+
34
+ int
35
+ bufprefix(const struct buf *buf, const char *prefix)
36
+ {
37
+ size_t i;
38
+ assert(buf && buf->unit);
39
+
40
+ for (i = 0; i < buf->size; ++i) {
41
+ if (prefix[i] == 0)
42
+ return 0;
43
+
44
+ if (buf->data[i] != prefix[i])
45
+ return buf->data[i] - prefix[i];
46
+ }
47
+
48
+ return 0;
49
+ }
50
+
51
+ /* bufgrow: increasing the allocated size to the given value */
52
+ int
53
+ bufgrow(struct buf *buf, size_t neosz)
54
+ {
55
+ size_t neoasz;
56
+ void *neodata;
57
+
58
+ assert(buf && buf->unit);
59
+
60
+ if (neosz > BUFFER_MAX_ALLOC_SIZE)
61
+ return BUF_ENOMEM;
62
+
63
+ if (buf->asize >= neosz)
64
+ return BUF_OK;
65
+
66
+ neoasz = buf->asize + buf->unit;
67
+ while (neoasz < neosz)
68
+ neoasz += buf->unit;
69
+
70
+ neodata = realloc(buf->data, neoasz);
71
+ if (!neodata)
72
+ return BUF_ENOMEM;
73
+
74
+ buf->data = neodata;
75
+ buf->asize = neoasz;
76
+ return BUF_OK;
77
+ }
78
+
79
+
80
+ /* bufnew: allocation of a new buffer */
81
+ struct buf *
82
+ bufnew(size_t unit)
83
+ {
84
+ struct buf *ret;
85
+ ret = malloc(sizeof (struct buf));
86
+
87
+ if (ret) {
88
+ ret->data = 0;
89
+ ret->size = ret->asize = 0;
90
+ ret->unit = unit;
91
+ }
92
+ return ret;
93
+ }
94
+
95
+ /* bufnullterm: NULL-termination of the string array */
96
+ const char *
97
+ bufcstr(struct buf *buf)
98
+ {
99
+ assert(buf && buf->unit);
100
+
101
+ if (buf->size < buf->asize && buf->data[buf->size] == 0)
102
+ return (char *)buf->data;
103
+
104
+ if (buf->size + 1 <= buf->asize || bufgrow(buf, buf->size + 1) == 0) {
105
+ buf->data[buf->size] = 0;
106
+ return (char *)buf->data;
107
+ }
108
+
109
+ return NULL;
110
+ }
111
+
112
+ /* bufprintf: formatted printing to a buffer */
113
+ void
114
+ bufprintf(struct buf *buf, const char *fmt, ...)
115
+ {
116
+ va_list ap;
117
+ int n;
118
+
119
+ assert(buf && buf->unit);
120
+
121
+ if (buf->size >= buf->asize && bufgrow(buf, buf->size + 1) < 0)
122
+ return;
123
+
124
+ va_start(ap, fmt);
125
+ n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
126
+ va_end(ap);
127
+
128
+ if (n < 0) {
129
+ #ifdef _MSC_VER
130
+ n = _vscprintf(fmt, ap);
131
+ #else
132
+ return;
133
+ #endif
134
+ }
135
+
136
+ if ((size_t)n >= buf->asize - buf->size) {
137
+ if (bufgrow(buf, buf->size + n + 1) < 0)
138
+ return;
139
+
140
+ va_start(ap, fmt);
141
+ n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
142
+ va_end(ap);
143
+ }
144
+
145
+ if (n < 0)
146
+ return;
147
+
148
+ buf->size += n;
149
+ }
150
+
151
+ /* bufput: appends raw data to a buffer */
152
+ void
153
+ bufput(struct buf *buf, const void *data, size_t len)
154
+ {
155
+ assert(buf && buf->unit);
156
+
157
+ if (buf->size + len > buf->asize && bufgrow(buf, buf->size + len) < 0)
158
+ return;
159
+
160
+ memcpy(buf->data + buf->size, data, len);
161
+ buf->size += len;
162
+ }
163
+
164
+ /* bufputs: appends a NUL-terminated string to a buffer */
165
+ void
166
+ bufputs(struct buf *buf, const char *str)
167
+ {
168
+ bufput(buf, str, strlen(str));
169
+ }
170
+
171
+
172
+ /* bufputc: appends a single uint8_t to a buffer */
173
+ void
174
+ bufputc(struct buf *buf, int c)
175
+ {
176
+ assert(buf && buf->unit);
177
+
178
+ if (buf->size + 1 > buf->asize && bufgrow(buf, buf->size + 1) < 0)
179
+ return;
180
+
181
+ buf->data[buf->size] = c;
182
+ buf->size += 1;
183
+ }
184
+
185
+ /* bufrelease: decrease the reference count and free the buffer if needed */
186
+ void
187
+ bufrelease(struct buf *buf)
188
+ {
189
+ if (!buf)
190
+ return;
191
+
192
+ free(buf->data);
193
+ free(buf);
194
+ }
195
+
196
+
197
+ /* bufreset: frees internal data of the buffer */
198
+ void
199
+ bufreset(struct buf *buf)
200
+ {
201
+ if (!buf)
202
+ return;
203
+
204
+ free(buf->data);
205
+ buf->data = NULL;
206
+ buf->size = buf->asize = 0;
207
+ }
208
+
209
+ /* bufslurp: removes a given number of bytes from the head of the array */
210
+ void
211
+ bufslurp(struct buf *buf, size_t len)
212
+ {
213
+ assert(buf && buf->unit);
214
+
215
+ if (len >= buf->size) {
216
+ buf->size = 0;
217
+ return;
218
+ }
219
+
220
+ buf->size -= len;
221
+ memmove(buf->data, buf->data + len, buf->size);
222
+ }
223
+