bluecloth 2.0.7-x86-mingw32 → 2.0.11pre158-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.gemtest +0 -0
  3. data/History.md +4 -0
  4. data/LICENSE +1 -1
  5. data/Manifest.txt +103 -0
  6. data/README.md +103 -0
  7. data/Rakefile +95 -301
  8. data/ext/VERSION +1 -1
  9. data/ext/bluecloth.c +69 -23
  10. data/ext/bluecloth.h +13 -2
  11. data/ext/config.h +13 -2
  12. data/ext/css.c +14 -5
  13. data/ext/cstring.h +4 -2
  14. data/ext/docheader.c +13 -7
  15. data/ext/emmatch.c +188 -0
  16. data/ext/extconf.rb +7 -9
  17. data/ext/generate.c +333 -293
  18. data/ext/html5.c +24 -0
  19. data/ext/markdown.c +326 -185
  20. data/ext/markdown.h +52 -29
  21. data/ext/mkdio.c +82 -41
  22. data/ext/mkdio.h +44 -23
  23. data/ext/resource.c +4 -2
  24. data/ext/setup.c +47 -0
  25. data/ext/tags.c +123 -0
  26. data/ext/tags.h +19 -0
  27. data/lib/1.8/bluecloth_ext.so +0 -0
  28. data/lib/1.9/bluecloth_ext.so +0 -0
  29. data/lib/bluecloth.rb +77 -42
  30. data/spec/bluecloth/101_changes_spec.rb +18 -21
  31. data/spec/bluecloth/TEMPLATE +36 -0
  32. data/spec/bluecloth/autolinks_spec.rb +4 -7
  33. data/spec/bluecloth/blockquotes_spec.rb +20 -23
  34. data/spec/bluecloth/code_spans_spec.rb +2 -5
  35. data/spec/bluecloth/emphasis_spec.rb +2 -5
  36. data/spec/bluecloth/entities_spec.rb +2 -5
  37. data/spec/bluecloth/hrules_spec.rb +2 -5
  38. data/spec/bluecloth/images_spec.rb +2 -5
  39. data/spec/bluecloth/inline_html_spec.rb +26 -66
  40. data/spec/bluecloth/links_spec.rb +1 -5
  41. data/spec/bluecloth/lists_spec.rb +2 -5
  42. data/spec/bluecloth/paragraphs_spec.rb +2 -5
  43. data/spec/bluecloth/titles_spec.rb +2 -5
  44. data/spec/bluecloth_spec.rb +36 -22
  45. data/spec/bugfix_spec.rb +90 -10
  46. data/spec/contributions_spec.rb +2 -3
  47. data/spec/discount_spec.rb +50 -10
  48. data/spec/lib/helpers.rb +18 -117
  49. data/spec/lib/matchers.rb +7 -18
  50. data/spec/markdowntest_spec.rb +3 -39
  51. metadata +257 -143
  52. metadata.gz.sig +0 -0
  53. data/ChangeLog +0 -387
  54. data/README +0 -81
  55. data/Rakefile.local +0 -41
  56. data/rake/191_compat.rb +0 -26
  57. data/rake/dependencies.rb +0 -76
  58. data/rake/helpers.rb +0 -435
  59. data/rake/hg.rb +0 -273
  60. data/rake/manual.rb +0 -782
  61. data/rake/packaging.rb +0 -123
  62. data/rake/publishing.rb +0 -274
  63. data/rake/rdoc.rb +0 -30
  64. data/rake/style.rb +0 -62
  65. data/rake/svn.rb +0 -668
  66. data/rake/testing.rb +0 -187
  67. data/rake/verifytask.rb +0 -64
data/ext/extconf.rb CHANGED
@@ -13,19 +13,17 @@ version = versionfile.read.chomp
13
13
  if CONFIG['host_os'].match( 'mswin' )
14
14
  $CFLAGS << ' -I.' << ' -W3' << ' -Zi'
15
15
  else
16
- $CFLAGS << ' -I.' << ' -Wall'
16
+ $CFLAGS << ' -I.'
17
17
  end
18
18
  $CPPFLAGS << %Q{ -DVERSION=\\"#{version}\\"}
19
19
 
20
20
  # Add my own debugging hooks if building for me
21
- if ENV['DEBUGGING_BUILD']
21
+ if ENV['MAINTAINER_MODE']
22
+ $stderr.puts "Maintainer mode enabled."
23
+ $CFLAGS << ' -Wall'
22
24
  $CFLAGS << ' -ggdb' << ' -DDEBUG'
23
25
  end
24
26
 
25
- def fail( *messages )
26
- $stderr.puts( *messages )
27
- exit( 1 )
28
- end
29
27
 
30
28
  # Stuff from configure.sh
