rdiscount 1.3.5 → 1.5.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +20 -10
- data/Rakefile +12 -11
- data/ext/Csio.c +14 -2
- data/ext/css.c +76 -0
- data/ext/cstring.h +7 -5
- data/ext/dumptree.c +5 -1
- data/ext/generate.c +473 -268
- data/ext/markdown.c +209 -96
- data/ext/markdown.h +16 -5
- data/ext/mkdio.c +68 -6
- data/ext/mkdio.h +20 -7
- data/ext/resource.c +13 -27
- data/ext/toc.c +24 -20
- data/ext/xml.c +82 -0
- data/lib/rdiscount.rb +2 -2
- data/rdiscount.gemspec +4 -2
- data/test/markdown_test.rb +17 -0
- metadata +5 -3
data/ext/markdown.h
CHANGED
@@ -11,6 +11,7 @@ typedef struct footnote {
|
|
11
11
|
Cstring link; /* what this footnote points to */
|
12
12
|
Cstring title; /* what it's called (TITLE= attribute) */
|
13
13
|
int height, width; /* dimensions (for image link) */
|
14
|
+
int dealloc; /* deallocation needed? */
|
14
15
|
} Footnote;
|
15
16
|
|
16
17
|
/* each input line is read into a Line, which contains the line,
|
@@ -36,7 +37,7 @@ typedef struct paragraph {
|
|
36
37
|
char *ident; /* %id% tag for QUOTE */
|
37
38
|
enum { WHITESPACE=0, CODE, QUOTE, MARKUP,
|
38
39
|
HTML, STYLE, DL, UL, OL, AL, LISTITEM,
|
39
|
-
HDR, HR } typ;
|
40
|
+
HDR, HR, TABLE, SOURCE } typ;
|
40
41
|
enum { IMPLICIT=0, PARA, CENTER} align;
|
41
42
|
int hnumber; /* <Hn> for typ == HDR */
|
42
43
|
} Paragraph;
|
@@ -73,9 +74,12 @@ typedef struct mmiot {
|
|
73
74
|
#define INSIDE_TAG 0x0020
|
74
75
|
#define NO_PSEUDO_PROTO 0x0040
|
75
76
|
#define CDATA_OUTPUT 0x0080
|
77
|
+
#define NOTABLES 0x0400
|
76
78
|
#define TOC 0x1000
|
77
79
|
#define MKD_1_COMPAT 0x2000
|
78
|
-
#define
|
80
|
+
#define AUTOLINK 0x4000
|
81
|
+
#define SAFELINK 0x8000
|
82
|
+
#define USER_FLAGS 0xFCFF
|
79
83
|
#define EMBEDDED DENY_A|DENY_IMG|NO_PSEUDO_PROTO|CDATA_OUTPUT
|
80
84
|
char *base;
|
81
85
|
} MMIOT;
|
@@ -104,9 +108,15 @@ extern int mkd_firstnonblank(Line *);
|
|
104
108
|
extern int mkd_compile(Document *, int);
|
105
109
|
extern int mkd_document(Document *, char **);
|
106
110
|
extern int mkd_generatehtml(Document *, FILE *);
|
107
|
-
extern int
|
111
|
+
extern int mkd_css(Document *, char **);
|
112
|
+
extern int mkd_generatecss(Document *, FILE *);
|
113
|
+
#define mkd_style mkd_generatecss
|
114
|
+
extern int mkd_xml(char *, int , char **);
|
115
|
+
extern int mkd_generatexml(char *, int, FILE *);
|
108
116
|
extern void mkd_cleanup(Document *);
|
109
|
-
extern int
|
117
|
+
extern int mkd_line(char *, int, char **, int);
|
118
|
+
extern int mkd_generateline(char *, int, FILE*, int);
|
119
|
+
#define mkd_text mkd_generateline
|
110
120
|
extern void mkd_basename(Document*, char *);
|
111
121
|
extern void mkd_string_to_anchor(char*,int, void(*)(int,void*), void*);
|
112
122
|
|
@@ -123,6 +133,7 @@ extern Document *mkd_string(char*,int, int);
|
|
123
133
|
extern void ___mkd_freeLine(Line *);
|
124
134
|
extern void ___mkd_freeLines(Line *);
|
125
135
|
extern void ___mkd_freeParagraph(Paragraph *);
|
136
|
+
extern void ___mkd_freefootnote(Footnote *);
|
126
137
|
extern void ___mkd_freefootnotes(MMIOT *);
|
127
138
|
extern void ___mkd_initmmiot(MMIOT *, void *);
|
128
139
|
extern void ___mkd_freemmiot(MMIOT *, void *);
|
@@ -130,6 +141,6 @@ extern void ___mkd_freeLineRange(Line *, Line *);
|
|
130
141
|
extern void ___mkd_xml(char *, int, FILE *);
|
131
142
|
extern void ___mkd_reparse(char *, int, int, MMIOT*);
|
132
143
|
extern void ___mkd_emblock(MMIOT*);
|
133
|
-
extern void ___mkd_tidy(
|
144
|
+
extern void ___mkd_tidy(Cstring *);
|
134
145
|
|
135
146
|
#endif/*_MARKDOWN_D*/
|
data/ext/mkdio.c
CHANGED
@@ -113,7 +113,7 @@ populate(getc_func getc, void* ctx, int flags)
|
|
113
113
|
queue(a, &line);
|
114
114
|
S(line) = 0;
|
115
115
|
}
|
116
|
-
else
|
116
|
+
else if ( isprint(c) || isspace(c) || (c & 0x80) )
|
117
117
|
EXPAND(line) = c;
|
118
118
|
}
|
119
119
|
|
@@ -193,7 +193,7 @@ mkd_generatehtml(Document *p, FILE *output)
|
|
193
193
|
|
194
194
|
if ( (szdoc = mkd_document(p, &doc)) != EOF ) {
|
195
195
|
if ( p->ctx->flags & CDATA_OUTPUT )
|
196
|
-
|
196
|
+
mkd_generatexml(doc, szdoc, output);
|
197
197
|
else
|
198
198
|
fwrite(doc, szdoc, 1, output);
|
199
199
|
putc('\n', output);
|
@@ -230,12 +230,74 @@ mkd_basename(Document *document, char *base)
|
|
230
230
|
void
|
231
231
|
mkd_string_to_anchor(char *s, int len, void(*outchar)(int,void*), void *out)
|
232
232
|
{
|
233
|
-
|
234
|
-
|
233
|
+
unsigned char c;
|
234
|
+
|
235
|
+
for ( ; len-- > 0; ) {
|
236
|
+
c = *s++;
|
237
|
+
if ( c == ' ' || c == '&' || c == '<' || c == '"' )
|
235
238
|
(*outchar)('+', out);
|
236
|
-
else if ( isalnum(
|
237
|
-
(*outchar)(
|
239
|
+
else if ( isalnum(c) || ispunct(c) || (c & 0x80) )
|
240
|
+
(*outchar)(c, out);
|
238
241
|
else
|
239
242
|
(*outchar)('~',out);
|
240
243
|
}
|
241
244
|
}
|
245
|
+
|
246
|
+
|
247
|
+
/* ___mkd_reparse() a line
|
248
|
+
*/
|
249
|
+
static void
|
250
|
+
mkd_parse_line(char *bfr, int size, MMIOT *f, int flags)
|
251
|
+
{
|
252
|
+
___mkd_initmmiot(f, 0);
|
253
|
+
f->flags = flags & USER_FLAGS;
|
254
|
+
___mkd_reparse(bfr, size, 0, f);
|
255
|
+
___mkd_emblock(f);
|
256
|
+
}
|
257
|
+
|
258
|
+
|
259
|
+
/* ___mkd_reparse() a line, returning it in malloc()ed memory
|
260
|
+
*/
|
261
|
+
int
|
262
|
+
mkd_line(char *bfr, int size, char **res, int flags)
|
263
|
+
{
|
264
|
+
MMIOT f;
|
265
|
+
int len;
|
266
|
+
|
267
|
+
mkd_parse_line(bfr, size, &f, flags);
|
268
|
+
|
269
|
+
if ( len = S(f.out) ) {
|
270
|
+
/* kludge alert; we know that T(f.out) is malloced memory,
|
271
|
+
* so we can just steal it away. This is awful -- there
|
272
|
+
* should be an opaque method that transparently moves
|
273
|
+
* the pointer out of the embedded Cstring.
|
274
|
+
*/
|
275
|
+
*res = T(f.out);
|
276
|
+
T(f.out) = 0;
|
277
|
+
S(f.out) = 0;
|
278
|
+
}
|
279
|
+
else {
|
280
|
+
*res = 0;
|
281
|
+
len = EOF;
|
282
|
+
}
|
283
|
+
___mkd_freemmiot(&f, 0);
|
284
|
+
return len;
|
285
|
+
}
|
286
|
+
|
287
|
+
|
288
|
+
/* ___mkd_reparse() a line, writing it to a FILE
|
289
|
+
*/
|
290
|
+
int
|
291
|
+
mkd_generateline(char *bfr, int size, FILE *output, int flags)
|
292
|
+
{
|
293
|
+
MMIOT f;
|
294
|
+
|
295
|
+
mkd_parse_line(bfr, size, &f, flags);
|
296
|
+
if ( flags & CDATA_OUTPUT )
|
297
|
+
mkd_generatexml(T(f.out), S(f.out), output);
|
298
|
+
else
|
299
|
+
fwrite(T(f.out), S(f.out), 1, output);
|
300
|
+
|
301
|
+
___mkd_freemmiot(&f, 0);
|
302
|
+
return 0;
|
303
|
+
}
|
data/ext/mkdio.h
CHANGED
@@ -15,19 +15,15 @@ void mkd_basename(MMIOT*,char*);
|
|
15
15
|
/* compilation, debugging, cleanup
|
16
16
|
*/
|
17
17
|
int mkd_compile(MMIOT*, int);
|
18
|
-
int mkd_generatehtml(MMIOT*,FILE*);
|
19
|
-
int mkd_generatetoc(MMIOT*,FILE*);
|
20
|
-
int mkd_xhtmlpage(MMIOT*,int,FILE*);
|
21
18
|
int mkd_cleanup(MMIOT*);
|
22
19
|
|
23
20
|
/* markup functions
|
24
21
|
*/
|
25
|
-
int mkd_text(char *, int, FILE*, int);
|
26
|
-
int mkd_style(MMIOT*, FILE*);
|
27
22
|
int mkd_dump(MMIOT*, FILE*, int, char*);
|
28
23
|
int markdown(MMIOT*, FILE*, int);
|
29
|
-
|
24
|
+
int mkd_line(char *, int, char **, int);
|
30
25
|
void mkd_string_to_anchor(char *, int, int (*)(int,void*), void*);
|
26
|
+
int mkd_xhtmlpage(MMIOT*,int,FILE*);
|
31
27
|
|
32
28
|
/* header block access
|
33
29
|
*/
|
@@ -38,6 +34,19 @@ char* mkd_doc_date(MMIOT*);
|
|
38
34
|
/* compiled data access
|
39
35
|
*/
|
40
36
|
int mkd_document(MMIOT*, char**);
|
37
|
+
int mkd_toc(MMIOT*, char**);
|
38
|
+
int mkd_css(MMIOT*, char **);
|
39
|
+
int mkd_xml(char *, int, char **);
|
40
|
+
|
41
|
+
/* write-to-file functions
|
42
|
+
*/
|
43
|
+
int mkd_generatehtml(MMIOT*,FILE*);
|
44
|
+
int mkd_generatetoc(MMIOT*,FILE*);
|
45
|
+
int mkd_generatexml(char *, int,FILE*);
|
46
|
+
int mkd_generatecss(MMIOT*,FILE*);
|
47
|
+
#define mkd_style mkd_generatecss
|
48
|
+
int mkd_generateline(char *, int, FILE*, int);
|
49
|
+
#define mkd_text mkd_generateline
|
41
50
|
|
42
51
|
/* version#.
|
43
52
|
*/
|
@@ -50,11 +59,15 @@ extern char markdown_version[];
|
|
50
59
|
#define MKD_NOPANTS 0x0004 /* don't run smartypants() */
|
51
60
|
#define MKD_NOHTML 0x0008 /* don't allow raw html through AT ALL */
|
52
61
|
#define MKD_STRICT 0x0010 /* disable SUPERSCRIPT, RELAXED_EMPHASIS */
|
53
|
-
#define MKD_TAGTEXT 0x0020 /*
|
62
|
+
#define MKD_TAGTEXT 0x0020 /* process text inside an html tag; no
|
63
|
+
* <em>, no <bold>, no html or [] expansion */
|
54
64
|
#define MKD_NO_EXT 0x0040 /* don't allow pseudo-protocols */
|
55
65
|
#define MKD_CDATA 0x0080 /* generate code for xml ![CDATA[...]] */
|
66
|
+
#define MKD_NOTABLES 0x0400 /* disallow tables */
|
56
67
|
#define MKD_TOC 0x1000 /* do table-of-contents processing */
|
57
68
|
#define MKD_1_COMPAT 0x2000 /* compatability with MarkdownTest_1.0 */
|
69
|
+
#define MKD_AUTOLINK 0x4000 /* make http://foo.com link even without <>s */
|
70
|
+
#define MKD_SAFELINK 0x8000 /* paranoid check for link protocol */
|
58
71
|
#define MKD_EMBED MKD_NOLINKS|MKD_NOIMAGE|MKD_TAGTEXT
|
59
72
|
|
60
73
|
/* special flags for mkd_in() and mkd_string()
|
data/ext/resource.c
CHANGED
@@ -55,6 +55,17 @@ ___mkd_freeParagraph(Paragraph *p)
|
|
55
55
|
}
|
56
56
|
|
57
57
|
|
58
|
+
/* bye bye footnote.
|
59
|
+
*/
|
60
|
+
void
|
61
|
+
___mkd_freefootnote(Footnote *f)
|
62
|
+
{
|
63
|
+
DELETE(f->tag);
|
64
|
+
DELETE(f->link);
|
65
|
+
DELETE(f->title);
|
66
|
+
}
|
67
|
+
|
68
|
+
|
58
69
|
/* bye bye footnotes.
|
59
70
|
*/
|
60
71
|
void
|
@@ -63,11 +74,8 @@ ___mkd_freefootnotes(MMIOT *f)
|
|
63
74
|
int i;
|
64
75
|
|
65
76
|
if ( f->footnotes ) {
|
66
|
-
for (i=0; i < S(*f->footnotes); i++)
|
67
|
-
|
68
|
-
DELETE(T(*f->footnotes)[i].link);
|
69
|
-
DELETE(T(*f->footnotes)[i].title);
|
70
|
-
}
|
77
|
+
for (i=0; i < S(*f->footnotes); i++)
|
78
|
+
___mkd_freefootnote( &T(*f->footnotes)[i] );
|
71
79
|
DELETE(*f->footnotes);
|
72
80
|
free(f->footnotes);
|
73
81
|
}
|
@@ -145,25 +153,3 @@ mkd_cleanup(Document *doc)
|
|
145
153
|
free(doc);
|
146
154
|
}
|
147
155
|
}
|
148
|
-
|
149
|
-
|
150
|
-
/* write output in XML format
|
151
|
-
*/
|
152
|
-
void
|
153
|
-
___mkd_xml(char *p, int size, FILE *out)
|
154
|
-
{
|
155
|
-
char c;
|
156
|
-
|
157
|
-
while ( size-- > 0 ) {
|
158
|
-
if ( !isascii(c = *p++) )
|
159
|
-
continue;
|
160
|
-
switch (c) {
|
161
|
-
case '<': fputs("<", out); break;
|
162
|
-
case '>': fputs(">", out); break;
|
163
|
-
case '&': fputs("&", out); break;
|
164
|
-
case '"': fputs(""", out); break;
|
165
|
-
case '\'':fputs("'", out); break;
|
166
|
-
default: putc(c,out); break;
|
167
|
-
}
|
168
|
-
}
|
169
|
-
}
|
data/ext/toc.c
CHANGED
@@ -19,7 +19,7 @@
|
|
19
19
|
int
|
20
20
|
mkd_toc(Document *p, char **doc)
|
21
21
|
{
|
22
|
-
Paragraph *
|
22
|
+
Paragraph *tp, *srcp;
|
23
23
|
int last_hnumber = 0;
|
24
24
|
Cstring res;
|
25
25
|
|
@@ -31,27 +31,31 @@ mkd_toc(Document *p, char **doc)
|
|
31
31
|
if ( !(p && p->ctx) ) return -1;
|
32
32
|
if ( ! (p->ctx->flags & TOC) ) return 0;
|
33
33
|
|
34
|
-
for (
|
35
|
-
|
34
|
+
for ( tp = p->code; tp ; tp = tp->next ) {
|
35
|
+
if ( tp->typ == SOURCE ) {
|
36
|
+
for ( srcp = tp->down; srcp; srcp = srcp->next ) {
|
37
|
+
if ( srcp->typ == HDR && srcp->text ) {
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
39
|
+
if ( last_hnumber == srcp->hnumber )
|
40
|
+
Csprintf(&res, "%*s</li>\n", srcp->hnumber, "");
|
41
|
+
else while ( last_hnumber > srcp->hnumber ) {
|
42
|
+
Csprintf(&res, "%*s</li>\n%*s</ul>\n",
|
43
|
+
last_hnumber, "",
|
44
|
+
last_hnumber-1,"");
|
45
|
+
--last_hnumber;
|
46
|
+
}
|
47
|
+
|
48
|
+
while ( srcp->hnumber > last_hnumber ) {
|
49
|
+
Csprintf(&res, "\n%*s<ul>\n", srcp->hnumber, "");
|
50
|
+
++last_hnumber;
|
51
|
+
}
|
52
|
+
Csprintf(&res, "%*s<li><a href=\"#", srcp->hnumber, "");
|
53
|
+
mkd_string_to_anchor(T(srcp->text->text), S(srcp->text->text), Csputc, &res);
|
54
|
+
Csprintf(&res, "\">");
|
55
|
+
Csreparse(&res, T(srcp->text->text), S(srcp->text->text), 0);
|
56
|
+
Csprintf(&res, "</a>");
|
57
|
+
}
|
49
58
|
}
|
50
|
-
Csprintf(&res, "%*s<li><a href=\"#", pp->hnumber, "");
|
51
|
-
mkd_string_to_anchor(T(pp->text->text), S(pp->text->text), Csputc, &res);
|
52
|
-
Csprintf(&res, "\">");
|
53
|
-
Csreparse(&res, T(pp->text->text), S(pp->text->text), 0);
|
54
|
-
Csprintf(&res, "</a>");
|
55
59
|
}
|
56
60
|
}
|
57
61
|
|
data/ext/xml.c
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
/* markdown: a C implementation of John Gruber's Markdown markup language.
|
2
|
+
*
|
3
|
+
* Copyright (C) 2007 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
|
+
/* return the xml version of a character
|
21
|
+
*/
|
22
|
+
static char *
|
23
|
+
mkd_xmlchar(unsigned char c)
|
24
|
+
{
|
25
|
+
switch (c) {
|
26
|
+
case '<': return "<";
|
27
|
+
case '>': return ">";
|
28
|
+
case '&': return "&";
|
29
|
+
case '"': return """;
|
30
|
+
case '\'': return "'";
|
31
|
+
default: if ( isascii(c) || (c & 0x80) )
|
32
|
+
return 0;
|
33
|
+
return "";
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
|
38
|
+
/* write output in XML format
|
39
|
+
*/
|
40
|
+
int
|
41
|
+
mkd_generatexml(char *p, int size, FILE *out)
|
42
|
+
{
|
43
|
+
unsigned char c;
|
44
|
+
char *entity;
|
45
|
+
|
46
|
+
while ( size-- > 0 ) {
|
47
|
+
c = *p++;
|
48
|
+
|
49
|
+
if ( entity = mkd_xmlchar(c) )
|
50
|
+
fputs(entity, out);
|
51
|
+
else
|
52
|
+
fputc(c, out);
|
53
|
+
}
|
54
|
+
return 0;
|
55
|
+
}
|
56
|
+
|
57
|
+
|
58
|
+
/* build a xml'ed version of a string
|
59
|
+
*/
|
60
|
+
int
|
61
|
+
mkd_xml(char *p, int size, char **res)
|
62
|
+
{
|
63
|
+
unsigned char c;
|
64
|
+
char *entity;
|
65
|
+
Cstring f;
|
66
|
+
|
67
|
+
CREATE(f);
|
68
|
+
RESERVE(f, 100);
|
69
|
+
|
70
|
+
while ( size-- > 0 ) {
|
71
|
+
c = *p++;
|
72
|
+
if ( entity = mkd_xmlchar(c) )
|
73
|
+
Cswrite(&f, entity, strlen(entity));
|
74
|
+
else
|
75
|
+
Csputc(c, &f);
|
76
|
+
}
|
77
|
+
/* HACK ALERT! HACK ALERT! HACK ALERT! */
|
78
|
+
*res = T(f); /* we know that a T(Cstring) is a character pointer */
|
79
|
+
/* so we can simply pick it up and carry it away, */
|
80
|
+
return S(f); /* leaving the husk of the Ctring on the stack */
|
81
|
+
/* END HACK ALERT */
|
82
|
+
}
|
data/lib/rdiscount.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# and passes the Markdown 1.0 test suite. The RDiscount extension makes
|
5
5
|
# the Discount processor available via a Ruby C Extension library.
|
6
6
|
#
|
7
|
-
#
|
7
|
+
# == Usage
|
8
8
|
#
|
9
9
|
# RDiscount implements the basic protocol popularized by RedCloth and adopted
|
10
10
|
# by BlueCloth:
|
@@ -12,7 +12,7 @@
|
|
12
12
|
# markdown = RDiscount.new("Hello World!")
|
13
13
|
# puts markdown.to_html
|
14
14
|
#
|
15
|
-
#
|
15
|
+
# == Replacing BlueCloth
|
16
16
|
#
|
17
17
|
# Inject RDiscount into your BlueCloth-using code by replacing your bluecloth
|
18
18
|
# require statements with the following:
|
data/rdiscount.gemspec
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'rdiscount'
|
3
|
-
s.version = '1.
|
3
|
+
s.version = '1.5.5'
|
4
4
|
s.summary = "Fast Implementation of Gruber's Markdown in C"
|
5
|
-
s.date = '2009-
|
5
|
+
s.date = '2009-11-13'
|
6
6
|
s.email = 'r@tomayko.com'
|
7
7
|
s.homepage = 'http://github.com/rtomayko/rdiscount'
|
8
8
|
s.has_rdoc = true
|
@@ -16,6 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
ext/Csio.c
|
17
17
|
ext/amalloc.h
|
18
18
|
ext/config.h
|
19
|
+
ext/css.c
|
19
20
|
ext/cstring.h
|
20
21
|
ext/docheader.c
|
21
22
|
ext/dumptree.c
|
@@ -28,6 +29,7 @@ Gem::Specification.new do |s|
|
|
28
29
|
ext/rdiscount.c
|
29
30
|
ext/resource.c
|
30
31
|
ext/toc.c
|
32
|
+
ext/xml.c
|
31
33
|
lib/markdown.rb
|
32
34
|
lib/rdiscount.rb
|
33
35
|
rdiscount.gemspec
|