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.
Files changed (47) hide show
  1. data.tar.gz.sig +0 -0
  2. data/ChangeLog +36 -6
  3. data/Rakefile +46 -26
  4. data/Rakefile.local +13 -6
  5. data/ext/VERSION +1 -1
  6. data/ext/bluecloth.c +46 -21
  7. data/ext/bluecloth.h +13 -2
  8. data/ext/cstring.h +3 -1
  9. data/ext/emmatch.c +188 -0
  10. data/ext/generate.c +203 -248
  11. data/ext/html5.c +24 -0
  12. data/ext/markdown.c +122 -98
  13. data/ext/markdown.h +16 -2
  14. data/ext/mkdio.c +43 -9
  15. data/ext/mkdio.h +11 -0
  16. data/ext/resource.c +1 -1
  17. data/ext/tags.c +110 -0
  18. data/ext/tags.h +18 -0
  19. data/lib/bluecloth.rb +33 -26
  20. data/rake/documentation.rb +115 -0
  21. data/rake/helpers.rb +375 -308
  22. data/rake/hg.rb +17 -3
  23. data/rake/manual.rb +11 -6
  24. data/rake/packaging.rb +7 -1
  25. data/rake/publishing.rb +162 -88
  26. data/spec/bluecloth/101_changes_spec.rb +1 -0
  27. data/spec/bluecloth/autolinks_spec.rb +1 -0
  28. data/spec/bluecloth/blockquotes_spec.rb +1 -0
  29. data/spec/bluecloth/code_spans_spec.rb +1 -0
  30. data/spec/bluecloth/emphasis_spec.rb +1 -0
  31. data/spec/bluecloth/entities_spec.rb +1 -0
  32. data/spec/bluecloth/hrules_spec.rb +1 -0
  33. data/spec/bluecloth/images_spec.rb +1 -0
  34. data/spec/bluecloth/inline_html_spec.rb +25 -61
  35. data/spec/bluecloth/lists_spec.rb +1 -0
  36. data/spec/bluecloth/paragraphs_spec.rb +1 -0
  37. data/spec/bluecloth/titles_spec.rb +1 -0
  38. data/spec/bluecloth_spec.rb +22 -6
  39. data/spec/bugfix_spec.rb +79 -2
  40. data/spec/contributions_spec.rb +1 -0
  41. data/spec/discount_spec.rb +46 -2
  42. data/spec/lib/helpers.rb +8 -8
  43. data/spec/lib/matchers.rb +5 -17
  44. data/spec/markdowntest_spec.rb +2 -34
  45. metadata +48 -17
  46. metadata.gz.sig +0 -0
  47. data/rake/rdoc.rb +0 -30
data/ext/cstring.h CHANGED
@@ -10,7 +10,9 @@
10
10
  #include <string.h>
11
11
  #include <stdlib.h>
12
12
 
13
- #include "amalloc.h"
13
+ #ifndef __WITHOUT_AMALLOC
14
+ # include "amalloc.h"
15
+ #endif
14
16
 
15
17
  /* expandable Pascal-style string.
16
18
  */
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.base = f->base;
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( "ftp://" ),
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, protocol[i].name, protocol[i].nlen) == 0 )
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
- return 0;
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
- Qstring(tag->link_pfx, f);
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 &lt; and &amp;
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
- Qstring("<a href=\"", f);
831
- puturl(text,size,f, 0);
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
- Qstring(forbidden_tag(f) ? "&lt;" : "<", f);
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 ( !(f->flags & STRICT) && isthisspace(f,-1)
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 '`': if ( tag_text(f) || !iscodeblock(f) )
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("&lt;", 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 &lt; and &amp;
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>","</center>" };
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 ( S(t->text) > 2 && T(t->text)[S(t->text)-2] == ' '
1401
- && T(t->text)[S(t->text)-1] == ' ') {
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
- for ( blanks = 0; t ; t = t->next )
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
- push("\n", 1, f);
1386
+ Qchar('\n', f);
1430
1387
  --blanks;
1431
1388
  }
1432
- push(T(t->text), S(t->text), f);
1433
- push("\n", 1, f);
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