31
29
  have_func( "srand" ) || have_func( "srandom" )
@@ -35,13 +33,13 @@ have_func( "random" ) || have_func( "rand" )
35
33
  have_func( "bzero", %w[string.h strings.h] )
36
34
 
37
35
  unless have_func( "strcasecmp" ) || have_func( "stricmp" )
38
- fail( "This extension requires either strcasecmp() or stricmp()" )
36
+ abort "This extension requires either strcasecmp() or stricmp()"
39
37
  end
40
38
  unless have_func( "strncasecmp" ) || have_func( "strnicmp" )
41
- fail( "This extensions requires either strncasecmp() or strnicmp()" )
39
+ abort "This extensions requires either strncasecmp() or strnicmp()"
42
40
  end
43
41
 
44
- have_header( 'mkdio.h' ) or fail( "missing mkdio.h" )
42
+ have_header( 'mkdio.h' ) or abort "missing mkdio.h"
45
43
 
46
44
  # Check for 1.9.xish encoding header
47
45
  have_header( 'ruby/encoding.h' )
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
  }
@@ -463,6 +351,53 @@ linkysize(MMIOT *f, Footnote *ref)
463
351
  }
464
352
 
465
353
 
354
+ /* extract a <...>-encased url from the input stream.
355
+ * (markdown 1.0.2b8 compatibility; older versions
356
+ * of markdown treated the < and > as syntactic
357
+ * sugar that didn't have to be there. 1.0.2b8
358
+ * requires a closing >, and then falls into the
359
+ * title or closing )
360
+ */
361
+ static int
362
+ linkybroket(MMIOT *f, int image, Footnote *p)
363
+ {
364
+ int c;
365
+ int good = 0;
366
+
367
+ T(p->link) = cursor(f);
368
+ for ( S(p->link)=0; (c = pull(f)) != '>'; ++S(p->link) ) {
369
+ /* pull in all input until a '>' is found, or die trying.
370
+ */
371
+ if ( c == EOF )
372
+ return 0;
373
+ else if ( (c == '\\') && ispunct(peek(f,2)) ) {
374
+ ++S(p->link);
375
+ pull(f);
376
+ }
377
+ }
378
+
379
+ c = eatspace(f);
380
+
381
+ /* next nonspace needs to be a title, a size, or )
382
+ */
383
+ if ( ( c == '\'' || c == '"' ) && linkytitle(f,c,p) )
384
+ good=1;
385
+ else if ( image && (c == '=') && linkysize(f,p) )
386
+ good=1;
387
+ else
388
+ good=( c == ')' );
389
+
390
+ if ( good ) {
391
+ if ( peek(f, 1) == ')' )
392
+ pull(f);
393
+
394
+ ___mkd_tidy(&p->link);
395
+ }
396
+
397
+ return good;
398
+ } /* linkybroket */
399
+
400
+
466
401
  /* extract a (-prefixed url from the input stream.
467
402
  * the label is either of the format `<link>`, where I
468
403
  * extract until I find a >, or it is of the format
@@ -480,6 +415,8 @@ linkyurl(MMIOT *f, int image, Footnote *p)
480
415
 
481
416
  if ( c == '<' ) {
482
417
  pull(f);
418
+ if ( !(f->flags & MKD_1_COMPAT) )
419
+ return linkybroket(f,image,p);
483
420
  mayneedtotrim=1;
484
421
  }
485
422
 
@@ -512,27 +449,28 @@ linkyurl(MMIOT *f, int image, Footnote *p)
512
449
 
513
450
  /* prefixes for <automatic links>
514
451
  */
515
- static struct {
452
+ static struct _protocol {
516
453
  char *name;
517
454
  int nlen;
518
455
  } protocol[] = {
519
456
  #define _aprotocol(x) { x, (sizeof x)-1 }
520
- _aprotocol( "http://" ),
521
- _aprotocol( "https://" ),
522
- _aprotocol( "ftp://" ),
523
- _aprotocol( "news://" ),
457
+ _aprotocol( "https:" ),
458
+ _aprotocol( "http:" ),
459
+ _aprotocol( "news:" ),
460
+ _aprotocol( "ftp:" ),
524
461
  #undef _aprotocol
525
462
  };
526
463
  #define NRPROTOCOLS (sizeof protocol / sizeof protocol[0])
527
464
 
528
465
 
529
466
  static int
530
- isautoprefix(char *text)
467
+ isautoprefix(char *text, int size)
531
468
  {
532
469
  int i;
470
+ struct _protocol *p;
533
471
 
534
- for (i=0; i < NRPROTOCOLS; i++)
535
- if ( strncasecmp(text, protocol[i].name, protocol[i].nlen) == 0 )
472
+ for (i=0, p=protocol; i < NRPROTOCOLS; i++, p++)
473
+ if ( (size >= p->nlen) && strncasecmp(text, p->name, p->nlen) == 0 )
536
474
  return 1;
537
475
  return 0;
538
476
  }
@@ -556,9 +494,9 @@ typedef struct linkytype {
556
494
  } linkytype;
557
495
 
558
496
  static linkytype imaget = { 0, 0, "<img src=\"", "\"",
559
- 1, " alt=\"", "\" />", DENY_IMG|INSIDE_TAG, IS_URL };
497
+ 1, " alt=\"", "\" />", MKD_NOIMAGE|MKD_TAGTEXT, IS_URL };
560
498
  static linkytype linkt = { 0, 0, "<a href=\"", "\"",
561
- 0, ">", "</a>", DENY_A, IS_URL };
499
+ 0, ">", "</a>", MKD_NOLINKS, IS_URL };
562
500
 
