rdiscount 1.5.8.1 → 1.6.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/ext/basename.c +43 -0
- data/ext/emmatch.c +188 -0
- data/ext/generate.c +172 -237
- data/ext/markdown.c +34 -20
- data/ext/markdown.h +13 -2
- data/ext/mkdio.c +40 -8
- data/ext/mkdio.h +10 -0
- data/lib/rdiscount.rb +1 -1
- data/rdiscount.gemspec +3 -1
- data/test/markdown_test.rb +1 -1
- metadata +5 -4
data/Rakefile
CHANGED
@@ -100,7 +100,7 @@ task :gather => 'discount' do |t|
|
|
100
100
|
files =
|
101
101
|
FileList[
|
102
102
|
'discount/{markdown,mkdio,amalloc,cstring}.h',
|
103
|
-
'discount/{markdown,docheader,dumptree,generate,mkdio,resource,toc,Csio,xml,css}.c'
|
103
|
+
'discount/{markdown,docheader,dumptree,generate,mkdio,resource,toc,Csio,xml,css,basename,emmatch}.c'
|
104
104
|
]
|
105
105
|
cp files, 'ext/',
|
106
106
|
:preserve => true,
|
data/ext/basename.c
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
/*
|
2
|
+
* mkdio -- markdown front end input functions
|
3
|
+
*
|
4
|
+
* Copyright (C) 2007 David L Parsons.
|
5
|
+
* The redistribution terms are provided in the COPYRIGHT file that must
|
6
|
+
* be distributed with this source code.
|
7
|
+
*/
|
8
|
+
#include "config.h"
|
9
|
+
#include <stdio.h>
|
10
|
+
#include <stdlib.h>
|
11
|
+
#include <ctype.h>
|
12
|
+
|
13
|
+
#include "mkdio.h"
|
14
|
+
#include "cstring.h"
|
15
|
+
#include "amalloc.h"
|
16
|
+
|
17
|
+
static char *
|
18
|
+
e_basename(const char *string, const int size, void *context)
|
19
|
+
{
|
20
|
+
char *ret;
|
21
|
+
char *base = (char*)context;
|
22
|
+
|
23
|
+
if ( base && string && (*string == '/') && (ret=malloc(strlen(base)+size+2)) ) {
|
24
|
+
strcpy(ret, base);
|
25
|
+
strncat(ret, string, size);
|
26
|
+
return ret;
|
27
|
+
}
|
28
|
+
return 0;
|
29
|
+
}
|
30
|
+
|
31
|
+
static void
|
32
|
+
e_free(char *string, void *context)
|
33
|
+
{
|
34
|
+
if ( string ) free(string);
|
35
|
+
}
|
36
|
+
|
37
|
+
void
|
38
|
+
mkd_basename(MMIOT *document, char *base)
|
39
|
+
{
|
40
|
+
mkd_e_url(document, e_basename);
|
41
|
+
mkd_e_data(document, base);
|
42
|
+
mkd_e_free(document, e_free);
|
43
|
+
}
|
data/ext/emmatch.c
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
/* markdown: a C implementation of John Gruber's Markdown markup language.
|
2
|
+
*
|
3
|
+
* Copyright (C) 2010 David L Parsons.
|
4
|
+
* The redistribution terms are provided in the COPYRIGHT file that must
|
5
|
+
* be distributed with this source code.
|
6
|
+
*/
|
7
|
+
#include <stdio.h>
|
8
|
+
#include <string.h>
|
9
|
+
#include <stdarg.h>
|
10
|
+
#include <stdlib.h>
|
11
|
+
#include <time.h>
|
12
|
+
#include <ctype.h>
|
13
|
+
|
14
|
+
#include "config.h"
|
15
|
+
|
16
|
+
#include "cstring.h"
|
17
|
+
#include "markdown.h"
|
18
|
+
#include "amalloc.h"
|
19
|
+
|
20
|
+
|
21
|
+
/* emmatch: the emphasis mangler that's run after a block
|
22
|
+
* of html has been generated.
|
23
|
+
*
|
24
|
+
* It should create MarkdownTest_1.0 (and _1.0.3)
|
25
|
+
* compatable emphasis for non-pathological cases
|
26
|
+
* and it should fail in a standards-compliant way
|
27
|
+
* when someone attempts to feed it junk.
|
28
|
+
*
|
29
|
+
* Emmatching is done after the input has been
|
30
|
+
* processed into a STRING (f->Q) of text and
|
31
|
+
* emphasis blocks. After ___mkd_emblock() finishes,
|
32
|
+
* it truncates f->Q and leaves the rendered paragraph
|
33
|
+
* if f->out.
|
34
|
+
*/
|
35
|
+
|
36
|
+
|
37
|
+
/* empair() -- find the NEAREST matching emphasis token (or
|
38
|
+
* subtoken of a 3+ long emphasis token.
|
39
|
+
*/
|
40
|
+
static int
|
41
|
+
empair(MMIOT *f, int first, int last, int match)
|
42
|
+
{
|
43
|
+
|
44
|
+
int i;
|
45
|
+
block *begin, *p;
|
46
|
+
|
47
|
+
begin = &T(f->Q)[first];
|
48
|
+
|
49
|
+
for (i=first+1; i <= last; i++) {
|
50
|
+
p = &T(f->Q)[i];
|
51
|
+
|
52
|
+
if ( (p->b_type != bTEXT) && (p->b_count <= 0) )
|
53
|
+
continue; /* break? */
|
54
|
+
|
55
|
+
if ( p->b_type == begin->b_type ) {
|
56
|
+
if ( p->b_count == match ) /* exact match */
|
57
|
+
return i;
|
58
|
+
|
59
|
+
if ( p->b_count > 2 ) /* fuzzy match */
|
60
|
+
return i;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
return 0;
|
64
|
+
} /* empair */
|
65
|
+
|
66
|
+
|
67
|
+
/* emfill() -- if an emphasis token has leftover stars or underscores,
|
68
|
+
* convert them back into character and append them to b_text.
|
69
|
+
*/
|
70
|
+
static void
|
71
|
+
emfill(block *p)
|
72
|
+
{
|
73
|
+
int j;
|
74
|
+
|
75
|
+
if ( p->b_type == bTEXT )
|
76
|
+
return;
|
77
|
+
|
78
|
+
for (j=0; j < p->b_count; j++)
|
79
|
+
EXPAND(p->b_text) = p->b_char;
|
80
|
+
p->b_count = 0;
|
81
|
+
} /* emfill */
|
82
|
+
|
83
|
+
|
84
|
+
static void
|
85
|
+
emclose(MMIOT *f, int first, int last)
|
86
|
+
{
|
87
|
+
int j;
|
88
|
+
|
89
|
+
for (j=first+1; j<last-1; j++)
|
90
|
+
emfill(&T(f->Q)[j]);
|
91
|
+
}
|
92
|
+
|
93
|
+
|
94
|
+
static struct emtags {
|
95
|
+
char open[10];
|
96
|
+
char close[10];
|
97
|
+
int size;
|
98
|
+
} emtags[] = { { "<em>" , "</em>", 5 }, { "<strong>", "</strong>", 9 } };
|
99
|
+
|
100
|
+
|
101
|
+
static void emblock(MMIOT*,int,int);
|
102
|
+
|
103
|
+
|
104
|
+
/* emmatch() -- match emphasis for a single emphasis token.
|
105
|
+
*/
|
106
|
+
static void
|
107
|
+
emmatch(MMIOT *f, int first, int last)
|
108
|
+
{
|
109
|
+
block *start = &T(f->Q)[first];
|
110
|
+
int e, e2, match;
|
111
|
+
|
112
|
+
switch (start->b_count) {
|
113
|
+
case 2: if ( e = empair(f,first,last,match=2) )
|
114
|
+
break;
|
115
|
+
case 1: e = empair(f,first,last,match=1);
|
116
|
+
break;
|
117
|
+
case 0: return;
|
118
|
+
default:
|
119
|
+
e = empair(f,first,last,1);
|
120
|
+
e2= empair(f,first,last,2);
|
121
|
+
|
122
|
+
if ( e2 >= e ) {
|
123
|
+
e = e2;
|
124
|
+
match = 2;
|
125
|
+
}
|
126
|
+
else
|
127
|
+
match = 1;
|
128
|
+
break;
|
129
|
+
}
|
130
|
+
|
131
|
+
if ( e ) {
|
132
|
+
/* if we found emphasis to match, match it, recursively call
|
133
|
+
* emblock to match emphasis inside the new html block, add
|
134
|
+
* the emphasis markers for the block, then (tail) recursively
|
135
|
+
* call ourself to match any remaining emphasis on this token.
|
136
|
+
*/
|
137
|
+
block *end = &T(f->Q)[e];
|
138
|
+
|
139
|
+
end->b_count -= match;
|
140
|
+
start->b_count -= match;
|
141
|
+
|
142
|
+
emblock(f, first, e);
|
143
|
+
|
144
|
+
PREFIX(start->b_text, emtags[match-1].open, emtags[match-1].size-1);
|
145
|
+
SUFFIX(end->b_post, emtags[match-1].close, emtags[match-1].size);
|
146
|
+
|
147
|
+
emmatch(f, first, last);
|
148
|
+
}
|
149
|
+
} /* emmatch */
|
150
|
+
|
151
|
+
|
152
|
+
/* emblock() -- walk a blocklist, attempting to match emphasis
|
153
|
+
*/
|
154
|
+
static void
|
155
|
+
emblock(MMIOT *f, int first, int last)
|
156
|
+
{
|
157
|
+
int i;
|
158
|
+
|
159
|
+
for ( i = first; i <= last; i++ )
|
160
|
+
if ( T(f->Q)[i].b_type != bTEXT )
|
161
|
+
emmatch(f, i, last);
|
162
|
+
emclose(f, first, last);
|
163
|
+
} /* emblock */
|
164
|
+
|
165
|
+
|
166
|
+
/* ___mkd_emblock() -- emblock a string of blocks, then concatinate the
|
167
|
+
* resulting text onto f->out.
|
168
|
+
*/
|
169
|
+
void
|
170
|
+
___mkd_emblock(MMIOT *f)
|
171
|
+
{
|
172
|
+
int i;
|
173
|
+
block *p;
|
174
|
+
|
175
|
+
emblock(f, 0, S(f->Q)-1);
|
176
|
+
|
177
|
+
for (i=0; i < S(f->Q); i++) {
|
178
|
+
p = &T(f->Q)[i];
|
179
|
+
emfill(p);
|
180
|
+
|
181
|
+
if ( S(p->b_post) ) { SUFFIX(f->out, T(p->b_post), S(p->b_post));
|
182
|
+
DELETE(p->b_post); }
|
183
|
+
if ( S(p->b_text) ) { SUFFIX(f->out, T(p->b_text), S(p->b_text));
|
184
|
+
DELETE(p->b_text); }
|
185
|
+
}
|
186
|
+
|
187
|
+
S(f->Q) = 0;
|
188
|
+
} /* ___mkd_emblock */
|
data/ext/generate.c
CHANGED
@@ -21,8 +21,6 @@ typedef int (*stfu)(const void*,const void*);
|
|
21
21
|
|
22
22
|
|
23
23
|
/* forward declarations */
|
24
|
-
static int iscodeblock(MMIOT*);
|
25
|
-
static void code(int, MMIOT*);
|
26
24
|
static void text(MMIOT *f);
|
27
25
|
static Paragraph *display(Paragraph*, MMIOT*);
|
28
26
|
|
@@ -166,6 +164,16 @@ Qprintf(MMIOT *f, char *fmt, ...)
|
|
166
164
|
}
|
167
165
|
|
168
166
|
|
167
|
+
/* Qcopy()
|
168
|
+
*/
|
169
|
+
static void
|
170
|
+
Qcopy(int count, MMIOT *f)
|
171
|
+
{
|
172
|
+
while ( count-- > 0 )
|
173
|
+
Qchar(pull(f), f);
|
174
|
+
}
|
175
|
+
|
176
|
+
|
169
177
|
/* Qem()
|
170
178
|
*/
|
171
179
|
static void
|
@@ -182,118 +190,6 @@ Qem(MMIOT *f, char c, int count)
|
|
182
190
|
}
|
183
191
|
|
184
192
|
|
185
|
-
/* empair()
|
186
|
-
*/
|
187
|
-
static int
|
188
|
-
empair(MMIOT *f, int go, int level)
|
189
|
-
{
|
190
|
-
|
191
|
-
int i;
|
192
|
-
block *begin, *p;
|
193
|
-
|
194
|
-
begin = &T(f->Q)[go];
|
195
|
-
for (i=go+1; i < S(f->Q); i++) {
|
196
|
-
p = &T(f->Q)[i];
|
197
|
-
|
198
|
-
if ( (p->b_type != bTEXT) && (p->b_count <= 0) )
|
199
|
-
break;
|
200
|
-
|
201
|
-
if ( p->b_type == begin->b_type ) {
|
202
|
-
if ( p->b_count == level ) /* exact match */
|
203
|
-
return i-go;
|
204
|
-
|
205
|
-
if ( p->b_count > 2 ) /* fuzzy match */
|
206
|
-
return i-go;
|
207
|
-
}
|
208
|
-
}
|
209
|
-
return EOF;
|
210
|
-
}
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
static struct emtags {
|
215
|
-
char open[10];
|
216
|
-
char close[10];
|
217
|
-
int size;
|
218
|
-
} emtags[] = { { "<em>" , "</em>", 5 }, { "<strong>", "</strong>", 9 } };
|
219
|
-
|
220
|
-
|
221
|
-
static void
|
222
|
-
emclose(Cstring *s, int level)
|
223
|
-
{
|
224
|
-
PREFIX(*s, emtags[level-1].close, emtags[level-1].size);
|
225
|
-
}
|
226
|
-
|
227
|
-
|
228
|
-
static void
|
229
|
-
emopen(Cstring *s, int level)
|
230
|
-
{
|
231
|
-
SUFFIX(*s, emtags[level-1].open, emtags[level-1].size-1);
|
232
|
-
}
|
233
|
-
|
234
|
-
|
235
|
-
/* emmatch()
|
236
|
-
*/
|
237
|
-
static void
|
238
|
-
emmatch(MMIOT *f, int go)
|
239
|
-
{
|
240
|
-
block *start = &T(f->Q)[go], *end;
|
241
|
-
int e, e2, i, match;
|
242
|
-
|
243
|
-
while ( start->b_count ) {
|
244
|
-
switch (start->b_count) {
|
245
|
-
case 2: e = empair(f,go,match=2);
|
246
|
-
if ( e != EOF ) break;
|
247
|
-
case 1: e = empair(f,go,match=1); break;
|
248
|
-
default:
|
249
|
-
e = empair(f,go,1);
|
250
|
-
e2= empair(f,go,2);
|
251
|
-
|
252
|
-
if ( e == EOF || ((e2 != EOF) && (e2 >= e)) ) {
|
253
|
-
e = e2;
|
254
|
-
match = 2;
|
255
|
-
}
|
256
|
-
else
|
257
|
-
match = 1;
|
258
|
-
}
|
259
|
-
if ( e != EOF ) {
|
260
|
-
end = &T(f->Q)[go+e];
|
261
|
-
emclose(&end->b_post, match);
|
262
|
-
emopen(&start->b_text, match);
|
263
|
-
end->b_count -= match;
|
264
|
-
}
|
265
|
-
else {
|
266
|
-
for (i=0; i < match; i++)
|
267
|
-
EXPAND(start->b_text) = start->b_char;
|
268
|
-
}
|
269
|
-
|
270
|
-
start->b_count -= match;
|
271
|
-
}
|
272
|
-
}
|
273
|
-
|
274
|
-
|
275
|
-
/* ___mkd_emblock()
|
276
|
-
*/
|
277
|
-
void
|
278
|
-
___mkd_emblock(MMIOT *f)
|
279
|
-
{
|
280
|
-
int i;
|
281
|
-
block *p;
|
282
|
-
|
283
|
-
for (i=0; i < S(f->Q); i++) {
|
284
|
-
p = &T(f->Q)[i];
|
285
|
-
|
286
|
-
if ( p->b_type != bTEXT ) emmatch(f, i);
|
287
|
-
|
288
|
-
if ( S(p->b_post) ) { SUFFIX(f->out, T(p->b_post), S(p->b_post));
|
289
|
-
DELETE(p->b_post); }
|
290
|
-
if ( S(p->b_text) ) { SUFFIX(f->out, T(p->b_text), S(p->b_text));
|
291
|
-
DELETE(p->b_text); }
|
292
|
-
}
|
293
|
-
S(f->Q) = 0;
|
294
|
-
}
|
295
|
-
|
296
|
-
|
297
193
|
/* generate html from a markup fragment
|
298
194
|
*/
|
299
195
|
void
|
@@ -304,7 +200,7 @@ ___mkd_reparse(char *bfr, int size, int flags, MMIOT *f)
|
|
304
200
|
___mkd_initmmiot(&sub, f->footnotes);
|
305
201
|
|
306
202
|
sub.flags = f->flags | flags;
|
307
|
-
sub.
|
203
|
+
sub.cb = f->cb;
|
308
204
|
|
309
205
|
push(bfr, size, &sub);
|
310
206
|
EXPAND(sub.in) = 0;
|
@@ -345,6 +241,8 @@ puturl(char *s, int size, MMIOT *f, int display)
|
|
345
241
|
Qstring("%22", f);
|
346
242
|
else if ( isalnum(c) || ispunct(c) || (display && isspace(c)) )
|
347
243
|
Qchar(c, f);
|
244
|
+
else if ( c == 003 ) /* untokenize ^C */
|
245
|
+
Qstring(" ", f);
|
348
246
|
else
|
349
247
|
Qprintf(f, "%%%02X", c);
|
350
248
|
}
|
@@ -512,27 +410,28 @@ linkyurl(MMIOT *f, int image, Footnote *p)
|
|
512
410
|
|
513
411
|
/* prefixes for <automatic links>
|
514
412
|
*/
|
515
|
-
static struct {
|
413
|
+
static struct _protocol {
|
516
414
|
char *name;
|
517
415
|
int nlen;
|
518
416
|
} protocol[] = {
|
519
417
|
#define _aprotocol(x) { x, (sizeof x)-1 }
|
520
|
-
_aprotocol( "http://" ),
|
521
418
|
_aprotocol( "https://" ),
|
522
|
-
_aprotocol( "
|
419
|
+
_aprotocol( "http://" ),
|
523
420
|
_aprotocol( "news://" ),
|
421
|
+
_aprotocol( "ftp://" ),
|
524
422
|
#undef _aprotocol
|
525
423
|
};
|
526
424
|
#define NRPROTOCOLS (sizeof protocol / sizeof protocol[0])
|
527
425
|
|
528
426
|
|
529
427
|
static int
|
530
|
-
isautoprefix(char *text)
|
428
|
+
isautoprefix(char *text, int size)
|
531
429
|
{
|
532
430
|
int i;
|
431
|
+
struct _protocol *p;
|
533
432
|
|
534
|
-
for (i=0; i < NRPROTOCOLS; i++)
|
535
|
-
if ( strncasecmp(text,
|
433
|
+
for (i=0, p=protocol; i < NRPROTOCOLS; i++, p++)
|
434
|
+
if ( (size >= p->nlen) && strncasecmp(text, p->name, p->nlen) == 0 )
|
536
435
|
return 1;
|
537
436
|
return 0;
|
538
437
|
}
|
@@ -584,8 +483,7 @@ pseudo(Cstring t)
|
|
584
483
|
int i;
|
585
484
|
linkytype *r;
|
586
485
|
|
587
|
-
for ( i=0; i < NR(specials); i++ ) {
|
588
|
-
r = &specials[i];
|
486
|
+
for ( i=0, r=specials; i < NR(specials); i++,r++ ) {
|
589
487
|
if ( (S(t) > r->szpat) && (strncasecmp(T(t), r->pat, r->szpat) == 0) )
|
590
488
|
return r;
|
591
489
|
}
|
@@ -593,6 +491,36 @@ pseudo(Cstring t)
|
|
593
491
|
}
|
594
492
|
|
595
493
|
|
494
|
+
/* print out the start of an `img' or `a' tag, applying callbacks as needed.
|
495
|
+
*/
|
496
|
+
static void
|
497
|
+
printlinkyref(MMIOT *f, linkytype *tag, char *link, int size)
|
498
|
+
{
|
499
|
+
char *edit;
|
500
|
+
|
501
|
+
Qstring(tag->link_pfx, f);
|
502
|
+
|
503
|
+
if ( tag->kind & IS_URL ) {
|
504
|
+
if ( f->cb->e_url && (edit = (*f->cb->e_url)(link, size, f->cb->e_data)) ) {
|
505
|
+
puturl(edit, strlen(edit), f, 0);
|
506
|
+
if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data);
|
507
|
+
}
|
508
|
+
else
|
509
|
+
puturl(link + tag->szpat, size - tag->szpat, f, 0);
|
510
|
+
}
|
511
|
+
else
|
512
|
+
___mkd_reparse(link + tag->szpat, size - tag->szpat, INSIDE_TAG, f);
|
513
|
+
|
514
|
+
Qstring(tag->link_sfx, f);
|
515
|
+
|
516
|
+
if ( f->cb->e_flags && (edit = (*f->cb->e_flags)(link, size, f->cb->e_data)) ) {
|
517
|
+
Qchar(' ', f);
|
518
|
+
Qstring(edit, f);
|
519
|
+
if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data);
|
520
|
+
}
|
521
|
+
} /* printlinkyref */
|
522
|
+
|
523
|
+
|
596
524
|
/* print out a linky (or fail if it's Not Allowed)
|
597
525
|
*/
|
598
526
|
static int
|
@@ -608,11 +536,11 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
|
|
608
536
|
}
|
609
537
|
else if ( (f->flags & SAFELINK) && T(ref->link)
|
610
538
|
&& (T(ref->link)[0] != '/')
|
611
|
-
&& !isautoprefix(T(ref->link)) )
|
539
|
+
&& !isautoprefix(T(ref->link), S(ref->link)) )
|
612
540
|
/* if SAFELINK, only accept links that are local or
|
613
541
|
* a well-known protocol
|
614
542
|
*/
|
615
|
-
|
543
|
+
return 0;
|
616
544
|
else
|
617
545
|
tag = &linkt;
|
618
546
|
|
@@ -620,21 +548,11 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
|
|
620
548
|
return 0;
|
621
549
|
|
622
550
|
if ( tag->link_pfx ) {
|
623
|
-
|
624
|
-
|
625
|
-
if ( tag->kind & IS_URL ) {
|
626
|
-
if ( f->base && T(ref->link) && (T(ref->link)[tag->szpat] == '/') )
|
627
|
-
puturl(f->base, strlen(f->base), f, 0);
|
628
|
-
puturl(T(ref->link) + tag->szpat, S(ref->link) - tag->szpat, f, 0);
|
629
|
-
}
|
630
|
-
else
|
631
|
-
___mkd_reparse(T(ref->link) + tag->szpat, S(ref->link) - tag->szpat, INSIDE_TAG, f);
|
632
|
-
|
633
|
-
Qstring(tag->link_sfx, f);
|
551
|
+
printlinkyref(f, tag, T(ref->link), S(ref->link));
|
634
552
|
|
635
|
-
if ( tag->WxH) {
|
636
|
-
if ( ref->height) Qprintf(f," height=\"%d\"", ref->height);
|
637
|
-
if ( ref->width) Qprintf(f, " width=\"%d\"", ref->width);
|
553
|
+
if ( tag->WxH ) {
|
554
|
+
if ( ref->height ) Qprintf(f," height=\"%d\"", ref->height);
|
555
|
+
if ( ref->width ) Qprintf(f, " width=\"%d\"", ref->width);
|
638
556
|
}
|
639
557
|
|
640
558
|
if ( S(ref->title) ) {
|
@@ -742,6 +660,89 @@ mangle(char *s, int len, MMIOT *f)
|
|
742
660
|
}
|
743
661
|
|
744
662
|
|
663
|
+
/* nrticks() -- count up a row of tick marks
|
664
|
+
*/
|
665
|
+
static int
|
666
|
+
nrticks(int offset, MMIOT *f)
|
667
|
+
{
|
668
|
+
int tick = 0;
|
669
|
+
|
670
|
+
while ( peek(f, offset+tick) == '`' ) tick++;
|
671
|
+
|
672
|
+
return tick;
|
673
|
+
} /* nrticks */
|
674
|
+
|
675
|
+
|
676
|
+
/* matchticks() -- match a certain # of ticks, and if that fails
|
677
|
+
* match the largest subset of those ticks.
|
678
|
+
*
|
679
|
+
* if a subset was matched, modify the passed in
|
680
|
+
* # of ticks so that the caller (text()) can
|
681
|
+
* appropriately process the horrible thing.
|
682
|
+
*/
|
683
|
+
static int
|
684
|
+
matchticks(MMIOT *f, int *ticks)
|
685
|
+
{
|
686
|
+
int size, tick, c;
|
687
|
+
int subsize=0, subtick=0;
|
688
|
+
|
689
|
+
for (size = *ticks; (c=peek(f,size)) != EOF; ) {
|
690
|
+
if ( c == '`' )
|
691
|
+
if ( (tick=nrticks(size,f)) == *ticks )
|
692
|
+
return size;
|
693
|
+
else {
|
694
|
+
if ( tick > subtick ) {
|
695
|
+
subsize = size;
|
696
|
+
subtick = tick;
|
697
|
+
}
|
698
|
+
size += tick;
|
699
|
+
}
|
700
|
+
else
|
701
|
+
size++;
|
702
|
+
}
|
703
|
+
if ( subsize ) {
|
704
|
+
*ticks = subtick;
|
705
|
+
return subsize;
|
706
|
+
}
|
707
|
+
return 0;
|
708
|
+
|
709
|
+
} /* matchticks */
|
710
|
+
|
711
|
+
|
712
|
+
/* code() -- write a string out as code. The only characters that have
|
713
|
+
* special meaning in a code block are * `<' and `&' , which
|
714
|
+
* are /always/ expanded to < and &
|
715
|
+
*/
|
716
|
+
static void
|
717
|
+
code(MMIOT *f, char *s, int length)
|
718
|
+
{
|
719
|
+
int i,c;
|
720
|
+
|
721
|
+
for ( i=0; i < length; i++ )
|
722
|
+
if ( (c = s[i]) == 003) /* ^C: expand back to 2 spaces */
|
723
|
+
Qstring(" ", f);
|
724
|
+
else
|
725
|
+
cputc(c, f);
|
726
|
+
} /* code */
|
727
|
+
|
728
|
+
|
729
|
+
/* codespan() -- write out a chunk of text as code, trimming one
|
730
|
+
* space off the front and/or back as appropriate.
|
731
|
+
*/
|
732
|
+
static void
|
733
|
+
codespan(MMIOT *f, int size)
|
734
|
+
{
|
735
|
+
int i=0, c;
|
736
|
+
|
737
|
+
if ( size > 1 && peek(f, size-1) == ' ' ) --size;
|
738
|
+
if ( peek(f,i) == ' ' ) ++i, --size;
|
739
|
+
|
740
|
+
Qstring("<code>", f);
|
741
|
+
code(f, cursor(f)+(i-1), size);
|
742
|
+
Qstring("</code>", f);
|
743
|
+
} /* codespan */
|
744
|
+
|
745
|
+
|
745
746
|
/* before letting a tag through, validate against
|
746
747
|
* DENY_A and DENY_IMG
|
747
748
|
*/
|
@@ -826,10 +827,9 @@ process_possible_link(MMIOT *f, int size)
|
|
826
827
|
Qstring("</a>", f);
|
827
828
|
return 1;
|
828
829
|
}
|
829
|
-
else if ( isautoprefix(text) ) {
|
830
|
-
|
831
|
-
|
832
|
-
Qstring("\">", f);
|
830
|
+
else if ( isautoprefix(text, size) ) {
|
831
|
+
printlinkyref(f, &linkt, text, size);
|
832
|
+
Qchar('>', f);
|
833
833
|
puturl(text,size,f, 1);
|
834
834
|
Qstring("</a>", f);
|
835
835
|
return 1;
|
@@ -879,7 +879,10 @@ maybe_tag_or_link(MMIOT *f)
|
|
879
879
|
else
|
880
880
|
size++;
|
881
881
|
|
882
|
-
|
882
|
+
if ( forbidden_tag(f) )
|
883
|
+
return 0;
|
884
|
+
|
885
|
+
Qchar('<', f);
|
883
886
|
while ( ((c = peek(f, 1)) != EOF) && (c != '>') )
|
884
887
|
Qchar(pull(f), f);
|
885
888
|
return 1;
|
@@ -1065,7 +1068,7 @@ text(MMIOT *f)
|
|
1065
1068
|
int smartyflags = 0;
|
1066
1069
|
|
1067
1070
|
while (1) {
|
1068
|
-
if ( (f->flags & AUTOLINK) && isalpha(peek(f,1)) )
|
1071
|
+
if ( (f->flags & AUTOLINK) && isalpha(peek(f,1)) && !tag_text(f) )
|
1069
1072
|
maybe_autolink(f);
|
1070
1073
|
|
1071
1074
|
c = pull(f);
|
@@ -1078,7 +1081,7 @@ text(MMIOT *f)
|
|
1078
1081
|
switch (c) {
|
1079
1082
|
case 0: break;
|
1080
1083
|
|
1081
|
-
case 3: Qstring("<br/>", f);
|
1084
|
+
case 3: Qstring(tag_text(f) ? " " : "<br/>", f);
|
1082
1085
|
break;
|
1083
1086
|
|
1084
1087
|
case '>': if ( tag_text(f) )
|
@@ -1131,16 +1134,13 @@ text(MMIOT *f)
|
|
1131
1134
|
}
|
1132
1135
|
#endif
|
1133
1136
|
case '*':
|
1134
|
-
#if RELAXED_EMPHASIS
|
1135
1137
|
/* Underscores & stars don't count if they're out in the middle
|
1136
1138
|
* of whitespace */
|
1137
|
-
if (
|
1138
|
-
&& isthisspace(f,1) ) {
|
1139
|
+
if ( isthisspace(f,-1) && isthisspace(f,1) ) {
|
1139
1140
|
Qchar(c, f);
|
1140
1141
|
break;
|
1141
1142
|
}
|
1142
1143
|
/* else fall into the regular old emphasis case */
|
1143
|
-
#endif
|
1144
1144
|
if ( tag_text(f) )
|
1145
1145
|
Qchar(c, f);
|
1146
1146
|
else {
|
@@ -1150,17 +1150,20 @@ text(MMIOT *f)
|
|
1150
1150
|
}
|
1151
1151
|
break;
|
1152
1152
|
|
1153
|
-
case '`': if ( tag_text(f)
|
1153
|
+
case '`': if ( tag_text(f) )
|
1154
1154
|
Qchar(c, f);
|
1155
1155
|
else {
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1156
|
+
int size, tick = nrticks(0, f);
|
1157
|
+
|
1158
|
+
if ( size = matchticks(f, &tick) ) {
|
1159
|
+
shift(f, tick);
|
1160
|
+
codespan(f, size-tick);
|
1161
|
+
shift(f, size-1);
|
1162
|
+
}
|
1163
|
+
else {
|
1164
|
+
Qchar(c, f);
|
1165
|
+
Qcopy(tick-1, f);
|
1160
1166
|
}
|
1161
|
-
else
|
1162
|
-
code(1, f);
|
1163
|
-
Qstring("</code>", f);
|
1164
1167
|
}
|
1165
1168
|
break;
|
1166
1169
|
|
@@ -1169,11 +1172,10 @@ text(MMIOT *f)
|
|
1169
1172
|
break;
|
1170
1173
|
case '<': Qstring("<", f);
|
1171
1174
|
break;
|
1172
|
-
case '\\':
|
1173
1175
|
case '>': case '#': case '.': case '-':
|
1174
1176
|
case '+': case '{': case '}': case ']':
|
1175
|
-
case '(': case ')': case '"': case '\'':
|
1176
1177
|
case '!': case '[': case '*': case '_':
|
1178
|
+
case '\\':case '(': case ')':
|
1177
1179
|
case '`': Qchar(c, f);
|
1178
1180
|
break;
|
1179
1181
|
default:
|
@@ -1207,74 +1209,6 @@ text(MMIOT *f)
|
|
1207
1209
|
} /* text */
|
1208
1210
|
|
1209
1211
|
|
1210
|
-
static int
|
1211
|
-
iscodeblock(MMIOT *f)
|
1212
|
-
{
|
1213
|
-
int i=1, single = 1, c;
|
1214
|
-
|
1215
|
-
if ( peek(f,i) == '`' ) {
|
1216
|
-
single=0;
|
1217
|
-
i++;
|
1218
|
-
}
|
1219
|
-
while ( (c=peek(f,i)) != EOF ) {
|
1220
|
-
if ( (c == '`') && (single || peek(f,i+1) == '`') )
|
1221
|
-
return 1;
|
1222
|
-
else if ( c == '\\' )
|
1223
|
-
i++;
|
1224
|
-
i++;
|
1225
|
-
}
|
1226
|
-
return 0;
|
1227
|
-
|
1228
|
-
}
|
1229
|
-
|
1230
|
-
static int
|
1231
|
-
endofcode(int escape, int offset, MMIOT *f)
|
1232
|
-
{
|
1233
|
-
switch (escape) {
|
1234
|
-
case 2: if ( peek(f, offset+1) == '`' ) {
|
1235
|
-
shift(f,1);
|
1236
|
-
case 1: shift(f,offset);
|
1237
|
-
return 1;
|
1238
|
-
}
|
1239
|
-
default:return 0;
|
1240
|
-
}
|
1241
|
-
}
|
1242
|
-
|
1243
|
-
|
1244
|
-
/* the only characters that have special meaning in a code block are
|
1245
|
-
* `<' and `&' , which are /always/ expanded to < and &
|
1246
|
-
*/
|
1247
|
-
static void
|
1248
|
-
code(int escape, MMIOT *f)
|
1249
|
-
{
|
1250
|
-
int c;
|
1251
|
-
|
1252
|
-
if ( escape && (peek(f,1) == ' ') )
|
1253
|
-
shift(f,1);
|
1254
|
-
|
1255
|
-
while ( (c = pull(f)) != EOF ) {
|
1256
|
-
switch (c) {
|
1257
|
-
case ' ': if ( peek(f,1) == '`' && endofcode(escape, 1, f) )
|
1258
|
-
return;
|
1259
|
-
Qchar(c, f);
|
1260
|
-
break;
|
1261
|
-
|
1262
|
-
case '`': if ( endofcode(escape, 0, f) )
|
1263
|
-
return;
|
1264
|
-
Qchar(c, f);
|
1265
|
-
break;
|
1266
|
-
|
1267
|
-
case '\\': cputc(c, f);
|
1268
|
-
if ( peek(f,1) == '>' || (c = pull(f)) == EOF )
|
1269
|
-
break;
|
1270
|
-
|
1271
|
-
default: cputc(c, f);
|
1272
|
-
break;
|
1273
|
-
}
|
1274
|
-
}
|
1275
|
-
} /* code */
|
1276
|
-
|
1277
|
-
|
1278
1212
|
/* print a header block
|
1279
1213
|
*/
|
1280
1214
|
static void
|
@@ -1333,6 +1267,7 @@ splat(Line *p, char *block, Istring align, int force, MMIOT *f)
|
|
1333
1267
|
return colno;
|
1334
1268
|
}
|
1335
1269
|
|
1270
|
+
|
1336
1271
|
static int
|
1337
1272
|
printtable(Paragraph *pp, MMIOT *f)
|
1338
1273
|
{
|
@@ -1402,8 +1337,9 @@ printblock(Paragraph *pp, MMIOT *f)
|
|
1402
1337
|
|
1403
1338
|
while (t) {
|
1404
1339
|
if ( S(t->text) ) {
|
1405
|
-
if (
|
1406
|
-
|
1340
|
+
if ( t->next && S(t->text) > 2
|
1341
|
+
&& T(t->text)[S(t->text)-2] == ' '
|
1342
|
+
&& T(t->text)[S(t->text)-1] == ' ' ) {
|
1407
1343
|
push(T(t->text), S(t->text)-2, f);
|
1408
1344
|
push("\003\n", 2, f);
|
1409
1345
|
}
|
@@ -1428,19 +1364,18 @@ printcode(Line *t, MMIOT *f)
|
|
1428
1364
|
{
|
1429
1365
|
int blanks;
|
1430
1366
|
|
1431
|
-
|
1367
|
+
Qstring("<pre><code>", f);
|
1368
|
+
for ( blanks = 0; t ; t = t->next ) {
|
1432
1369
|
if ( S(t->text) > t->dle ) {
|
1433
1370
|
while ( blanks ) {
|
1434
|
-
|
1371
|
+
Qchar('\n', f);
|
1435
1372
|
--blanks;
|
1436
1373
|
}
|
1437
|
-
|
1438
|
-
|
1374
|
+
code(f, T(t->text), S(t->text));
|
1375
|
+
Qchar('\n', f);
|
1439
1376
|
}
|
1440
1377
|
else blanks++;
|
1441
|
-
|
1442
|
-
Qstring("<pre><code>", f);
|
1443
|
-
code(0, f);
|
1378
|
+
}
|
1444
1379
|
Qstring("</code></pre>", f);
|
1445
1380
|
}
|
1446
1381
|
|
data/ext/markdown.c
CHANGED
@@ -305,8 +305,8 @@ isfootnote(Line *t)
|
|
305
305
|
for ( ++i; i < S(t->text) ; ++i ) {
|
306
306
|
if ( T(t->text)[i] == '[' )
|
307
307
|
return 0;
|
308
|
-
else if ( T(t->text)[i] == ']'
|
309
|
-
return 1;
|
308
|
+
else if ( T(t->text)[i] == ']' )
|
309
|
+
return ( T(t->text)[i+1] == ':' ) ;
|
310
310
|
}
|
311
311
|
return 0;
|
312
312
|
}
|
@@ -315,11 +315,14 @@ isfootnote(Line *t)
|
|
315
315
|
static int
|
316
316
|
isquote(Line *t)
|
317
317
|
{
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
318
|
+
int j;
|
319
|
+
|
320
|
+
for ( j=0; j < 4; j++ )
|
321
|
+
if ( T(t->text)[j] == '>' )
|
322
|
+
return 1;
|
323
|
+
else if ( !isspace(T(t->text)[j]) )
|
324
|
+
return 0;
|
325
|
+
return 0;
|
323
326
|
}
|
324
327
|
|
325
328
|
|
@@ -386,13 +389,14 @@ ishdr(Line *t, int *htyp)
|
|
386
389
|
|
387
390
|
if ( t->next ) {
|
388
391
|
char *q = T(t->next->text);
|
392
|
+
int last = S(t->next->text);
|
389
393
|
|
390
394
|
if ( (*q == '=') || (*q == '-') ) {
|
391
|
-
/*
|
392
|
-
|
393
|
-
|
395
|
+
/* ignore trailing whitespace */
|
396
|
+
while ( (last > 1) && isspace(q[last-1]) )
|
397
|
+
--last;
|
394
398
|
|
395
|
-
for (i=1; i
|
399
|
+
for (i=1; i < last; i++)
|
396
400
|
if ( q[0] != q[i] )
|
397
401
|
return 0;
|
398
402
|
*htyp = SETEXT;
|
@@ -483,7 +487,8 @@ headerblock(Paragraph *pp, int htyp)
|
|
483
487
|
* the leading and trailing `#`'s
|
484
488
|
*/
|
485
489
|
|
486
|
-
for (i=0; (T(p->text)[i] == T(p->text)[0]) && (i < S(p->text)-1)
|
490
|
+
for (i=0; (T(p->text)[i] == T(p->text)[0]) && (i < S(p->text)-1)
|
491
|
+
&& (i < 6); i++)
|
487
492
|
;
|
488
493
|
|
489
494
|
pp->hnumber = i;
|
@@ -637,9 +642,16 @@ quoteblock(Paragraph *p)
|
|
637
642
|
|
638
643
|
for ( t = p->text; t ; t = q ) {
|
639
644
|
if ( isquote(t) ) {
|
640
|
-
|
641
|
-
|
642
|
-
|
645
|
+
/* clip leading spaces */
|
646
|
+
for (qp = 0; T(t->text)[qp] != '>'; qp ++)
|
647
|
+
/* assert: the first nonblank character on this line
|
648
|
+
* will be a >
|
649
|
+
*/;
|
650
|
+
/* clip '>' */
|
651
|
+
qp++;
|
652
|
+
/* clip next space, if any */
|
653
|
+
if ( T(t->text)[qp] == ' ' )
|
654
|
+
qp++;
|
643
655
|
CLIP(t->text, 0, qp);
|
644
656
|
t->dle = mkd_firstnonblank(t);
|
645
657
|
}
|
@@ -719,8 +731,9 @@ listitem(Paragraph *p, int indent)
|
|
719
731
|
}
|
720
732
|
|
721
733
|
/* after a blank line, the next block needs to start with a line
|
722
|
-
* that's indented 4
|
723
|
-
*
|
734
|
+
* that's indented 4(? -- reference implementation allows a 1
|
735
|
+
* character indent, but that has unfortunate side effects here)
|
736
|
+
* spaces, but after that the line doesn't need any indentation
|
724
737
|
*/
|
725
738
|
if ( q != t->next ) {
|
726
739
|
if (q->dle < indent) {
|
@@ -728,7 +741,8 @@ listitem(Paragraph *p, int indent)
|
|
728
741
|
t->next = 0;
|
729
742
|
return q;
|
730
743
|
}
|
731
|
-
indent
|
744
|
+
/* indent as far as the initial line was indented. */
|
745
|
+
indent = clip;
|
732
746
|
}
|
733
747
|
|
734
748
|
if ( (q->dle < indent) && (ishr(q) || islist(q,&z)) && !ishdr(q,&z) ) {
|
@@ -1070,8 +1084,8 @@ mkd_compile(Document *doc, int flags)
|
|
1070
1084
|
|
1071
1085
|
doc->compiled = 1;
|
1072
1086
|
memset(doc->ctx, 0, sizeof(MMIOT) );
|
1073
|
-
doc->ctx->
|
1074
|
-
doc->ctx->
|
1087
|
+
doc->ctx->cb = &(doc->cb);
|
1088
|
+
doc->ctx->flags = flags & USER_FLAGS;
|
1075
1089
|
CREATE(doc->ctx->in);
|
1076
1090
|
doc->ctx->footnotes = malloc(sizeof doc->ctx->footnotes[0]);
|
1077
1091
|
CREATE(*doc->ctx->footnotes);
|
data/ext/markdown.h
CHANGED
@@ -56,6 +56,17 @@ typedef struct block {
|
|
56
56
|
typedef STRING(block) Qblock;
|
57
57
|
|
58
58
|
|
59
|
+
typedef char* (*mkd_callback_t)(const char*, const int, void*);
|
60
|
+
typedef void (*mkd_free_t)(char*, void*);
|
61
|
+
|
62
|
+
typedef struct callback_data {
|
63
|
+
void *e_data; /* private data for callbacks */
|
64
|
+
mkd_callback_t e_url; /* url edit callback */
|
65
|
+
mkd_callback_t e_flags; /* extra href flags callback */
|
66
|
+
mkd_free_t e_free; /* edit/flags callback memory deallocator */
|
67
|
+
} Callback_data;
|
68
|
+
|
69
|
+
|
59
70
|
/* a magic markdown io thing holds all the data structures needed to
|
60
71
|
* do the backend processing of a markdown document
|
61
72
|
*/
|
@@ -81,7 +92,7 @@ typedef struct mmiot {
|
|
81
92
|
#define SAFELINK 0x8000
|
82
93
|
#define USER_FLAGS 0xFCFF
|
83
94
|
#define EMBEDDED DENY_A|DENY_IMG|NO_PSEUDO_PROTO|CDATA_OUTPUT
|
84
|
-
|
95
|
+
Callback_data *cb;
|
85
96
|
} MMIOT;
|
86
97
|
|
87
98
|
|
@@ -100,7 +111,7 @@ typedef struct document {
|
|
100
111
|
int html; /* set after (internal) htmlify() */
|
101
112
|
int tabstop; /* for properly expanding tabs (ick) */
|
102
113
|
MMIOT *ctx; /* backend buffers, flags, and structures */
|
103
|
-
|
114
|
+
Callback_data cb; /* callback functions & private data */
|
104
115
|
} Document;
|
105
116
|
|
106
117
|
|
data/ext/mkdio.c
CHANGED
@@ -217,14 +217,6 @@ markdown(Document *document, FILE *out, int flags)
|
|
217
217
|
}
|
218
218
|
|
219
219
|
|
220
|
-
void
|
221
|
-
mkd_basename(Document *document, char *base)
|
222
|
-
{
|
223
|
-
if ( document )
|
224
|
-
document->base = base;
|
225
|
-
}
|
226
|
-
|
227
|
-
|
228
220
|
/* write out a Cstring, mangled into a form suitable for `<a href=` or `<a id=`
|
229
221
|
*/
|
230
222
|
void
|
@@ -301,3 +293,43 @@ mkd_generateline(char *bfr, int size, FILE *output, int flags)
|
|
301
293
|
___mkd_freemmiot(&f, 0);
|
302
294
|
return 0;
|
303
295
|
}
|
296
|
+
|
297
|
+
|
298
|
+
/* set the url display callback
|
299
|
+
*/
|
300
|
+
void
|
301
|
+
mkd_e_url(Document *f, mkd_callback_t edit)
|
302
|
+
{
|
303
|
+
if ( f )
|
304
|
+
f->cb.e_url = edit;
|
305
|
+
}
|
306
|
+
|
307
|
+
|
308
|
+
/* set the url options callback
|
309
|
+
*/
|
310
|
+
void
|
311
|
+
mkd_e_flags(Document *f, mkd_callback_t edit)
|
312
|
+
{
|
313
|
+
if ( f )
|
314
|
+
f->cb.e_flags = edit;
|
315
|
+
}
|
316
|
+
|
317
|
+
|
318
|
+
/* set the url display/options deallocator
|
319
|
+
*/
|
320
|
+
void
|
321
|
+
mkd_e_free(Document *f, mkd_free_t dealloc)
|
322
|
+
{
|
323
|
+
if ( f )
|
324
|
+
f->cb.e_free = dealloc;
|
325
|
+
}
|
326
|
+
|
327
|
+
|
328
|
+
/* set the url display/options context data field
|
329
|
+
*/
|
330
|
+
void
|
331
|
+
mkd_e_data(Document *f, void *data)
|
332
|
+
{
|
333
|
+
if ( f )
|
334
|
+
f->cb.e_data = data;
|
335
|
+
}
|
data/ext/mkdio.h
CHANGED
@@ -48,6 +48,16 @@ int mkd_generatecss(MMIOT*,FILE*);
|
|
48
48
|
int mkd_generateline(char *, int, FILE*, int);
|
49
49
|
#define mkd_text mkd_generateline
|
50
50
|
|
51
|
+
/* url generator callbacks
|
52
|
+
*/
|
53
|
+
typedef char * (*mkd_callback_t)(const char*, const int, void*);
|
54
|
+
typedef void (*mkd_free_t)(char*, void*);
|
55
|
+
|
56
|
+
void mkd_e_url(void *, mkd_callback_t);
|
57
|
+
void mkd_e_flags(void *, mkd_callback_t);
|
58
|
+
void mkd_e_free(void *, mkd_free_t );
|
59
|
+
void mkd_e_data(void *, void *);
|
60
|
+
|
51
61
|
/* version#.
|
52
62
|
*/
|
53
63
|
extern char markdown_version[];
|
data/lib/rdiscount.rb
CHANGED
data/rdiscount.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'rdiscount'
|
3
|
-
s.version = '1.
|
3
|
+
s.version = '1.6.3'
|
4
4
|
s.summary = "Fast Implementation of Gruber's Markdown in C"
|
5
5
|
s.date = '2010-03-08'
|
6
6
|
s.email = 'r@tomayko.com'
|
@@ -15,11 +15,13 @@ Gem::Specification.new do |s|
|
|
15
15
|
bin/rdiscount
|
16
16
|
ext/Csio.c
|
17
17
|
ext/amalloc.h
|
18
|
+
ext/basename.c
|
18
19
|
ext/config.h
|
19
20
|
ext/css.c
|
20
21
|
ext/cstring.h
|
21
22
|
ext/docheader.c
|
22
23
|
ext/dumptree.c
|
24
|
+
ext/emmatch.c
|
23
25
|
ext/extconf.rb
|
24
26
|
ext/generate.c
|
25
27
|
ext/markdown.c
|
data/test/markdown_test.rb
CHANGED
@@ -129,7 +129,7 @@ class MarkdownTest < Test::Unit::TestCase
|
|
129
129
|
"=================== \n\n" +
|
130
130
|
"By Candice Yellowflower \n"
|
131
131
|
markdown = Markdown.new(text)
|
132
|
-
assert_equal "<h1>The Ant-Sugar Tales </h1>\n\n<p>By Candice Yellowflower
|
132
|
+
assert_equal "<h1>The Ant-Sugar Tales </h1>\n\n<p>By Candice Yellowflower</p>\n",
|
133
133
|
markdown.to_html
|
134
134
|
end
|
135
135
|
|
metadata
CHANGED
@@ -4,10 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
|
-
-
|
8
|
-
-
|
9
|
-
|
10
|
-
version: 1.5.8.1
|
7
|
+
- 6
|
8
|
+
- 3
|
9
|
+
version: 1.6.3
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Ryan Tomayko
|
@@ -36,11 +35,13 @@ files:
|
|
36
35
|
- bin/rdiscount
|
37
36
|
- ext/Csio.c
|
38
37
|
- ext/amalloc.h
|
38
|
+
- ext/basename.c
|
39
39
|
- ext/config.h
|
40
40
|
- ext/css.c
|
41
41
|
- ext/cstring.h
|
42
42
|
- ext/docheader.c
|
43
43
|
- ext/dumptree.c
|
44
|
+
- ext/emmatch.c
|
44
45
|
- ext/extconf.rb
|
45
46
|
- ext/generate.c
|
46
47
|
- ext/markdown.c
|