bluecloth 2.0.7-x86-mswin32 → 2.0.11pre158-x86-mswin32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/.gemtest +0 -0
- data/History.md +4 -0
- data/LICENSE +1 -1
- data/Manifest.txt +103 -0
- data/README.md +103 -0
- data/Rakefile +95 -301
- data/ext/VERSION +1 -1
- data/ext/bluecloth.c +69 -23
- data/ext/bluecloth.h +13 -2
- data/ext/config.h +13 -2
- data/ext/css.c +14 -5
- data/ext/cstring.h +4 -2
- data/ext/docheader.c +13 -7
- data/ext/emmatch.c +188 -0
- data/ext/extconf.rb +7 -9
- data/ext/generate.c +333 -293
- data/ext/html5.c +24 -0
- data/ext/markdown.c +326 -185
- data/ext/markdown.h +52 -29
- data/ext/mkdio.c +82 -41
- data/ext/mkdio.h +44 -23
- data/ext/resource.c +4 -2
- data/ext/setup.c +47 -0
- data/ext/tags.c +123 -0
- data/ext/tags.h +19 -0
- data/lib/1.8/bluecloth_ext.so +0 -0
- data/lib/1.9/bluecloth_ext.so +0 -0
- data/lib/bluecloth.rb +77 -42
- data/spec/bluecloth/101_changes_spec.rb +18 -21
- data/spec/bluecloth/TEMPLATE +36 -0
- data/spec/bluecloth/autolinks_spec.rb +4 -7
- data/spec/bluecloth/blockquotes_spec.rb +20 -23
- data/spec/bluecloth/code_spans_spec.rb +2 -5
- data/spec/bluecloth/emphasis_spec.rb +2 -5
- data/spec/bluecloth/entities_spec.rb +2 -5
- data/spec/bluecloth/hrules_spec.rb +2 -5
- data/spec/bluecloth/images_spec.rb +2 -5
- data/spec/bluecloth/inline_html_spec.rb +26 -66
- data/spec/bluecloth/links_spec.rb +1 -5
- data/spec/bluecloth/lists_spec.rb +2 -5
- data/spec/bluecloth/paragraphs_spec.rb +2 -5
- data/spec/bluecloth/titles_spec.rb +2 -5
- data/spec/bluecloth_spec.rb +36 -22
- data/spec/bugfix_spec.rb +90 -10
- data/spec/contributions_spec.rb +2 -3
- data/spec/discount_spec.rb +50 -10
- data/spec/lib/helpers.rb +18 -117
- data/spec/lib/matchers.rb +7 -18
- data/spec/markdowntest_spec.rb +3 -39
- metadata +257 -143
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -387
- data/README +0 -81
- data/Rakefile.local +0 -41
- data/rake/191_compat.rb +0 -26
- data/rake/dependencies.rb +0 -76
- data/rake/helpers.rb +0 -435
- data/rake/hg.rb +0 -273
- data/rake/manual.rb +0 -782
- data/rake/packaging.rb +0 -123
- data/rake/publishing.rb +0 -274
- data/rake/rdoc.rb +0 -30
- data/rake/style.rb +0 -62
- data/rake/svn.rb +0 -668
- data/rake/testing.rb +0 -187
- data/rake/verifytask.rb +0 -64
data/ext/html5.c
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
/* block-level tags for passing html5 blocks through the blender
|
2
|
+
*/
|
3
|
+
#include "tags.h"
|
4
|
+
|
5
|
+
void
|
6
|
+
mkd_with_html5_tags()
|
7
|
+
{
|
8
|
+
static int populated = 0;
|
9
|
+
|
10
|
+
if ( populated ) return;
|
11
|
+
populated = 1;
|
12
|
+
|
13
|
+
mkd_prepare_tags();
|
14
|
+
|
15
|
+
mkd_define_tag("ASIDE", 0);
|
16
|
+
mkd_define_tag("FOOTER", 0);
|
17
|
+
mkd_define_tag("HEADER", 0);
|
18
|
+
mkd_define_tag("HGROUP", 0);
|
19
|
+
mkd_define_tag("NAV", 0);
|
20
|
+
mkd_define_tag("SECTION", 0);
|
21
|
+
mkd_define_tag("ARTICLE", 0);
|
22
|
+
|
23
|
+
mkd_sort_tags();
|
24
|
+
}
|
data/ext/markdown.c
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
* The redistribution terms are provided in the COPYRIGHT file that must
|
5
5
|
* be distributed with this source code.
|
6
6
|
*/
|
7
|
+
#include "config.h"
|
8
|
+
|
7
9
|
#include <stdio.h>
|
8
10
|
#include <string.h>
|
9
11
|
#include <stdarg.h>
|
@@ -11,51 +13,15 @@
|
|
11
13
|
#include <time.h>
|
12
14
|
#include <ctype.h>
|
13
15
|
|
14
|
-
#include "config.h"
|
15
|
-
|
16
16
|
#include "cstring.h"
|
17
17
|
#include "markdown.h"
|
18
18
|
#include "amalloc.h"
|
19
|
-
|
20
|
-
/* block-level tags for passing html blocks through the blender
|
21
|
-
*/
|
22
|
-
struct kw {
|
23
|
-
char *id;
|
24
|
-
int size;
|
25
|
-
int selfclose;
|
26
|
-
} ;
|
27
|
-
|
28
|
-
#define KW(x) { x, sizeof(x)-1, 0 }
|
29
|
-
#define SC(x) { x, sizeof(x)-1, 1 }
|
30
|
-
|
31
|
-
static struct kw blocktags[] = { KW("!--"), KW("STYLE"), KW("SCRIPT"),
|
32
|
-
KW("ADDRESS"), KW("BDO"), KW("BLOCKQUOTE"),
|
33
|
-
KW("CENTER"), KW("DFN"), KW("DIV"), KW("H1"),
|
34
|
-
KW("H2"), KW("H3"), KW("H4"), KW("H5"),
|
35
|
-
KW("H6"), KW("LISTING"), KW("NOBR"),
|
36
|
-
KW("UL"), KW("P"), KW("OL"), KW("DL"),
|
37
|
-
KW("PLAINTEXT"), KW("PRE"), KW("TABLE"),
|
38
|
-
KW("WBR"), KW("XMP"), SC("HR"), SC("BR"),
|
39
|
-
KW("IFRAME"), KW("MAP") };
|
40
|
-
#define SZTAGS (sizeof blocktags / sizeof blocktags[0])
|
41
|
-
#define MAXTAG 11 /* sizeof "BLOCKQUOTE" */
|
19
|
+
#include "tags.h"
|
42
20
|
|
43
21
|
typedef int (*stfu)(const void*,const void*);
|
44
22
|
|
45
23
|
typedef ANCHOR(Paragraph) ParagraphRoot;
|
46
24
|
|
47
|
-
|
48
|
-
/* case insensitive string sort (for qsort() and bsearch() of block tags)
|
49
|
-
*/
|
50
|
-
static int
|
51
|
-
casort(struct kw *a, struct kw *b)
|
52
|
-
{
|
53
|
-
if ( a->size != b->size )
|
54
|
-
return a->size - b->size;
|
55
|
-
return strncasecmp(a->id, b->id, b->size);
|
56
|
-
}
|
57
|
-
|
58
|
-
|
59
25
|
/* case insensitive string sort for Footnote tags.
|
60
26
|
*/
|
61
27
|
int
|
@@ -135,19 +101,28 @@ ___mkd_tidy(Cstring *t)
|
|
135
101
|
}
|
136
102
|
|
137
103
|
|
104
|
+
static struct kw comment = { "!--", 3, 0 };
|
105
|
+
|
138
106
|
static struct kw *
|
139
107
|
isopentag(Line *p)
|
140
108
|
{
|
141
109
|
int i=0, len;
|
142
|
-
|
110
|
+
char *line;
|
143
111
|
|
144
112
|
if ( !p ) return 0;
|
145
113
|
|
114
|
+
line = T(p->text);
|
146
115
|
len = S(p->text);
|
147
116
|
|
148
|
-
if ( len < 3 ||
|
117
|
+
if ( len < 3 || line[0] != '<' )
|
149
118
|
return 0;
|
150
119
|
|
120
|
+
if ( line[1] == '!' && line[2] == '-' && line[3] == '-' )
|
121
|
+
/* comments need special case handling, because
|
122
|
+
* the !-- doesn't need to end in a whitespace
|
123
|
+
*/
|
124
|
+
return &comment;
|
125
|
+
|
151
126
|
/* find how long the tag is so we can check to see if
|
152
127
|
* it's a block-level tag
|
153
128
|
*/
|
@@ -156,13 +131,8 @@ isopentag(Line *p)
|
|
156
131
|
&& !isspace(T(p->text)[i]); ++i )
|
157
132
|
;
|
158
133
|
|
159
|
-
key.id = T(p->text)+1;
|
160
|
-
key.size = i-1;
|
161
|
-
|
162
|
-
if ( ret = bsearch(&key, blocktags, SZTAGS, sizeof key, (stfu)casort))
|
163
|
-
return ret;
|
164
134
|
|
165
|
-
return
|
135
|
+
return mkd_search_tags(T(p->text)+1, i-1);
|
166
136
|
}
|
167
137
|
|
168
138
|
|
@@ -171,6 +141,8 @@ typedef struct _flo {
|
|
171
141
|
int i;
|
172
142
|
} FLO;
|
173
143
|
|
144
|
+
#define floindex(x) (x.i)
|
145
|
+
|
174
146
|
|
175
147
|
static int
|
176
148
|
flogetc(FLO *f)
|
@@ -186,15 +158,56 @@ flogetc(FLO *f)
|
|
186
158
|
}
|
187
159
|
|
188
160
|
|
161
|
+
static void
|
162
|
+
splitline(Line *t, int cutpoint)
|
163
|
+
{
|
164
|
+
if ( t && (cutpoint < S(t->text)) ) {
|
165
|
+
Line *tmp = calloc(1, sizeof *tmp);
|
166
|
+
|
167
|
+
tmp->next = t->next;
|
168
|
+
t->next = tmp;
|
169
|
+
|
170
|
+
tmp->dle = t->dle;
|
171
|
+
SUFFIX(tmp->text, T(t->text)+cutpoint, S(t->text)-cutpoint);
|
172
|
+
S(t->text) = cutpoint;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
|
177
|
+
static Line *
|
178
|
+
commentblock(Paragraph *p, int *unclosed)
|
179
|
+
{
|
180
|
+
Line *t, *ret;
|
181
|
+
char *end;
|
182
|
+
|
183
|
+
for ( t = p->text; t ; t = t->next) {
|
184
|
+
if ( end = strstr(T(t->text), "-->") ) {
|
185
|
+
splitline(t, 3 + (end - T(t->text)) );
|
186
|
+
ret = t->next;
|
187
|
+
t->next = 0;
|
188
|
+
return ret;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
*unclosed = 1;
|
192
|
+
return t;
|
193
|
+
|
194
|
+
}
|
195
|
+
|
196
|
+
|
189
197
|
static Line *
|
190
|
-
htmlblock(Paragraph *p, struct kw *tag)
|
198
|
+
htmlblock(Paragraph *p, struct kw *tag, int *unclosed)
|
191
199
|
{
|
192
200
|
Line *ret;
|
193
201
|
FLO f = { p->text, 0 };
|
194
202
|
int c;
|
195
203
|
int i, closing, depth=0;
|
196
204
|
|
197
|
-
|
205
|
+
*unclosed = 0;
|
206
|
+
|
207
|
+
if ( tag == &comment )
|
208
|
+
return commentblock(p, unclosed);
|
209
|
+
|
210
|
+
if ( tag->selfclose ) {
|
198
211
|
ret = f.t->next;
|
199
212
|
f.t->next = 0;
|
200
213
|
return ret;
|
@@ -230,8 +243,11 @@ htmlblock(Paragraph *p, struct kw *tag)
|
|
230
243
|
/* consume trailing gunk in close tag */
|
231
244
|
c = flogetc(&f);
|
232
245
|
}
|
246
|
+
if ( c == EOF )
|
247
|
+
break;
|
233
248
|
if ( !f.t )
|
234
249
|
return 0;
|
250
|
+
splitline(f.t, floindex(f));
|
235
251
|
ret = f.t->next;
|
236
252
|
f.t->next = 0;
|
237
253
|
return ret;
|
@@ -240,27 +256,11 @@ htmlblock(Paragraph *p, struct kw *tag)
|
|
240
256
|
}
|
241
257
|
}
|
242
258
|
}
|
259
|
+
*unclosed = 1;
|
243
260
|
return 0;
|
244
261
|
}
|
245
262
|
|
246
263
|
|
247
|
-
static Line *
|
248
|
-
comment(Paragraph *p)
|
249
|
-
{
|
250
|
-
Line *t, *ret;
|
251
|
-
|
252
|
-
for ( t = p->text; t ; t = t->next) {
|
253
|
-
if ( strstr(T(t->text), "-->") ) {
|
254
|
-
ret = t->next;
|
255
|
-
t->next = 0;
|
256
|
-
return ret;
|
257
|
-
}
|
258
|
-
}
|
259
|
-
return t;
|
260
|
-
|
261
|
-
}
|
262
|
-
|
263
|
-
|
264
264
|
/* tables look like
|
265
265
|
* header|header{|header}
|
266
266
|
* ------|------{|......}
|
@@ -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,7 +315,14 @@ isfootnote(Line *t)
|
|
315
315
|
static int
|
316
316
|
isquote(Line *t)
|
317
317
|
{
|
318
|
-
|
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;
|
319
326
|
}
|
320
327
|
|
321
328
|
|
@@ -355,6 +362,34 @@ ishr(Line *t)
|
|
355
362
|
}
|
356
363
|
|
357
364
|
|
365
|
+
static int
|
366
|
+
issetext(Line *t, int *htyp)
|
367
|
+
{
|
368
|
+
int i;
|
369
|
+
/* then check for setext-style HEADER
|
370
|
+
* ======
|
371
|
+
*/
|
372
|
+
|
373
|
+
if ( t->next ) {
|
374
|
+
char *q = T(t->next->text);
|
375
|
+
int last = S(t->next->text);
|
376
|
+
|
377
|
+
if ( (*q == '=') || (*q == '-') ) {
|
378
|
+
/* ignore trailing whitespace */
|
379
|
+
while ( (last > 1) && isspace(q[last-1]) )
|
380
|
+
--last;
|
381
|
+
|
382
|
+
for (i=1; i < last; i++)
|
383
|
+
if ( q[0] != q[i] )
|
384
|
+
return 0;
|
385
|
+
*htyp = SETEXT;
|
386
|
+
return 1;
|
387
|
+
}
|
388
|
+
}
|
389
|
+
return 0;
|
390
|
+
}
|
391
|
+
|
392
|
+
|
358
393
|
static int
|
359
394
|
ishdr(Line *t, int *htyp)
|
360
395
|
{
|
@@ -376,75 +411,116 @@ ishdr(Line *t, int *htyp)
|
|
376
411
|
return 1;
|
377
412
|
}
|
378
413
|
|
379
|
-
|
380
|
-
|
381
|
-
*/
|
414
|
+
return issetext(t, htyp);
|
415
|
+
}
|
382
416
|
|
383
|
-
if ( t->next ) {
|
384
|
-
char *q = T(t->next->text);
|
385
417
|
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
418
|
+
static Line*
|
419
|
+
is_discount_dt(Line *t, int *clip)
|
420
|
+
{
|
421
|
+
#if USE_DISCOUNT_DL
|
422
|
+
if ( t && t->next
|
423
|
+
&& (S(t->text) > 2)
|
424
|
+
&& (t->dle == 0)
|
425
|
+
&& (T(t->text)[0] == '=')
|
426
|
+
&& (T(t->text)[S(t->text)-1] == '=') ) {
|
427
|
+
if ( t->next->dle >= 4 ) {
|
428
|
+
*clip = 4;
|
429
|
+
return t;
|
392
430
|
}
|
431
|
+
else
|
432
|
+
return is_discount_dt(t->next, clip);
|
393
433
|
}
|
434
|
+
#endif
|
394
435
|
return 0;
|
395
436
|
}
|
396
437
|
|
397
438
|
|
398
439
|
static int
|
399
|
-
|
440
|
+
is_extra_dd(Line *t)
|
400
441
|
{
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
442
|
+
return (t->dle < 4) && (T(t->text)[t->dle] == ':')
|
443
|
+
&& isspace(T(t->text)[t->dle+1]);
|
444
|
+
}
|
445
|
+
|
446
|
+
|
447
|
+
static Line*
|
448
|
+
is_extra_dt(Line *t, int *clip)
|
449
|
+
{
|
450
|
+
#if USE_EXTRA_DL
|
451
|
+
int i;
|
452
|
+
|
453
|
+
if ( t && t->next && T(t->text)[0] != '='
|
454
|
+
&& T(t->text)[S(t->text)-1] != '=') {
|
455
|
+
Line *x;
|
456
|
+
|
457
|
+
if ( iscode(t) || blankline(t) || ishdr(t,&i) || ishr(t) )
|
458
|
+
return 0;
|
459
|
+
|
460
|
+
if ( (x = skipempty(t->next)) && is_extra_dd(x) ) {
|
461
|
+
*clip = x->dle+2;
|
462
|
+
return t;
|
463
|
+
}
|
464
|
+
|
465
|
+
if ( x=is_extra_dt(t->next, clip) )
|
466
|
+
return x;
|
467
|
+
}
|
410
468
|
#endif
|
469
|
+
return 0;
|
470
|
+
}
|
471
|
+
|
472
|
+
|
473
|
+
static Line*
|
474
|
+
isdefinition(Line *t, int *clip, int *kind)
|
475
|
+
{
|
476
|
+
Line *ret;
|
477
|
+
|
478
|
+
*kind = 1;
|
479
|
+
if ( ret = is_discount_dt(t,clip) )
|
480
|
+
return ret;
|
481
|
+
|
482
|
+
*kind=2;
|
483
|
+
return is_extra_dt(t,clip);
|
411
484
|
}
|
412
485
|
|
413
486
|
|
414
487
|
static int
|
415
|
-
islist(Line *t, int *
|
488
|
+
islist(Line *t, int *clip, DWORD flags, int *list_type)
|
416
489
|
{
|
417
490
|
int i, j;
|
418
491
|
char *q;
|
419
492
|
|
420
|
-
if ( iscode(t)
|
493
|
+
if ( /*iscode(t) ||*/ blankline(t) || ishdr(t,&i) || ishr(t) )
|
421
494
|
return 0;
|
422
495
|
|
423
|
-
if ( isdefinition(t) )
|
424
|
-
*trim = 4;
|
496
|
+
if ( !(flags & (MKD_NODLIST|MKD_STRICT)) && isdefinition(t,clip,list_type) )
|
425
497
|
return DL;
|
426
|
-
}
|
427
498
|
|
428
499
|
if ( strchr("*-+", T(t->text)[t->dle]) && isspace(T(t->text)[t->dle+1]) ) {
|
429
500
|
i = nextnonblank(t, t->dle+1);
|
430
|
-
*
|
431
|
-
|
501
|
+
*clip = (i > 4) ? 4 : i;
|
502
|
+
*list_type = UL;
|
503
|
+
return AL;
|
432
504
|
}
|
433
505
|
|
434
506
|
if ( (j = nextblank(t,t->dle)) > t->dle ) {
|
435
507
|
if ( T(t->text)[j-1] == '.' ) {
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
508
|
+
|
509
|
+
if ( !(flags & (MKD_NOALPHALIST|MKD_STRICT))
|
510
|
+
&& (j == t->dle + 2)
|
511
|
+
&& isalpha(T(t->text)[t->dle]) ) {
|
512
|
+
j = nextnonblank(t,j);
|
513
|
+
*clip = (j > 4) ? 4 : j;
|
514
|
+
*list_type = AL;
|
515
|
+
return AL;
|
516
|
+
}
|
517
|
+
|
443
518
|
strtoul(T(t->text)+t->dle, &q, 10);
|
444
519
|
if ( (q > T(t->text)+t->dle) && (q == T(t->text) + (j-1)) ) {
|
445
520
|
j = nextnonblank(t,j);
|
446
|
-
*
|
447
|
-
|
521
|
+
*clip = (j > 4) ? 4 : j;
|
522
|
+
*list_type = OL;
|
523
|
+
return AL;
|
448
524
|
}
|
449
525
|
}
|
450
526
|
}
|
@@ -475,7 +551,8 @@ headerblock(Paragraph *pp, int htyp)
|
|
475
551
|
* the leading and trailing `#`'s
|
476
552
|
*/
|
477
553
|
|
478
|
-
for (i=0; (T(p->text)[i] == T(p->text)[0]) && (i < S(p->text)-1)
|
554
|
+
for (i=0; (T(p->text)[i] == T(p->text)[0]) && (i < S(p->text)-1)
|
555
|
+
&& (i < 6); i++)
|
479
556
|
;
|
480
557
|
|
481
558
|
pp->hnumber = i;
|
@@ -539,27 +616,33 @@ centered(Line *first, Line *last)
|
|
539
616
|
|
540
617
|
|
541
618
|
static int
|
542
|
-
endoftextblock(Line *t, int toplevelblock)
|
619
|
+
endoftextblock(Line *t, int toplevelblock, DWORD flags)
|
543
620
|
{
|
544
621
|
int z;
|
545
622
|
|
546
|
-
if ( blankline(t)||isquote(t)||
|
623
|
+
if ( blankline(t)||isquote(t)||ishdr(t,&z)||ishr(t) )
|
624
|
+
return 1;
|
625
|
+
|
626
|
+
/* HORRIBLE STANDARDS KLUDGE: non-toplevel paragraphs absorb adjacent
|
627
|
+
* code blocks
|
628
|
+
*/
|
629
|
+
if ( toplevelblock && iscode(t) )
|
547
630
|
return 1;
|
548
631
|
|
549
632
|
/* HORRIBLE STANDARDS KLUDGE: Toplevel paragraphs eat absorb adjacent
|
550
633
|
* list items, but sublevel blocks behave properly.
|
551
634
|
*/
|
552
|
-
return toplevelblock ? 0 : islist(t,&z);
|
635
|
+
return toplevelblock ? 0 : islist(t,&z,flags, &z);
|
553
636
|
}
|
554
637
|
|
555
638
|
|
556
639
|
static Line *
|
557
|
-
textblock(Paragraph *p, int toplevel)
|
640
|
+
textblock(Paragraph *p, int toplevel, DWORD flags)
|
558
641
|
{
|
559
642
|
Line *t, *next;
|
560
643
|
|
561
644
|
for ( t = p->text; t ; t = next ) {
|
562
|
-
if ( ((next = t->next) == 0) || endoftextblock(next, toplevel) ) {
|
645
|
+
if ( ((next = t->next) == 0) || endoftextblock(next, toplevel, flags) ) {
|
563
646
|
p->align = centered(p->text, t);
|
564
647
|
t->next = 0;
|
565
648
|
return next;
|
@@ -586,27 +669,32 @@ szmarkerclass(char *p)
|
|
586
669
|
* check if the first line of a quoted block is the special div-not-quote
|
587
670
|
* marker %[kind:]name%
|
588
671
|
*/
|
672
|
+
#define iscsschar(c) (isalpha(c) || (c == '-') || (c == '_') )
|
673
|
+
|
589
674
|
static int
|
590
|
-
isdivmarker(Line *p, int start)
|
675
|
+
isdivmarker(Line *p, int start, DWORD flags)
|
591
676
|
{
|
592
|
-
|
593
|
-
|
594
|
-
int len = S(p->text);
|
595
|
-
int i;
|
677
|
+
char *s;
|
678
|
+
int last, i;
|
596
679
|
|
597
|
-
if (
|
680
|
+
if ( flags & (MKD_NODIVQUOTE|MKD_STRICT) )
|
681
|
+
return 0;
|
682
|
+
|
683
|
+
last= S(p->text) - (1 + start);
|
684
|
+
s = T(p->text) + start;
|
685
|
+
|
686
|
+
if ( (last <= 0) || (*s != '%') || (s[last] != '%') )
|
687
|
+
return 0;
|
598
688
|
|
599
|
-
i = szmarkerclass(s+
|
600
|
-
len -= start+1;
|
689
|
+
i = szmarkerclass(s+1);
|
601
690
|
|
602
|
-
|
603
|
-
|
691
|
+
if ( !iscsschar(s[i+1]) )
|
692
|
+
return 0;
|
693
|
+
while ( ++i < last )
|
694
|
+
if ( !(isdigit(s[i]) || iscsschar(s[i])) )
|
604
695
|
return 0;
|
605
696
|
|
606
697
|
return 1;
|
607
|
-
#else
|
608
|
-
return 0;
|
609
|
-
#endif
|
610
698
|
}
|
611
699
|
|
612
700
|
|
@@ -622,27 +710,36 @@ isdivmarker(Line *p, int start)
|
|
622
710
|
* way the markdown sample web form at Daring Fireball works.
|
623
711
|
*/
|
624
712
|
static Line *
|
625
|
-
quoteblock(Paragraph *p)
|
713
|
+
quoteblock(Paragraph *p, DWORD flags)
|
626
714
|
{
|
627
715
|
Line *t, *q;
|
628
716
|
int qp;
|
629
717
|
|
630
718
|
for ( t = p->text; t ; t = q ) {
|
631
719
|
if ( isquote(t) ) {
|
632
|
-
|
720
|
+
/* clip leading spaces */
|
721
|
+
for (qp = 0; T(t->text)[qp] != '>'; qp ++)
|
722
|
+
/* assert: the first nonblank character on this line
|
723
|
+
* will be a >
|
724
|
+
*/;
|
725
|
+
/* clip '>' */
|
726
|
+
qp++;
|
727
|
+
/* clip next space, if any */
|
728
|
+
if ( T(t->text)[qp] == ' ' )
|
729
|
+
qp++;
|
633
730
|
CLIP(t->text, 0, qp);
|
634
731
|
t->dle = mkd_firstnonblank(t);
|
635
732
|
}
|
636
733
|
|
637
734
|
q = skipempty(t->next);
|
638
735
|
|
639
|
-
if ( (q == 0) || ((q != t->next) && (!isquote(q) || isdivmarker(q,1))) ) {
|
736
|
+
if ( (q == 0) || ((q != t->next) && (!isquote(q) || isdivmarker(q,1,flags))) ) {
|
640
737
|
___mkd_freeLineRange(t, q);
|
641
738
|
t = q;
|
642
739
|
break;
|
643
740
|
}
|
644
741
|
}
|
645
|
-
if ( isdivmarker(p->text,0) ) {
|
742
|
+
if ( isdivmarker(p->text,0,flags) ) {
|
646
743
|
char *prefix = "class";
|
647
744
|
int i;
|
648
745
|
|
@@ -685,6 +782,8 @@ tableblock(Paragraph *p)
|
|
685
782
|
static Paragraph *Pp(ParagraphRoot *, Line *, int);
|
686
783
|
static Paragraph *compile(Line *, int, MMIOT *);
|
687
784
|
|
785
|
+
typedef int (*linefn)(Line *);
|
786
|
+
|
688
787
|
|
689
788
|
/*
|
690
789
|
* pull in a list block. A list block starts with a list marker and
|
@@ -693,7 +792,7 @@ static Paragraph *compile(Line *, int, MMIOT *);
|
|
693
792
|
* marker, but multiple paragraphs need to start with a 4-space indent.
|
694
793
|
*/
|
695
794
|
static Line *
|
696
|
-
listitem(Paragraph *p, int indent)
|
795
|
+
listitem(Paragraph *p, int indent, DWORD flags, linefn check)
|
697
796
|
{
|
698
797
|
Line *t, *q;
|
699
798
|
int clip = indent;
|
@@ -709,8 +808,9 @@ listitem(Paragraph *p, int indent)
|
|
709
808
|
}
|
710
809
|
|
711
810
|
/* after a blank line, the next block needs to start with a line
|
712
|
-
* that's indented 4
|
713
|
-
*
|
811
|
+
* that's indented 4(? -- reference implementation allows a 1
|
812
|
+
* character indent, but that has unfortunate side effects here)
|
813
|
+
* spaces, but after that the line doesn't need any indentation
|
714
814
|
*/
|
715
815
|
if ( q != t->next ) {
|
716
816
|
if (q->dle < indent) {
|
@@ -718,10 +818,14 @@ listitem(Paragraph *p, int indent)
|
|
718
818
|
t->next = 0;
|
719
819
|
return q;
|
720
820
|
}
|
721
|
-
indent
|
821
|
+
/* indent at least 2, and at most as
|
822
|
+
* as far as the initial line was indented. */
|
823
|
+
indent = clip ? clip : 2;
|
722
824
|
}
|
723
825
|
|
724
|
-
if ( (q->dle < indent) && (ishr(q) || islist(q,&z
|
826
|
+
if ( (q->dle < indent) && (ishr(q) || islist(q,&z,flags,&z)
|
827
|
+
|| (check && (*check)(q)))
|
828
|
+
&& !issetext(q,&z) ) {
|
725
829
|
q = t->next;
|
726
830
|
t->next = 0;
|
727
831
|
return q;
|
@@ -734,39 +838,81 @@ listitem(Paragraph *p, int indent)
|
|
734
838
|
|
735
839
|
|
736
840
|
static Line *
|
737
|
-
|
841
|
+
definition_block(Paragraph *top, int clip, MMIOT *f, int kind)
|
738
842
|
{
|
739
843
|
ParagraphRoot d = { 0, 0 };
|
740
844
|
Paragraph *p;
|
741
|
-
Line *q = top->text, *text, *
|
742
|
-
int
|
743
|
-
para = 0,
|
744
|
-
ltype;
|
845
|
+
Line *q = top->text, *text = 0, *labels;
|
846
|
+
int z, para;
|
745
847
|
|
746
|
-
while ((
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
848
|
+
while (( labels = q )) {
|
849
|
+
|
850
|
+
if ( (q = isdefinition(labels, &z, &kind)) == 0 )
|
851
|
+
break;
|
852
|
+
|
853
|
+
if ( (text = skipempty(q->next)) == 0 )
|
854
|
+
break;
|
855
|
+
|
856
|
+
if (( para = (text != q->next) ))
|
857
|
+
___mkd_freeLineRange(q, text);
|
858
|
+
|
859
|
+
q->next = 0;
|
860
|
+
if ( kind == 1 /* discount dl */ )
|
861
|
+
for ( q = labels; q; q = q->next ) {
|
862
|
+
CLIP(q->text, 0, 1);
|
863
|
+
S(q->text)--;
|
756
864
|
}
|
865
|
+
|
866
|
+
dd_block:
|
867
|
+
p = Pp(&d, text, LISTITEM);
|
868
|
+
|
869
|
+
text = listitem(p, clip, f->flags, (kind==2) ? is_extra_dd : 0);
|
870
|
+
p->down = compile(p->text, 0, f);
|
871
|
+
p->text = labels; labels = 0;
|
872
|
+
|
873
|
+
if ( para && p->down ) p->down->align = PARA;
|
874
|
+
|
875
|
+
if ( (q = skipempty(text)) == 0 )
|
876
|
+
break;
|
877
|
+
|
878
|
+
if (( para = (q != text) )) {
|
879
|
+
Line anchor;
|
880
|
+
|
881
|
+
anchor.next = text;
|
882
|
+
___mkd_freeLineRange(&anchor,q);
|
883
|
+
text = q;
|
884
|
+
|
757
885
|
}
|
758
|
-
else label = 0;
|
759
886
|
|
887
|
+
if ( kind == 2 && is_extra_dd(q) )
|
888
|
+
goto dd_block;
|
889
|
+
}
|
890
|
+
top->text = 0;
|
891
|
+
top->down = T(d);
|
892
|
+
return text;
|
893
|
+
}
|
894
|
+
|
895
|
+
|
896
|
+
static Line *
|
897
|
+
enumerated_block(Paragraph *top, int clip, MMIOT *f, int list_class)
|
898
|
+
{
|
899
|
+
ParagraphRoot d = { 0, 0 };
|
900
|
+
Paragraph *p;
|
901
|
+
Line *q = top->text, *text;
|
902
|
+
int para = 0, z;
|
903
|
+
|
904
|
+
while (( text = q )) {
|
905
|
+
|
760
906
|
p = Pp(&d, text, LISTITEM);
|
761
|
-
text = listitem(p,
|
907
|
+
text = listitem(p, clip, f->flags, 0);
|
762
908
|
|
763
909
|
p->down = compile(p->text, 0, f);
|
764
|
-
p->text =
|
910
|
+
p->text = 0;
|
765
911
|
|
766
|
-
if ( para &&
|
912
|
+
if ( para && p->down ) p->down->align = PARA;
|
767
913
|
|
768
|
-
if (
|
769
|
-
|
914
|
+
if ( (q = skipempty(text)) == 0
|
915
|
+
|| islist(q, &clip, f->flags, &z) != list_class )
|
770
916
|
break;
|
771
917
|
|
772
918
|
if ( para = (q != text) ) {
|
@@ -774,9 +920,9 @@ listblock(Paragraph *top, int trim, MMIOT *f)
|
|
774
920
|
|
775
921
|
anchor.next = text;
|
776
922
|
___mkd_freeLineRange(&anchor, q);
|
777
|
-
}
|
778
923
|
|
779
|
-
|
924
|
+
if ( p->down ) p->down->align = PARA;
|
925
|
+
}
|
780
926
|
}
|
781
927
|
top->text = 0;
|
782
928
|
top->down = T(d);
|
@@ -908,10 +1054,10 @@ compile_document(Line *ptr, MMIOT *f)
|
|
908
1054
|
ANCHOR(Line) source = { 0, 0 };
|
909
1055
|
Paragraph *p = 0;
|
910
1056
|
struct kw *tag;
|
911
|
-
int eaten;
|
1057
|
+
int eaten, unclosed;
|
912
1058
|
|
913
1059
|
while ( ptr ) {
|
914
|
-
if ( !(f->flags &
|
1060
|
+
if ( !(f->flags & MKD_NOHTML) && (tag = isopentag(ptr)) ) {
|
915
1061
|
/* If we encounter a html/style block, compile and save all
|
916
1062
|
* of the cached source BEFORE processing the html/style.
|
917
1063
|
*/
|
@@ -922,10 +1068,12 @@ compile_document(Line *ptr, MMIOT *f)
|
|
922
1068
|
T(source) = E(source) = 0;
|
923
1069
|
}
|
924
1070
|
p = Pp(&d, ptr, strcmp(tag->id, "STYLE") == 0 ? STYLE : HTML);
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
1071
|
+
ptr = htmlblock(p, tag, &unclosed);
|
1072
|
+
if ( unclosed ) {
|
1073
|
+
p->typ = SOURCE;
|
1074
|
+
p->down = compile(p->text, 1, f);
|
1075
|
+
p->text = 0;
|
1076
|
+
}
|
929
1077
|
}
|
930
1078
|
else if ( isfootnote(ptr) ) {
|
931
1079
|
/* footnotes, like cats, sleep anywhere; pull them
|
@@ -967,7 +1115,7 @@ compile(Line *ptr, int toplevel, MMIOT *f)
|
|
967
1115
|
Line *r;
|
968
1116
|
int para = toplevel;
|
969
1117
|
int blocks = 0;
|
970
|
-
int hdr_type, list_type, indent;
|
1118
|
+
int hdr_type, list_type, list_class, indent;
|
971
1119
|
|
972
1120
|
ptr = consume(ptr, ¶);
|
973
1121
|
|
@@ -990,13 +1138,19 @@ compile(Line *ptr, int toplevel, MMIOT *f)
|
|
990
1138
|
ptr = ptr->next;
|
991
1139
|
___mkd_freeLine(r);
|
992
1140
|
}
|
993
|
-
else if ((
|
994
|
-
|
995
|
-
|
1141
|
+
else if (( list_class = islist(ptr, &indent, f->flags, &list_type) )) {
|
1142
|
+
if ( list_class == DL ) {
|
1143
|
+
p = Pp(&d, ptr, DL);
|
1144
|
+
ptr = definition_block(p, indent, f, list_type);
|
1145
|
+
}
|
1146
|
+
else {
|
1147
|
+
p = Pp(&d, ptr, list_type);
|
1148
|
+
ptr = enumerated_block(p, indent, f, list_class);
|
1149
|
+
}
|
996
1150
|
}
|
997
1151
|
else if ( isquote(ptr) ) {
|
998
1152
|
p = Pp(&d, ptr, QUOTE);
|
999
|
-
ptr = quoteblock(p);
|
1153
|
+
ptr = quoteblock(p, f->flags);
|
1000
1154
|
p->down = compile(p->text, 1, f);
|
1001
1155
|
p->text = 0;
|
1002
1156
|
}
|
@@ -1004,13 +1158,13 @@ compile(Line *ptr, int toplevel, MMIOT *f)
|
|
1004
1158
|
p = Pp(&d, ptr, HDR);
|
1005
1159
|
ptr = headerblock(p, hdr_type);
|
1006
1160
|
}
|
1007
|
-
else if ( istable(ptr) && !(f->flags & (
|
1161
|
+
else if ( istable(ptr) && !(f->flags & (MKD_STRICT|MKD_NOTABLES)) ) {
|
1008
1162
|
p = Pp(&d, ptr, TABLE);
|
1009
1163
|
ptr = tableblock(p);
|
1010
1164
|
}
|
1011
1165
|
else {
|
1012
1166
|
p = Pp(&d, ptr, MARKUP);
|
1013
|
-
ptr = textblock(p, toplevel);
|
1167
|
+
ptr = textblock(p, toplevel, f->flags);
|
1014
1168
|
}
|
1015
1169
|
|
1016
1170
|
if ( (para||toplevel) && !p->align )
|
@@ -1028,19 +1182,6 @@ compile(Line *ptr, int toplevel, MMIOT *f)
|
|
1028
1182
|
}
|
1029
1183
|
|
1030
1184
|
|
1031
|
-
static void
|
1032
|
-
initialize()
|
1033
|
-
{
|
1034
|
-
static int first = 1;
|
1035
|
-
|
1036
|
-
if ( first-- > 0 ) {
|
1037
|
-
first = 0;
|
1038
|
-
INITRNG(time(0));
|
1039
|
-
qsort(blocktags, SZTAGS, sizeof blocktags[0], (stfu)casort);
|
1040
|
-
}
|
1041
|
-
}
|
1042
|
-
|
1043
|
-
|
1044
1185
|
/*
|
1045
1186
|
* the guts of the markdown() function, ripped out so I can do
|
1046
1187
|
* debugging.
|
@@ -1050,7 +1191,7 @@ initialize()
|
|
1050
1191
|
* prepare and compile `text`, returning a Paragraph tree.
|
1051
1192
|
*/
|
1052
1193
|
int
|
1053
|
-
mkd_compile(Document *doc,
|
1194
|
+
mkd_compile(Document *doc, DWORD flags)
|
1054
1195
|
{
|
1055
1196
|
if ( !doc )
|
1056
1197
|
return 0;
|
@@ -1060,13 +1201,13 @@ mkd_compile(Document *doc, int flags)
|
|
1060
1201
|
|
1061
1202
|
doc->compiled = 1;
|
1062
1203
|
memset(doc->ctx, 0, sizeof(MMIOT) );
|
1063
|
-
doc->ctx->
|
1064
|
-
doc->ctx->
|
1204
|
+
doc->ctx->cb = &(doc->cb);
|
1205
|
+
doc->ctx->flags = flags & USER_FLAGS;
|
1065
1206
|
CREATE(doc->ctx->in);
|
1066
1207
|
doc->ctx->footnotes = malloc(sizeof doc->ctx->footnotes[0]);
|
1067
1208
|
CREATE(*doc->ctx->footnotes);
|
1068
1209
|
|
1069
|
-
|
1210
|
+
mkd_initialize();
|
1070
1211
|
|
1071
1212
|
doc->code = compile_document(T(doc->content), doc->ctx);
|
1072
1213
|
qsort(T(*doc->ctx->footnotes), S(*doc->ctx->footnotes),
|