563
501
  /*
564
502
  * pseudo-protocols for [][];
@@ -568,10 +506,11 @@ static linkytype linkt = { 0, 0, "<a href=\"", "\"",
568
506
  * raw: just dump the link without any processing
569
507
  */
570
508
  static linkytype specials[] = {
571
- { "id:", 3, "<a id=\"", "\"", 0, ">", "</a>", 0, IS_URL },
572
- { "class:", 6, "<span class=\"", "\"", 0, ">", "</span>", 0, 0 },
573
- { "raw:", 4, 0, 0, 0, 0, 0, DENY_HTML, 0 },
509
+ { "id:", 3, "<span id=\"", "\"", 0, ">", "</span>", 0, 0 },
510
+ { "raw:", 4, 0, 0, 0, 0, 0, MKD_NOHTML, 0 },
511
+ { "lang:", 5, "<span lang=\"", "\"", 0, ">", "</span>", 0, 0 },
574
512
  { "abbr:", 5, "<abbr title=\"", "\"", 0, ">", "</abbr>", 0, 0 },
513
+ { "class:", 6, "<span class=\"", "\"", 0, ">", "</span>", 0, 0 },
575
514
  } ;
576
515
 
577
516
  #define NR(x) (sizeof x / sizeof x[0])
@@ -584,8 +523,7 @@ pseudo(Cstring t)
584
523
  int i;
585
524
  linkytype *r;
586
525
 
587
- for ( i=0; i < NR(specials); i++ ) {
588
- r = &specials[i];
526
+ for ( i=0, r=specials; i < NR(specials); i++,r++ ) {
589
527
  if ( (S(t) > r->szpat) && (strncasecmp(T(t), r->pat, r->szpat) == 0) )
590
528
  return r;
591
529
  }
@@ -593,6 +531,39 @@ pseudo(Cstring t)
593
531
  }
594
532
 
595
533
 
534
+ /* print out the start of an `img' or `a' tag, applying callbacks as needed.
535
+ */
536
+ static void
537
+ printlinkyref(MMIOT *f, linkytype *tag, char *link, int size)
538
+ {
539
+ char *edit;
540
+
541
+ if ( f->flags & IS_LABEL )
542
+ return;
543
+
544
+ Qstring(tag->link_pfx, f);
545
+
546
+ if ( tag->kind & IS_URL ) {
547
+ if ( f->cb && f->cb->e_url && (edit = (*f->cb->e_url)(link, size, f->cb->e_data)) ) {
548
+ puturl(edit, strlen(edit), f, 0);
549
+ if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data);
550
+ }
551
+ else
552
+ puturl(link + tag->szpat, size - tag->szpat, f, 0);
553
+ }
554
+ else
555
+ ___mkd_reparse(link + tag->szpat, size - tag->szpat, MKD_TAGTEXT, f);
556
+
557
+ Qstring(tag->link_sfx, f);
558
+
559
+ if ( f->cb && f->cb->e_flags && (edit = (*f->cb->e_flags)(link, size, f->cb->e_data)) ) {
560
+ Qchar(' ', f);
561
+ Qstring(edit, f);
562
+ if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data);
563
+ }
564
+ } /* printlinkyref */
565
+
566
+
596
567
  /* print out a linky (or fail if it's Not Allowed)
597
568
  */
598
569
  static int
