bluecloth 2.0.7 → 2.0.9
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/ChangeLog +36 -6
- data/Rakefile +46 -26
- data/Rakefile.local +13 -6
- data/ext/VERSION +1 -1
- data/ext/bluecloth.c +46 -21
- data/ext/bluecloth.h +13 -2
- data/ext/cstring.h +3 -1
- data/ext/emmatch.c +188 -0
- data/ext/generate.c +203 -248
- data/ext/html5.c +24 -0
- data/ext/markdown.c +122 -98
- data/ext/markdown.h +16 -2
- data/ext/mkdio.c +43 -9
- data/ext/mkdio.h +11 -0
- data/ext/resource.c +1 -1
- data/ext/tags.c +110 -0
- data/ext/tags.h +18 -0
- data/lib/bluecloth.rb +33 -26
- data/rake/documentation.rb +115 -0
- data/rake/helpers.rb +375 -308
- data/rake/hg.rb +17 -3
- data/rake/manual.rb +11 -6
- data/rake/packaging.rb +7 -1
- data/rake/publishing.rb +162 -88
- data/spec/bluecloth/101_changes_spec.rb +1 -0
- data/spec/bluecloth/autolinks_spec.rb +1 -0
- data/spec/bluecloth/blockquotes_spec.rb +1 -0
- data/spec/bluecloth/code_spans_spec.rb +1 -0
- data/spec/bluecloth/emphasis_spec.rb +1 -0
- data/spec/bluecloth/entities_spec.rb +1 -0
- data/spec/bluecloth/hrules_spec.rb +1 -0
- data/spec/bluecloth/images_spec.rb +1 -0
- data/spec/bluecloth/inline_html_spec.rb +25 -61
- data/spec/bluecloth/lists_spec.rb +1 -0
- data/spec/bluecloth/paragraphs_spec.rb +1 -0
- data/spec/bluecloth/titles_spec.rb +1 -0
- data/spec/bluecloth_spec.rb +22 -6
- data/spec/bugfix_spec.rb +79 -2
- data/spec/contributions_spec.rb +1 -0
- data/spec/discount_spec.rb +46 -2
- data/spec/lib/helpers.rb +8 -8
- data/spec/lib/matchers.rb +5 -17
- data/spec/markdowntest_spec.rb +2 -34
- metadata +48 -17
- metadata.gz.sig +0 -0
- data/rake/rdoc.rb +0 -30
data/ext/cstring.h
CHANGED
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
@@ -18,11 +18,9 @@
|
|
18
18
|
#include "amalloc.h"
|
19
19
|
|
20
20
|
typedef int (*stfu)(const void*,const void*);
|
21
|
-
|
21
|
+
typedef void (*spanhandler)(MMIOT*,int);
|
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
|
|
@@ -182,118 +180,6 @@ Qem(MMIOT *f, char c, int count)
|
|
182
180
|
}
|
183
181
|
|
184
182
|
|
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
183
|
/* generate html from a markup fragment
|
298
184
|
*/
|
299
185
|
void
|
@@ -304,7 +190,7 @@ ___mkd_reparse(char *bfr, int size, int flags, MMIOT *f)
|
|
304
190
|
___mkd_initmmiot(&sub, f->footnotes);
|
305
191
|
|
306
192
|
sub.flags = f->flags | flags;
|
307
|
-
sub.
|
193
|
+
sub.cb = f->cb;
|
308
194
|
|
309
195
|
push(bfr, size, &sub);
|
310
196
|
EXPAND(sub.in) = 0;
|
@@ -345,6 +231,8 @@ puturl(char *s, int size, MMIOT *f, int display)
|
|
345
231
|
Qstring("%22", f);
|
346
232
|
else if ( isalnum(c) || ispunct(c) || (display && isspace(c)) )
|
347
233
|
Qchar(c, f);
|
234
|
+
else if ( c == 003 ) /* untokenize ^C */
|
235
|
+
Qstring(" ", f);
|
348
236
|
else
|
349
237
|
Qprintf(f, "%%%02X", c);
|
350
238
|
}
|
@@ -374,12 +262,12 @@ parenthetical(int in, int out, MMIOT *f)
|
|
374
262
|
for ( indent=1,size=0; indent; size++ ) {
|
375
263
|
if ( (c = pull(f)) == EOF )
|
376
264
|
return EOF;
|
377
|
-
else if ( c == in )
|
378
|
-
++indent;
|
379
|
-
else if ( (c == '\\') && (peek(f,1) == out) ) {
|
265
|
+
else if ( (c == '\\') && (peek(f,1) == out || peek(f,1) == in) ) {
|
380
266
|
++size;
|
381
267
|
pull(f);
|
382
268
|
}
|
269
|
+
else if ( c == in )
|
270
|
+
++indent;
|
383
271
|
else if ( c == out )
|
384
272
|
--indent;
|
385
273
|
}
|
@@ -512,27 +400,28 @@ linkyurl(MMIOT *f, int image, Footnote *p)
|
|
512
400
|
|
513
401
|
/* prefixes for <automatic links>
|
514
402
|
*/
|
515
|
-
static struct {
|
403
|
+
static struct _protocol {
|
516
404
|
char *name;
|
517
405
|
int nlen;
|
518
406
|
} protocol[] = {
|
519
407
|
#define _aprotocol(x) { x, (sizeof x)-1 }
|
520
|
-
_aprotocol( "http://" ),
|
521
408
|
_aprotocol( "https://" ),
|
522
|
-
_aprotocol( "
|
409
|
+
_aprotocol( "http://" ),
|
523
410
|
_aprotocol( "news://" ),
|
411
|
+
_aprotocol( "ftp://" ),
|
524
412
|
#undef _aprotocol
|
525
413
|
};
|
526
414
|
#define NRPROTOCOLS (sizeof protocol / sizeof protocol[0])
|
527
415
|
|
528
416
|
|
529
417
|
static int
|
530
|
-
isautoprefix(char *text)
|
418
|
+
isautoprefix(char *text, int size)
|
531
419
|
{
|
532
420
|
int i;
|
421
|
+
struct _protocol *p;
|
533
422
|
|
534
|
-
for (i=0; i < NRPROTOCOLS; i++)
|
535
|
-
if ( strncasecmp(text,
|
423
|
+
for (i=0, p=protocol; i < NRPROTOCOLS; i++, p++)
|
424
|
+
if ( (size >= p->nlen) && strncasecmp(text, p->name, p->nlen) == 0 )
|
536
425
|
return 1;
|
537
426
|
return 0;
|
538
427
|
}
|
@@ -569,9 +458,10 @@ static linkytype linkt = { 0, 0, "<a href=\"", "\"",
|
|
569
458
|
*/
|
570
459
|
static linkytype specials[] = {
|
571
460
|
{ "id:", 3, "<a id=\"", "\"", 0, ">", "</a>", 0, IS_URL },
|
572
|
-
{ "class:", 6, "<span class=\"", "\"", 0, ">", "</span>", 0, 0 },
|
573
461
|
{ "raw:", 4, 0, 0, 0, 0, 0, DENY_HTML, 0 },
|
462
|
+
{ "lang:", 5, "<span lang=\"", "\"", 0, ">", "</span>", 0, 0 },
|
574
463
|
{ "abbr:", 5, "<abbr title=\"", "\"", 0, ">", "</abbr>", 0, 0 },
|
464
|
+
{ "class:", 6, "<span class=\"", "\"", 0, ">", "</span>", 0, 0 },
|
575
465
|
} ;
|
576
466
|
|
577
467
|
#define NR(x) (sizeof x / sizeof x[0])
|
@@ -584,8 +474,7 @@ pseudo(Cstring t)
|
|
584
474
|
int i;
|
585
475
|
linkytype *r;
|
586
476
|
|
587
|
-
for ( i=0; i < NR(specials); i++ ) {
|
588
|
-
r = &specials[i];
|
477
|
+
for ( i=0, r=specials; i < NR(specials); i++,r++ ) {
|
589
478
|
if ( (S(t) > r->szpat) && (strncasecmp(T(t), r->pat, r->szpat) == 0) )
|
590
479
|
return r;
|
591
480
|
}
|
@@ -593,6 +482,36 @@ pseudo(Cstring t)
|
|
593
482
|
}
|
594
483
|
|
595
484
|
|
485
|
+
/* print out the start of an `img' or `a' tag, applying callbacks as needed.
|
486
|
+
*/
|
487
|
+
static void
|
488
|
+
printlinkyref(MMIOT *f, linkytype *tag, char *link, int size)
|
489
|
+
{
|
490
|
+
char *edit;
|
491
|
+
|
492
|
+
Qstring(tag->link_pfx, f);
|
493
|
+
|
494
|
+
if ( tag->kind & IS_URL ) {
|
495
|
+
if ( f->cb->e_url && (edit = (*f->cb->e_url)(link, size, f->cb->e_data)) ) {
|
496
|
+
puturl(edit, strlen(edit), f, 0);
|
497
|
+
if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data);
|
498
|
+
}
|
499
|
+
else
|
500
|
+
puturl(link + tag->szpat, size - tag->szpat, f, 0);
|
501
|
+
}
|
502
|
+
else
|
503
|
+
___mkd_reparse(link + tag->szpat, size - tag->szpat, INSIDE_TAG, f);
|
504
|
+
|
505
|
+
Qstring(tag->link_sfx, f);
|
506
|
+
|
507
|
+
if ( f->cb->e_flags && (edit = (*f->cb->e_flags)(link, size, f->cb->e_data)) ) {
|
508
|
+
Qchar(' ', f);
|
509
|
+
Qstring(edit, f);
|
510
|
+
if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data);
|
511
|
+
}
|
512
|
+
} /* printlinkyref */
|
513
|
+
|
514
|
+
|
596
515
|
/* print out a linky (or fail if it's Not Allowed)
|
597
516
|
*/
|
598
517
|
static int
|
@@ -608,11 +527,11 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
|
|
608
527
|
}
|
609
528
|
else if ( (f->flags & SAFELINK) && T(ref->link)
|
610
529
|
&& (T(ref->link)[0] != '/')
|
611
|
-
&& !isautoprefix(T(ref->link)) )
|
530
|
+
&& !isautoprefix(T(ref->link), S(ref->link)) )
|
612
531
|
/* if SAFELINK, only accept links that are local or
|
613
532
|
* a well-known protocol
|
614
533
|
*/
|
615
|
-
|
534
|
+
return 0;
|
616
535
|
else
|
617
536
|
tag = &linkt;
|
618
537
|
|
@@ -620,21 +539,11 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
|
|
620
539
|
return 0;
|
621
540
|
|
622
541
|
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);
|
542
|
+
printlinkyref(f, tag, T(ref->link), S(ref->link));
|
634
543
|
|
635
|
-
if ( tag->WxH) {
|
636
|
-
if ( ref->height) Qprintf(f," height=\"%d\"", ref->height);
|
637
|
-
if ( ref->width) Qprintf(f, " width=\"%d\"", ref->width);
|
544
|
+
if ( tag->WxH ) {
|
545
|
+
if ( ref->height ) Qprintf(f," height=\"%d\"", ref->height);
|
546
|
+
if ( ref->width ) Qprintf(f, " width=\"%d\"", ref->width);
|
638
547
|
}
|
639
548
|
|
640
549
|
if ( S(ref->title) ) {
|
@@ -677,7 +586,7 @@ linkylinky(int image, MMIOT *f)
|
|
677
586
|
}
|
678
587
|
else {
|
679
588
|
int goodlink, implicit_mark = mmiottell(f);
|
680
|
-
|
589
|
+
|
681
590
|
if ( eatspace(f) == '[' ) {
|
682
591
|
pull(f); /* consume leading '[' */
|
683
592
|
goodlink = linkylabel(f, &key.tag);
|
@@ -742,6 +651,98 @@ mangle(char *s, int len, MMIOT *f)
|
|
742
651
|
}
|
743
652
|
|
744
653
|
|
654
|
+
/* nrticks() -- count up a row of tick marks
|
655
|
+
*/
|
656
|
+
static int
|
657
|
+
nrticks(int offset, int tickchar, MMIOT *f)
|
658
|
+
{
|
659
|
+
int tick = 0;
|
660
|
+
|
661
|
+
while ( peek(f, offset+tick) == tickchar ) tick++;
|
662
|
+
|
663
|
+
return tick;
|
664
|
+
} /* nrticks */
|
665
|
+
|
666
|
+
|
667
|
+
/* matchticks() -- match a certain # of ticks, and if that fails
|
668
|
+
* match the largest subset of those ticks.
|
669
|
+
*
|
670
|
+
* if a subset was matched, return the # of ticks
|
671
|
+
* that were matched.
|
672
|
+
*/
|
673
|
+
static int
|
674
|
+
matchticks(MMIOT *f, int tickchar, int ticks, int *endticks)
|
675
|
+
{
|
676
|
+
int size, count, c;
|
677
|
+
int subsize=0, subtick=0;
|
678
|
+
|
679
|
+
*endticks = ticks;
|
680
|
+
for (size = 0; (c=peek(f,size+ticks)) != EOF; size ++) {
|
681
|
+
if ( (c == tickchar) && ( count = nrticks(size+ticks,tickchar,f)) ) {
|
682
|
+
if ( count == ticks )
|
683
|
+
return size;
|
684
|
+
else if ( count ) {
|
685
|
+
if ( (count > subtick) && (count < ticks) ) {
|
686
|
+
subsize = size;
|
687
|
+
subtick = count;
|
688
|
+
}
|
689
|
+
size += count;
|
690
|
+
}
|
691
|
+
}
|
692
|
+
}
|
693
|
+
if ( subsize ) {
|
694
|
+
*endticks = subtick;
|
695
|
+
return subsize;
|
696
|
+
}
|
697
|
+
return 0;
|
698
|
+
} /* matchticks */
|
699
|
+
|
700
|
+
|
701
|
+
/* code() -- write a string out as code. The only characters that have
|
702
|
+
* special meaning in a code block are * `<' and `&' , which
|
703
|
+
* are /always/ expanded to < and &
|
704
|
+
*/
|
705
|
+
static void
|
706
|
+
code(MMIOT *f, char *s, int length)
|
707
|
+
{
|
708
|
+
int i,c;
|
709
|
+
|
710
|
+
for ( i=0; i < length; i++ )
|
711
|
+
if ( (c = s[i]) == 003) /* ^C: expand back to 2 spaces */
|
712
|
+
Qstring(" ", f);
|
713
|
+
else
|
714
|
+
cputc(c, f);
|
715
|
+
} /* code */
|
716
|
+
|
717
|
+
|
718
|
+
/* delspan() -- write out a chunk of text, blocking with <del>...</del>
|
719
|
+
*/
|
720
|
+
static void
|
721
|
+
delspan(MMIOT *f, int size)
|
722
|
+
{
|
723
|
+
Qstring("<del>", f);
|
724
|
+
___mkd_reparse(cursor(f)-1, size, 0, f);
|
725
|
+
Qstring("</del>", f);
|
726
|
+
}
|
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;
|
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;
|
@@ -981,6 +984,11 @@ static struct smarties {
|
|
981
984
|
} smarties[] = {
|
982
985
|
{ '\'', "'s>", "rsquo", 0 },
|
983
986
|
{ '\'', "'t>", "rsquo", 0 },
|
987
|
+
{ '\'', "'re>", "rsquo", 0 },
|
988
|
+
{ '\'', "'ll>", "rsquo", 0 },
|
989
|
+
{ '\'', "'ve>", "rsquo", 0 },
|
990
|
+
{ '\'', "'m>", "rsquo", 0 },
|
991
|
+
{ '\'', "'d>", "rsquo", 0 },
|
984
992
|
{ '-', "--", "mdash", 1 },
|
985
993
|
{ '-', "<->", "ndash", 0 },
|
986
994
|
{ '.', "...", "hellip", 2 },
|
@@ -1049,6 +1057,30 @@ smartypants(int c, int *flags, MMIOT *f)
|
|
1049
1057
|
} /* smartypants */
|
1050
1058
|
|
1051
1059
|
|
1060
|
+
/* process a body of text encased in some sort of tick marks. If it
|
1061
|
+
* works, generate the output and return 1, otherwise just return 0 and
|
1062
|
+
* let the caller figure it out.
|
1063
|
+
*/
|
1064
|
+
static int
|
1065
|
+
tickhandler(MMIOT *f, int tickchar, int minticks, spanhandler spanner)
|
1066
|
+
{
|
1067
|
+
int endticks, size;
|
1068
|
+
int tick = nrticks(0, tickchar, f);
|
1069
|
+
|
1070
|
+
if ( (tick >= minticks) && (size = matchticks(f,tickchar,tick,&endticks)) ) {
|
1071
|
+
if ( endticks < tick ) {
|
1072
|
+
size += (tick - endticks);
|
1073
|
+
tick = endticks;
|
1074
|
+
}
|
1075
|
+
|
1076
|
+
shift(f, tick);
|
1077
|
+
(*spanner)(f,size);
|
1078
|
+
shift(f, size+tick-1);
|
1079
|
+
return 1;
|
1080
|
+
}
|
1081
|
+
return 0;
|
1082
|
+
}
|
1083
|
+
|
1052
1084
|
#define tag_text(f) (f->flags & INSIDE_TAG)
|
1053
1085
|
|
1054
1086
|
|
@@ -1060,7 +1092,7 @@ text(MMIOT *f)
|
|
1060
1092
|
int smartyflags = 0;
|
1061
1093
|
|
1062
1094
|
while (1) {
|
1063
|
-
if ( (f->flags & AUTOLINK) && isalpha(peek(f,1)) )
|
1095
|
+
if ( (f->flags & AUTOLINK) && isalpha(peek(f,1)) && !tag_text(f) )
|
1064
1096
|
maybe_autolink(f);
|
1065
1097
|
|
1066
1098
|
c = pull(f);
|
@@ -1073,7 +1105,7 @@ text(MMIOT *f)
|
|
1073
1105
|
switch (c) {
|
1074
1106
|
case 0: break;
|
1075
1107
|
|
1076
|
-
case 3: Qstring("<br/>", f);
|
1108
|
+
case 3: Qstring(tag_text(f) ? " " : "<br/>", f);
|
1077
1109
|
break;
|
1078
1110
|
|
1079
1111
|
case '>': if ( tag_text(f) )
|
@@ -1126,16 +1158,13 @@ text(MMIOT *f)
|
|
1126
1158
|
}
|
1127
1159
|
#endif
|
1128
1160
|
case '*':
|
1129
|
-
#if RELAXED_EMPHASIS
|
1130
1161
|
/* Underscores & stars don't count if they're out in the middle
|
1131
1162
|
* of whitespace */
|
1132
|
-
if (
|
1133
|
-
&& isthisspace(f,1) ) {
|
1163
|
+
if ( isthisspace(f,-1) && isthisspace(f,1) ) {
|
1134
1164
|
Qchar(c, f);
|
1135
1165
|
break;
|
1136
1166
|
}
|
1137
1167
|
/* else fall into the regular old emphasis case */
|
1138
|
-
#endif
|
1139
1168
|
if ( tag_text(f) )
|
1140
1169
|
Qchar(c, f);
|
1141
1170
|
else {
|
@@ -1145,18 +1174,12 @@ text(MMIOT *f)
|
|
1145
1174
|
}
|
1146
1175
|
break;
|
1147
1176
|
|
1148
|
-
case '
|
1177
|
+
case '~': if ( (f->flags & (NOSTRIKETHROUGH|INSIDE_TAG|STRICT)) || !tickhandler(f,c,2,delspan) )
|
1178
|
+
Qchar(c, f);
|
1179
|
+
break;
|
1180
|
+
|
1181
|
+
case '`': if ( tag_text(f) || !tickhandler(f,c,1,codespan) )
|
1149
1182
|
Qchar(c, f);
|
1150
|
-
else {
|
1151
|
-
Qstring("<code>", f);
|
1152
|
-
if ( peek(f, 1) == '`' ) {
|
1153
|
-
pull(f);
|
1154
|
-
code(2, f);
|
1155
|
-
}
|
1156
|
-
else
|
1157
|
-
code(1, f);
|
1158
|
-
Qstring("</code>", f);
|
1159
|
-
}
|
1160
1183
|
break;
|
1161
1184
|
|
1162
1185
|
case '\\': switch ( c = pull(f) ) {
|
@@ -1164,11 +1187,10 @@ text(MMIOT *f)
|
|
1164
1187
|
break;
|
1165
1188
|
case '<': Qstring("<", f);
|
1166
1189
|
break;
|
1167
|
-
case '\\':
|
1168
1190
|
case '>': case '#': case '.': case '-':
|
1169
1191
|
case '+': case '{': case '}': case ']':
|
1170
|
-
case '(': case ')': case '"': case '\'':
|
1171
1192
|
case '!': case '[': case '*': case '_':
|
1193
|
+
case '\\':case '(': case ')':
|
1172
1194
|
case '`': Qchar(c, f);
|
1173
1195
|
break;
|
1174
1196
|
default:
|
@@ -1202,74 +1224,6 @@ text(MMIOT *f)
|
|
1202
1224
|
} /* text */
|
1203
1225
|
|
1204
1226
|
|
1205
|
-
static int
|
1206
|
-
iscodeblock(MMIOT *f)
|
1207
|
-
{
|
1208
|
-
int i=1, single = 1, c;
|
1209
|
-
|
1210
|
-
if ( peek(f,i) == '`' ) {
|
1211
|
-
single=0;
|
1212
|
-
i++;
|
1213
|
-
}
|
1214
|
-
while ( (c=peek(f,i)) != EOF ) {
|
1215
|
-
if ( (c == '`') && (single || peek(f,i+1) == '`') )
|
1216
|
-
return 1;
|
1217
|
-
else if ( c == '\\' )
|
1218
|
-
i++;
|
1219
|
-
i++;
|
1220
|
-
}
|
1221
|
-
return 0;
|
1222
|
-
|
1223
|
-
}
|
1224
|
-
|
1225
|
-
static int
|
1226
|
-
endofcode(int escape, int offset, MMIOT *f)
|
1227
|
-
{
|
1228
|
-
switch (escape) {
|
1229
|
-
case 2: if ( peek(f, offset+1) == '`' ) {
|
1230
|
-
shift(f,1);
|
1231
|
-
case 1: shift(f,offset);
|
1232
|
-
return 1;
|
1233
|
-
}
|
1234
|
-
default:return 0;
|
1235
|
-
}
|
1236
|
-
}
|
1237
|
-
|
1238
|
-
|
1239
|
-
/* the only characters that have special meaning in a code block are
|
1240
|
-
* `<' and `&' , which are /always/ expanded to < and &
|
1241
|
-
*/
|
1242
|
-
static void
|
1243
|
-
code(int escape, MMIOT *f)
|
1244
|
-
{
|
1245
|
-
int c;
|
1246
|
-
|
1247
|
-
if ( escape && (peek(f,1) == ' ') )
|
1248
|
-
shift(f,1);
|
1249
|
-
|
1250
|
-
while ( (c = pull(f)) != EOF ) {
|
1251
|
-
switch (c) {
|
1252
|
-
case ' ': if ( peek(f,1) == '`' && endofcode(escape, 1, f) )
|
1253
|
-
return;
|
1254
|
-
Qchar(c, f);
|
1255
|
-
break;
|
1256
|
-
|
1257
|
-
case '`': if ( endofcode(escape, 0, f) )
|
1258
|
-
return;
|
1259
|
-
Qchar(c, f);
|
1260
|
-
break;
|
1261
|
-
|
1262
|
-
case '\\': cputc(c, f);
|
1263
|
-
if ( peek(f,1) == '>' || (c = pull(f)) == EOF )
|
1264
|
-
break;
|
1265
|
-
|
1266
|
-
default: cputc(c, f);
|
1267
|
-
break;
|
1268
|
-
}
|
1269
|
-
}
|
1270
|
-
} /* code */
|
1271
|
-
|
1272
|
-
|
1273
1227
|
/* print a header block
|
1274
1228
|
*/
|
1275
1229
|
static void
|
@@ -1328,6 +1282,7 @@ splat(Line *p, char *block, Istring align, int force, MMIOT *f)
|
|
1328
1282
|
return colno;
|
1329
1283
|
}
|
1330
1284
|
|
1285
|
+
|
1331
1286
|
static int
|
1332
1287
|
printtable(Paragraph *pp, MMIOT *f)
|
1333
1288
|
{
|
@@ -1392,13 +1347,14 @@ static int
|
|
1392
1347
|
printblock(Paragraph *pp, MMIOT *f)
|
1393
1348
|
{
|
1394
1349
|
Line *t = pp->text;
|
1395
|
-
static char *Begin[] = { "", "<p>", "<center>" };
|
1396
|
-
static char *End[] = { "", "</p>","</
|
1350
|
+
static char *Begin[] = { "", "<p>", "<p style=\"text-align:center;\">" };
|
1351
|
+
static char *End[] = { "", "</p>","</p>" };
|
1397
1352
|
|
1398
1353
|
while (t) {
|
1399
1354
|
if ( S(t->text) ) {
|
1400
|
-
if (
|
1401
|
-
|
1355
|
+
if ( t->next && S(t->text) > 2
|
1356
|
+
&& T(t->text)[S(t->text)-2] == ' '
|
1357
|
+
&& T(t->text)[S(t->text)-1] == ' ' ) {
|
1402
1358
|
push(T(t->text), S(t->text)-2, f);
|
1403
1359
|
push("\003\n", 2, f);
|
1404
1360
|
}
|
@@ -1423,19 +1379,18 @@ printcode(Line *t, MMIOT *f)
|
|
1423
1379
|
{
|
1424
1380
|
int blanks;
|
1425
1381
|
|
1426
|
-
|
1382
|
+
Qstring("<pre><code>", f);
|
1383
|
+
for ( blanks = 0; t ; t = t->next ) {
|
1427
1384
|
if ( S(t->text) > t->dle ) {
|
1428
1385
|
while ( blanks ) {
|
1429
|
-
|
1386
|
+
Qchar('\n', f);
|
1430
1387
|
--blanks;
|
1431
1388
|
}
|
1432
|
-
|
1433
|
-
|
1389
|
+
code(f, T(t->text), S(t->text));
|
1390
|
+
Qchar('\n', f);
|
1434
1391
|
}
|
1435
1392
|
else blanks++;
|
1436
|
-
|
1437
|
-
Qstring("<pre><code>", f);
|
1438
|
-
code(0, f);
|
1393
|
+
}
|
1439
1394
|
Qstring("</code></pre>", f);
|
1440
1395
|
}
|
1441
1396
|
|