@@ -600,46 +571,38 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
600
571
  {
601
572
  linkytype *tag;
602
573
 
603
- if ( image )
574
+ if ( image || (ref == 0) )
604
575
  tag = &imaget;
605
576
  else if ( tag = pseudo(ref->link) ) {
606
- if ( f->flags & (NO_PSEUDO_PROTO|SAFELINK) )
577
+ if ( f->flags & (MKD_NO_EXT|MKD_SAFELINK) )
607
578
  return 0;
608
579
  }
609
- else if ( (f->flags & SAFELINK) && T(ref->link)
610
- && (T(ref->link)[0] != '/')
611
- && !isautoprefix(T(ref->link)) )
612
- /* if SAFELINK, only accept links that are local or
580
+ else if ( (f->flags & MKD_SAFELINK) && T(ref->link)
581
+ && (T(ref->link)[0] != '/')
582
+ && !isautoprefix(T(ref->link), S(ref->link)) )
583
+ /* if MKD_SAFELINK, only accept links that are local or
613
584
  * a well-known protocol
614
585
  */
615
- return 0;
586
+ return 0;
616
587
  else
617
588
  tag = &linkt;
618
589
 
619
590
  if ( f->flags & tag->flags )
620
591
  return 0;
621
592
 
622
- 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);
593
+ if ( f->flags & IS_LABEL )
594
+ ___mkd_reparse(T(text), S(text), tag->flags, f);
595
+ else if ( tag->link_pfx ) {
596
+ printlinkyref(f, tag, T(ref->link), S(ref->link));
634
597
 
635
- if ( tag->WxH) {
636
- if ( ref->height) Qprintf(f," height=\"%d\"", ref->height);
637
- if ( ref->width) Qprintf(f, " width=\"%d\"", ref->width);
598
+ if ( tag->WxH ) {
599
+ if ( ref->height ) Qprintf(f," height=\"%d\"", ref->height);
600
+ if ( ref->width ) Qprintf(f, " width=\"%d\"", ref->width);
638
601
  }
639
602
 
640
603
  if ( S(ref->title) ) {
641
604
  Qstring(" title=\"", f);
642
- ___mkd_reparse(T(ref->title), S(ref->title), INSIDE_TAG, f);
605
+ ___mkd_reparse(T(ref->title), S(ref->title), MKD_TAGTEXT, f);
643
606
  Qchar('"', f);
644
607
  }
645
608
 
@@ -677,8 +640,11 @@ linkylinky(int image, MMIOT *f)
677
640
  }
678
641
  else {
679
642
  int goodlink, implicit_mark = mmiottell(f);
680
-
681
- if ( eatspace(f) == '[' ) {
643
+
644
+ if ( isspace(peek(f,1)) )
645
+ pull(f);
646
+
647
+ if ( peek(f,1) == '[' ) {
682
648
  pull(f); /* consume leading '[' */
683
649
  goodlink = linkylabel(f, &key.tag);
684
650
  }
@@ -700,6 +666,8 @@ linkylinky(int image, MMIOT *f)
700
666
  if ( ref = bsearch(&key, T(*f->footnotes), S(*f->footnotes),
701
667
  sizeof key, (stfu)__mkd_footsort) )
702
668
  status = linkyformat(f, name, image, ref);
669
+ else if ( f->flags & IS_LABEL )
670
+ status = linkyformat(f, name, image, 0);
703
671
  }
704
672
  }
705
673
  }
@@ -742,20 +710,112 @@ mangle(char *s, int len, MMIOT *f)
742
710
  }
743
711
 
744
712
 
713
+ /* nrticks() -- count up a row of tick marks
714
+ */
715
+ static int
716
+ nrticks(int offset, int tickchar, MMIOT *f)
717
+ {
718
+ int tick = 0;
719
+
720
+ while ( peek(f, offset+tick) == tickchar ) tick++;
721
+
722
+ return tick;
723
+ } /* nrticks */
724
+
725
+
726
+ /* matchticks() -- match a certain # of ticks, and if that fails
727
+ * match the largest subset of those ticks.
728
+ *
729
+ * if a subset was matched, return the # of ticks
730
+ * that were matched.
731
+ */
732
+ static int
733
+ matchticks(MMIOT *f, int tickchar, int ticks, int *endticks)
734
+ {
735
+ int size, count, c;
736
+ int subsize=0, subtick=0;
737
+
738
+ *endticks = ticks;
739
+ for (size = 0; (c=peek(f,size+ticks)) != EOF; size ++) {
740
+ if ( (c == tickchar) && ( count = nrticks(size+ticks,tickchar,f)) ) {
741
+ if ( count == ticks )
742
+ return size;
743
+ else if ( count ) {
744
+ if ( (count > subtick) && (count < ticks) ) {
745
+ subsize = size;
746
+ subtick = count;
747
+ }
748
+ size += count;
749
+ }
750
+ }
751
+ }
752
+ if ( subsize ) {
753
+ *endticks = subtick;
754
+ return subsize;
755
+ }
756
+ return 0;
757
+ } /* matchticks */
758
+
759
+
760
+ /* code() -- write a string out as code. The only characters that have
761
+ * special meaning in a code block are * `<' and `&' , which
762
+ * are /always/ expanded to &lt; and &amp;
763
+ */
764
+ static void
765
+ code(MMIOT *f, char *s, int length)
766
+ {
767
+ int i,c;
768
+
769
+ for ( i=0; i < length; i++ )
770
+ if ( (c = s[i]) == 003) /* ^C: expand back to 2 spaces */
771
+ Qstring(" ", f);
772
+ else
773
+ cputc(c, f);
774
+ } /* code */
775
+
776
+
777
+ /* delspan() -- write out a chunk of text, blocking with <del>...</del>
778
+ */
779
+ static void
780
+ delspan(MMIOT *f, int size)
781
+ {
782
+ Qstring("<del>", f);
783
+ ___mkd_reparse(cursor(f)-1, size, 0, f);
784
+ Qstring("</del>", f);
785
+ }
786
+
787
+
788
+ /* codespan() -- write out a chunk of text as code, trimming one
789
+ * space off the front and/or back as appropriate.
790
+ */
791
+ static void
792
+ codespan(MMIOT *f, int size)
793
+ {
794
+ int i=0;
795
+
796
+ if ( size > 1 && peek(f, size-1) == ' ' ) --size;
797
+ if ( peek(f,i) == ' ' ) ++i, --size;
798
+
799
+ Qstring("<code>", f);
800
+ code(f, cursor(f)+(i-1), size);
801
+ Qstring("</code>", f);
802
+ } /* codespan */
803
+
804
+
745
805
  /* before letting a tag through, validate against
746
- * DENY_A and DENY_IMG
806
+ * MKD_NOLINKS and MKD_NOIMAGE
747
807
  */
748
808
  static int
749
809
  forbidden_tag(MMIOT *f)
750
810
  {
751
811
  int c = toupper(peek(f, 1));
752
812
 
753
- if ( f->flags & DENY_HTML )
813
+ if ( f->flags & MKD_NOHTML )
754
814
  return 1;
755
815
 
756
- if ( c == 'A' && (f->flags & DENY_A) && !isthisalnum(f,2) )
816
+ if ( c == 'A' && (f->flags & MKD_NOLINKS) && !isthisalnum(f,2) )
757
817
  return 1;
758
- if ( c == 'I' && (f->flags & DENY_IMG)
818
+ if ( c == 'I' && (f->flags & MKD_NOIMAGE)
759
819
  && strncasecmp(cursor(f)+1, "MG", 2) == 0
760
820
  && !isthisalnum(f,4) )
761
821
  return 1;
@@ -802,7 +862,7 @@ process_possible_link(MMIOT *f, int size)
802
862
  int mailto = 0;
803
863
  char *text = cursor(f);
804
864
 
805
- if ( f->flags & DENY_A ) return 0;
865
+ if ( f->flags & MKD_NOLINKS ) return 0;
806
866
 
807
867
  if ( (size > 7) && strncasecmp(text, "mailto:", 7) == 0 ) {
808
868
  /* if it says it's a mailto, it's a mailto -- who am
@@ -826,10 +886,9 @@ process_possible_link(MMIOT *f, int size)
826
886
  Qstring("</a>", f);
827
887
  return 1;
828
888
  }
829
- else if ( isautoprefix(text) ) {
830
- Qstring("<a href=\"", f);
831
- puturl(text,size,f, 0);
832
- Qstring("\">", f);
889
+ else if ( isautoprefix(text, size) ) {
890
+ printlinkyref(f, &linkt, text, size);
891
+ Qchar('>', f);
833
892
  puturl(text,size,f, 1);
834
893
  Qstring("</a>", f);
835
894
  return 1;
@@ -850,7 +909,7 @@ maybe_tag_or_link(MMIOT *f)
850
909
  int c, size;
851
910
  int maybetag = 1;
852
911
 
853
- if ( f->flags & INSIDE_TAG )
912
+ if ( f->flags & MKD_TAGTEXT )
854
913
  return 0;
855
914
 
856
915
  for ( size=0; (c = peek(f, size+1)) != '>'; size++) {
@@ -879,7 +938,10 @@ maybe_tag_or_link(MMIOT *f)
879
938
  else
880
939
  size++;
881
940
 
882
- Qstring(forbidden_tag(f) ? "&lt;" : "<", f);
941
+ if ( forbidden_tag(f) )
942
+ return 0;
943
+
944
+ Qchar('<', f);
883
945
  while ( ((c = peek(f, 1)) != EOF) && (c != '>') )
884
946
  Qchar(pull(f), f);
885
947
  return 1;
@@ -981,6 +1043,11 @@ static struct smarties {
981
1043
  } smarties[] = {
982
1044
  { '\'', "'s>", "rsquo", 0 },
983
1045
  { '\'', "'t>", "rsquo", 0 },
1046
+ { '\'', "'re>", "rsquo", 0 },
1047
+ { '\'', "'ll>", "rsquo", 0 },
1048
+ { '\'', "'ve>", "rsquo", 0 },
1049
+ { '\'', "'m>", "rsquo", 0 },
1050
+ { '\'', "'d>", "rsquo", 0 },
984
1051
  { '-', "--", "mdash", 1 },
985
1052
  { '-', "<->", "ndash", 0 },
986
1053
  { '.', "...", "hellip", 2 },
@@ -1005,7 +1072,7 @@ smartypants(int c, int *flags, MMIOT *f)
1005
1072
  {
1006
1073
  int i;
1007
1074
 
1008
- if ( f->flags & (DENY_SMARTY|INSIDE_TAG) )
1075
+ if ( f->flags & (MKD_NOPANTS|MKD_TAGTEXT|IS_LABEL) )
1009
1076
  return 0;
1010
1077
 
1011
1078
  for ( i=0; i < NRSMART; i++)
@@ -1049,7 +1116,31 @@ smartypants(int c, int *flags, MMIOT *f)
1049
1116
  } /* smartypants */
1050
1117
 
1051
1118
 
1052
- #define tag_text(f) (f->flags & INSIDE_TAG)
1119
+ /* process a body of text encased in some sort of tick marks. If it
1120
+ * works, generate the output and return 1, otherwise just return 0 and
1121
+ * let the caller figure it out.
1122
+ */
1123
+ static int
1124
+ tickhandler(MMIOT *f, int tickchar, int minticks, spanhandler spanner)
1125
+ {
1126
+ int endticks, size;
1127
+ int tick = nrticks(0, tickchar, f);
1128
+
1129
+ if ( (tick >= minticks) && (size = matchticks(f,tickchar,tick,&endticks)) ) {
1130
+ if ( endticks < tick ) {
1131
+ size += (tick - endticks);
1132
+ tick = endticks;
1133
+ }
1134
+
1135
+ shift(f, tick);
1136
+ (*spanner)(f,size);
1137
+ shift(f, size+tick-1);
1138
+ return 1;
1139
+ }
1140
+ return 0;
1141
+ }
1142
+
1143
+ #define tag_text(f) (f->flags & MKD_TAGTEXT)
1053
1144
 
1054
1145
 
1055
1146
  static void
@@ -1060,7 +1151,7 @@ text(MMIOT *f)
1060
1151
  int smartyflags = 0;
1061
1152
 
1062
1153
  while (1) {
1063
- if ( (f->flags & AUTOLINK) && isalpha(peek(f,1)) )
1154
+ if ( (f->flags & MKD_AUTOLINK) && isalpha(peek(f,1)) && !tag_text(f) )
1064
1155
  maybe_autolink(f);
1065
1156
 
1066
1157
  c = pull(f);
@@ -1073,7 +1164,7 @@ text(MMIOT *f)
1073
1164
  switch (c) {
1074
1165
  case 0: break;
1075
1166
 
1076
- case 3: Qstring("<br/>", f);
1167
+ case 3: Qstring(tag_text(f) ? " " : "<br/>", f);
1077
1168
  break;
1078
1169
 
1079
1170
  case '>': if ( tag_text(f) )
@@ -1099,43 +1190,56 @@ text(MMIOT *f)
1099
1190
  case '[': if ( tag_text(f) || !linkylinky(0, f) )
1100
1191
  Qchar(c, f);
1101
1192
  break;
1102
- #if SUPERSCRIPT
1103
1193
  /* A^B -> A<sup>B</sup> */
1104
- case '^': if ( (f->flags & (STRICT|INSIDE_TAG)) || isthisspace(f,-1) || isthisspace(f,1) )
1194
+ case '^': if ( (f->flags & (MKD_NOSUPERSCRIPT|MKD_STRICT|MKD_TAGTEXT))
1195
+ || (isthisnonword(f,-1) && peek(f,-1) != ')')
1196
+ || isthisspace(f,1) )
1105
1197
  Qchar(c,f);
1106
1198
  else {
1107
1199
  char *sup = cursor(f);
1108
1200
  int len = 0;
1109
- Qstring("<sup>",f);
1110
- while ( !isthisspace(f,1+len) ) {
1111
- ++len;
1201
+
1202
+ if ( peek(f,1) == '(' ) {
1203
+ int here = mmiottell(f);
1204
+ pull(f);
1205
+
1206
+ if ( (len = parenthetical('(',')',f)) <= 0 ) {
1207
+ mmiotseek(f,here);
1208
+ Qchar(c, f);
1209
+ break;
1210
+ }
1211
+ sup++;
1112
1212
  }
1113
- shift(f,len);
1213
+ else {
1214
+ while ( isthisalnum(f,1+len) )
1215
+ ++len;
1216
+ if ( !len ) {
1217
+ Qchar(c,f);
1218
+ break;
1219
+ }
1220
+ shift(f,len);
1221
+ }
1222
+ Qstring("<sup>",f);
1114
1223
  ___mkd_reparse(sup, len, 0, f);
1115
1224
  Qstring("</sup>", f);
1116
1225
  }
1117
1226
  break;
1118
- #endif
1119
1227
  case '_':
1120
- #if RELAXED_EMPHASIS
1121
1228
  /* Underscores don't count if they're in the middle of a word */
1122
- if ( !(f->flags & STRICT) && isthisalnum(f,-1)
1123
- && isthisalnum(f,1) ) {
1229
+ if ( !(f->flags & (MKD_NORELAXED|MKD_STRICT))
1230
+ && isthisalnum(f,-1)
1231
+ && isthisalnum(f,1) ) {
1124
1232
  Qchar(c, f);
1125
1233
  break;
1126
1234
  }
1127
- #endif
1128
1235
  case '*':
1129
- #if RELAXED_EMPHASIS
1130
1236
  /* Underscores & stars don't count if they're out in the middle
1131
1237
  * of whitespace */
1132
- if ( !(f->flags & STRICT) && isthisspace(f,-1)
1133
- && isthisspace(f,1) ) {
1238
+ if ( isthisspace(f,-1) && isthisspace(f,1) ) {
1134
1239
  Qchar(c, f);
1135
1240
  break;
1136
1241
  }
1137
1242
  /* else fall into the regular old emphasis case */
1138
- #endif
1139
1243
  if ( tag_text(f) )
1140
1244
  Qchar(c, f);
1141
1245
  else {
@@ -1145,18 +1249,12 @@ text(MMIOT *f)
1145
1249
  }
1146
1250
  break;
1147
1251
 
1148
- case '`': if ( tag_text(f) || !iscodeblock(f) )
1252
+ case '~': if ( (f->flags & (MKD_NOSTRIKETHROUGH|MKD_TAGTEXT|MKD_STRICT)) || !tickhandler(f,c,2,delspan) )
1253
+ Qchar(c, f);
1254
+ break;
1255
+
1256
+ case '`': if ( tag_text(f) || !tickhandler(f,c,1,codespan) )
1149
1257
  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
1258
  break;
1161
1259
 
1162
1260
  case '\\': switch ( c = pull(f) ) {
@@ -1164,11 +1262,18 @@ text(MMIOT *f)
1164
1262
  break;
1165
1263
  case '<': Qstring("&lt;", f);
1166
1264
  break;
1167
- case '\\':
1265
+ case '^': if ( f->flags & (MKD_STRICT|MKD_NOSUPERSCRIPT) ) {
1266
+ Qchar('\\', f);
1267
+ shift(f,-1);
1268
+ break;
1269
+ }
1270
+ Qchar(c, f);
1271
+ break;
1272
+
1168
1273
  case '>': case '#': case '.': case '-':
1169
1274
  case '+': case '{': case '}': case ']':
1170
- case '(': case ')': case '"': case '\'':
1171
1275
  case '!': case '[': case '*': case '_':
1276
+ case '\\':case '(': case ')':
1172
1277
  case '`': Qchar(c, f);
1173
1278
  break;
1174
1279
  default:
@@ -1202,86 +1307,17 @@ text(MMIOT *f)
1202
1307
  } /* text */
1203
1308
 
1204
1309
 
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
1310
  /* print a header block
1274
1311
  */
1275
1312
  static void
1276
1313
  printheader(Paragraph *pp, MMIOT *f)
1277
1314
  {
1278
- Qprintf(f, "<h%d", pp->hnumber);
1279
- if ( f->flags & TOC ) {
1280
- Qprintf(f, " id=\"", pp->hnumber);
1281
- mkd_string_to_anchor(T(pp->text->text), S(pp->text->text), Qchar, f);
1282
- Qchar('"', f);
1315
+ if ( f->flags & MKD_TOC ) {
1316
+ Qstring("<a name=\"", f);
1317
+ mkd_string_to_anchor(T(pp->text->text), S(pp->text->text), Qchar, f, 1);
1318
+ Qstring("\"></a>\n", f);
1283
1319
  }
1284
- Qchar('>', f);
1320
+ Qprintf(f, "<h%d>", pp->hnumber);
1285
1321
  push(T(pp->text->text), S(pp->text->text), f);
1286
1322
  text(f);
1287
1323
  Qprintf(f, "</h%d>", pp->hnumber);
@@ -1328,6 +1364,7 @@ splat(Line *p, char *block, Istring align, int force, MMIOT *f)
1328
1364
  return colno;
1329
1365
  }
1330
1366
 
1367
+
1331
1368
  static int
1332
1369
  printtable(Paragraph *pp, MMIOT *f)
1333
1370
  {
@@ -1392,13 +1429,14 @@ static int
1392
1429
  printblock(Paragraph *pp, MMIOT *f)
1393
1430
  {
1394
1431
  Line *t = pp->text;
1395
- static char *Begin[] = { "", "<p>", "<center>" };
1396
- static char *End[] = { "", "</p>","</center>" };
1432
+ static char *Begin[] = { "", "<p>", "<p style=\"text-align:center;\">" };
1433
+ static char *End[] = { "", "</p>","</p>" };
1397
1434
 
1398
1435
  while (t) {
1399
1436
  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] == ' ') {
1437
+ if ( t->next && S(t->text) > 2
1438
+ && T(t->text)[S(t->text)-2] == ' '
1439
+ && T(t->text)[S(t->text)-1] == ' ' ) {
1402
1440
  push(T(t->text), S(t->text)-2, f);
1403
1441
  push("\003\n", 2, f);
1404
1442
  }
@@ -1423,19 +1461,18 @@ printcode(Line *t, MMIOT *f)
1423
1461
  {
1424
1462
  int blanks;
1425
1463
 
1426
- for ( blanks = 0; t ; t = t->next )
1464
+ Qstring("<pre><code>", f);
1465
+ for ( blanks = 0; t ; t = t->next ) {
1427
1466
  if ( S(t->text) > t->dle ) {
1428
1467
  while ( blanks ) {
1429
- push("\n", 1, f);
1468
+ Qchar('\n', f);
1430
1469
  --blanks;
1431
1470
  }
1432
- push(T(t->text), S(t->text), f);
1433
- push("\n", 1, f);
1471
+ code(f, T(t->text), S(t->text));
1472
+ Qchar('\n', f);
1434
1473
  }
1435
1474
  else blanks++;
1436
-
1437
- Qstring("<pre><code>", f);
1438
- code(0, f);
1475
+ }
1439
1476
  Qstring("</code></pre>", f);
1440
1477
  }
1441
1478
 
@@ -1477,7 +1514,6 @@ htmlify(Paragraph *p, char *block, char *arguments, MMIOT *f)
1477
1514
  }
1478
1515
 
1479
1516
 
1480
- #if DL_TAG_EXTENSION
1481
1517
  static void
1482
1518
  definitionlist(Paragraph *p, MMIOT *f)
1483
1519
  {
@@ -1500,7 +1536,6 @@ definitionlist(Paragraph *p, MMIOT *f)
1500
1536
  Qstring("</dl>", f);
1501
1537
  }
1502
1538
  }
1503
- #endif
1504
1539
 
1505
1540
 
1506
1541
  static void
@@ -1509,7 +1544,7 @@ listdisplay(int typ, Paragraph *p, MMIOT* f)
1509
1544
  if ( p ) {
1510
1545
  Qprintf(f, "<%cl", (typ==UL)?'u':'o');
1511
1546
  if ( typ == AL )
1512
- Qprintf(f, " type=a");
1547
+ Qprintf(f, " type=\"a\"");
1513
1548
  Qprintf(f, ">\n");
1514
1549
 
1515
1550
  for ( ; p ; p = p->next ) {
@@ -1552,11 +1587,9 @@ display(Paragraph *p, MMIOT *f)
1552
1587
  listdisplay(p->typ, p->down, f);
1553
1588
  break;
1554
1589
 
1555
- #if DL_TAG_EXTENSION
1556
1590
  case DL:
1557
1591
  definitionlist(p->down, f);
1558
1592
  break;
1559
- #endif
1560
1593
 
1561
1594
  case HR:
1562
1595
  Qstring("<hr />", f);
@@ -1588,14 +1621,21 @@ display(Paragraph *p, MMIOT *f)
1588
1621
  int
1589
1622
  mkd_document(Document *p, char **res)
1590
1623
  {
1624
+ int size;
1625
+
1591
1626
  if ( p && p->compiled ) {
1592
1627
  if ( ! p->html ) {
1593
1628
  htmlify(p->code, 0, 0, p->ctx);
1594
1629
  p->html = 1;
1595
1630
  }
1596
1631
 
1632
+ size = S(p->ctx->out);
1633
+
1634
+ if ( (size == 0) || T(p->ctx->out)[size-1] )
1635
+ EXPAND(p->ctx->out) = 0;
1636
+
1597
1637
  *res = T(p->ctx->out);
1598
- return S(p->ctx->out);
1638
+ return size;
1599
1639
  }
1600
1640
  return EOF;
1601
1641
  }