bluecloth 2.0.9 → 2.0.10

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 +29 -2
  3. data/Rakefile +18 -15
  4. data/ext/VERSION +1 -1
  5. data/ext/bluecloth.c +26 -5
  6. data/ext/config.h +13 -2
  7. data/ext/css.c +14 -5
  8. data/ext/cstring.h +1 -1
  9. data/ext/docheader.c +13 -7
  10. data/ext/emmatch.c +1 -1
  11. data/ext/generate.c +134 -48
  12. data/ext/markdown.c +207 -94
  13. data/ext/markdown.h +37 -28
  14. data/ext/mkdio.c +39 -32
  15. data/ext/mkdio.h +34 -24
  16. data/ext/resource.c +3 -1
  17. data/ext/setup.c +47 -0
  18. data/ext/tags.c +15 -2
  19. data/ext/tags.h +1 -0
  20. data/lib/bluecloth.rb +65 -40
  21. data/rake/documentation.rb +9 -1
  22. data/rake/hg.rb +34 -3
  23. data/rake/packaging.rb +1 -1
  24. data/rake/publishing.rb +2 -9
  25. data/rake/testing.rb +53 -88
  26. data/spec/bluecloth/101_changes_spec.rb +17 -17
  27. data/spec/bluecloth/autolinks_spec.rb +1 -1
  28. data/spec/bluecloth/blockquotes_spec.rb +18 -18
  29. data/spec/bluecloth/code_spans_spec.rb +1 -1
  30. data/spec/bluecloth/emphasis_spec.rb +1 -1
  31. data/spec/bluecloth/entities_spec.rb +1 -1
  32. data/spec/bluecloth/hrules_spec.rb +1 -1
  33. data/spec/bluecloth/images_spec.rb +1 -1
  34. data/spec/bluecloth/inline_html_spec.rb +1 -1
  35. data/spec/bluecloth/links_spec.rb +1 -1
  36. data/spec/bluecloth/lists_spec.rb +1 -1
  37. data/spec/bluecloth/paragraphs_spec.rb +1 -1
  38. data/spec/bluecloth/titles_spec.rb +1 -1
  39. data/spec/bluecloth_spec.rb +13 -13
  40. data/spec/bugfix_spec.rb +6 -1
  41. data/spec/contributions_spec.rb +1 -1
  42. data/spec/discount_spec.rb +2 -2
  43. data/spec/lib/helpers.rb +1 -124
  44. data/spec/lib/matchers.rb +1 -1
  45. data/spec/markdowntest_spec.rb +1 -1
  46. metadata +10 -10
  47. metadata.gz.sig +0 -0
@@ -175,7 +175,7 @@ splitline(Line *t, int cutpoint)
175
175
 
176
176
 
177
177
  static Line *
178
- commentblock(Paragraph *p)
178
+ commentblock(Paragraph *p, int *unclosed)
179
179
  {
180
180
  Line *t, *ret;
181
181
  char *end;
@@ -188,21 +188,24 @@ commentblock(Paragraph *p)
188
188
  return ret;
189
189
  }
190
190
  }
191
+ *unclosed = 1;
191
192
  return t;
192
193
 
193
194
  }
194
195
 
195
196
 
196
197
  static Line *
197
- htmlblock(Paragraph *p, struct kw *tag)
198
+ htmlblock(Paragraph *p, struct kw *tag, int *unclosed)
198
199
  {
199
200
  Line *ret;
200
201
  FLO f = { p->text, 0 };
201
202
  int c;
202
203
  int i, closing, depth=0;
203
204
 
205
+ *unclosed = 0;
206
+
204
207
  if ( tag == &comment )
205
- return commentblock(p);
208
+ return commentblock(p, unclosed);
206
209
 
207
210
  if ( tag->selfclose ) {
208
211
  ret = f.t->next;
@@ -240,6 +243,8 @@ htmlblock(Paragraph *p, struct kw *tag)
240
243
  /* consume trailing gunk in close tag */
241
244
  c = flogetc(&f);
242
245
  }
246
+ if ( c == EOF )
247
+ break;
243
248
  if ( !f.t )
244
249
  return 0;
245
250
  splitline(f.t, floindex(f));
@@ -251,6 +256,7 @@ htmlblock(Paragraph *p, struct kw *tag)
251
256
  }
252
257
  }
253
258
  }
259
+ *unclosed = 1;
254
260
  return 0;
255
261
  }
256
262
 
@@ -409,56 +415,112 @@ ishdr(Line *t, int *htyp)
409
415
  }
410
416
 
411
417
 
412
- static int
413
- isdefinition(Line *t)
418
+ static Line*
419
+ is_discount_dt(Line *t, int *clip)
414
420
  {
415
- #if DL_TAG_EXTENSION
416
- return t && t->next
417
- && (S(t->text) > 2)
418
- && (t->dle == 0)
419
- && (T(t->text)[0] == '=')
420
- && (T(t->text)[S(t->text)-1] == '=')
421
- && ( (t->next->dle >= 4) || isdefinition(t->next) );
422
- #else
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;
430
+ }
431
+ else
432
+ return is_discount_dt(t->next, clip);
433
+ }
434
+ #endif
423
435
  return 0;
436
+ }
437
+
438
+
439
+ static int
440
+ is_extra_dd(Line *t)
441
+ {
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
+ }
424
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);
425
484
  }
426
485
 
427
486
 
428
487
  static int
429
- islist(Line *t, int *trim)
488
+ islist(Line *t, int *clip, DWORD flags, int *list_type)
430
489
  {
431
490
  int i, j;
432
491
  char *q;
433
492
 
434
- if ( iscode(t) || blankline(t) || ishdr(t,&i) || ishr(t) )
493
+ if ( /*iscode(t) ||*/ blankline(t) || ishdr(t,&i) || ishr(t) )
435
494
  return 0;
436
495
 
437
- if ( isdefinition(t) ) {
438
- *trim = 4;
496
+ if ( !(flags & (MKD_NODLIST|MKD_STRICT)) && isdefinition(t,clip,list_type) )
439
497
  return DL;
440
- }
441
498
 
442
499
  if ( strchr("*-+", T(t->text)[t->dle]) && isspace(T(t->text)[t->dle+1]) ) {
443
500
  i = nextnonblank(t, t->dle+1);
444
- *trim = (i > 4) ? 4 : i;
445
- return UL;
501
+ *clip = (i > 4) ? 4 : i;
502
+ *list_type = UL;
503
+ return AL;
446
504
  }
447
505
 
448
506
  if ( (j = nextblank(t,t->dle)) > t->dle ) {
449
507
  if ( T(t->text)[j-1] == '.' ) {
450
- #if ALPHA_LIST
451
- if ( (j == t->dle + 2) && isalpha(T(t->text)[t->dle]) ) {
452
- j = nextnonblank(t,j);
453
- *trim = j;
454
- return AL;
455
- }
456
- #endif
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
+
457
518
  strtoul(T(t->text)+t->dle, &q, 10);
458
519
  if ( (q > T(t->text)+t->dle) && (q == T(t->text) + (j-1)) ) {
459
520
  j = nextnonblank(t,j);
460
- *trim = j;
461
- return OL;
521
+ *clip = (j > 4) ? 4 : j;
522
+ *list_type = OL;
523
+ return AL;
462
524
  }
463
525
  }
464
526
  }
@@ -554,27 +616,33 @@ centered(Line *first, Line *last)
554
616
 
555
617
 
556
618
  static int
557
- endoftextblock(Line *t, int toplevelblock)
619
+ endoftextblock(Line *t, int toplevelblock, DWORD flags)
558
620
  {
559
621
  int z;
560
622
 
561
- if ( blankline(t)||isquote(t)||iscode(t)||ishdr(t,&z)||ishr(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) )
562
630
  return 1;
563
631
 
564
632
  /* HORRIBLE STANDARDS KLUDGE: Toplevel paragraphs eat absorb adjacent
565
633
  * list items, but sublevel blocks behave properly.
566
634
  */
567
- return toplevelblock ? 0 : islist(t,&z);
635
+ return toplevelblock ? 0 : islist(t,&z,flags, &z);
568
636
  }
569
637
 
570
638
 
571
639
  static Line *
572
- textblock(Paragraph *p, int toplevel)
640
+ textblock(Paragraph *p, int toplevel, DWORD flags)
573
641
  {
574
642
  Line *t, *next;
575
643
 
576
644
  for ( t = p->text; t ; t = next ) {
577
- if ( ((next = t->next) == 0) || endoftextblock(next, toplevel) ) {
645
+ if ( ((next = t->next) == 0) || endoftextblock(next, toplevel, flags) ) {
578
646
  p->align = centered(p->text, t);
579
647
  t->next = 0;
580
648
  return next;
@@ -602,12 +670,16 @@ szmarkerclass(char *p)
602
670
  * marker %[kind:]name%
603
671
  */
604
672
  static int
605
- isdivmarker(Line *p, int start)
673
+ isdivmarker(Line *p, int start, DWORD flags)
606
674
  {
607
- #if DIV_QUOTE
608
- char *s = T(p->text);
609
- int len = S(p->text);
610
- int i;
675
+ char *s;
676
+ int len, i;
677
+
678
+ if ( flags & (MKD_NODIVQUOTE|MKD_STRICT) )
679
+ return 0;
680
+
681
+ len = S(p->text);
682
+ s = T(p->text);
611
683
 
612
684
  if ( !(len && s[start] == '%' && s[len-1] == '%') ) return 0;
613
685
 
@@ -619,9 +691,6 @@ isdivmarker(Line *p, int start)
619
691
  return 0;
620
692
 
621
693
  return 1;
622
- #else
623
- return 0;
624
- #endif
625
694
  }
626
695
 
627
696
 
@@ -637,7 +706,7 @@ isdivmarker(Line *p, int start)
637
706
  * way the markdown sample web form at Daring Fireball works.
638
707
  */
639
708
  static Line *
640
- quoteblock(Paragraph *p)
709
+ quoteblock(Paragraph *p, DWORD flags)
641
710
  {
642
711
  Line *t, *q;
643
712
  int qp;
@@ -660,13 +729,13 @@ quoteblock(Paragraph *p)
660
729
 
661
730
  q = skipempty(t->next);
662
731
 
663
- if ( (q == 0) || ((q != t->next) && (!isquote(q) || isdivmarker(q,1))) ) {
732
+ if ( (q == 0) || ((q != t->next) && (!isquote(q) || isdivmarker(q,1,flags))) ) {
664
733
  ___mkd_freeLineRange(t, q);
665
734
  t = q;
666
735
  break;
667
736
  }
668
737
  }
669
- if ( isdivmarker(p->text,0) ) {
738
+ if ( isdivmarker(p->text,0,flags) ) {
670
739
  char *prefix = "class";
671
740
  int i;
672
741
 
@@ -709,6 +778,8 @@ tableblock(Paragraph *p)
709
778
  static Paragraph *Pp(ParagraphRoot *, Line *, int);
710
779
  static Paragraph *compile(Line *, int, MMIOT *);
711
780
 
781
+ typedef int (*linefn)(Line *);
782
+
712
783
 
713
784
  /*
714
785
  * pull in a list block. A list block starts with a list marker and
@@ -717,7 +788,7 @@ static Paragraph *compile(Line *, int, MMIOT *);
717
788
  * marker, but multiple paragraphs need to start with a 4-space indent.
718
789
  */
719
790
  static Line *
720
- listitem(Paragraph *p, int indent)
791
+ listitem(Paragraph *p, int indent, DWORD flags, linefn check)
721
792
  {
722
793
  Line *t, *q;
723
794
  int clip = indent;
@@ -748,7 +819,9 @@ listitem(Paragraph *p, int indent)
748
819
  indent = clip ? clip : 2;
749
820
  }
750
821
 
751
- if ( (q->dle < indent) && (ishr(q) || islist(q,&z)) && !issetext(q,&z) ) {
822
+ if ( (q->dle < indent) && (ishr(q) || islist(q,&z,flags,&z)
823
+ || (check && (*check)(q)))
824
+ && !issetext(q,&z) ) {
752
825
  q = t->next;
753
826
  t->next = 0;
754
827
  return q;
@@ -761,39 +834,81 @@ listitem(Paragraph *p, int indent)
761
834
 
762
835
 
763
836
  static Line *
764
- listblock(Paragraph *top, int trim, MMIOT *f)
837
+ definition_block(Paragraph *top, int clip, MMIOT *f, int kind)
765
838
  {
766
839
  ParagraphRoot d = { 0, 0 };
767
840
  Paragraph *p;
768
- Line *q = top->text, *text, *label;
769
- int isdl = (top->typ == DL),
770
- para = 0,
771
- ltype;
841
+ Line *q = top->text, *text = 0, *labels;
842
+ int z, para;
772
843
 
773
- while (( text = q )) {
774
- if ( top->typ == DL ) {
775
- Line *lp;
776
-
777
- for ( lp = label = text; lp ; lp = lp->next ) {
778
- text = lp->next;
779
- CLIP(lp->text, 0, 1);
780
- S(lp->text)--;
781
- if ( !isdefinition(lp->next) )
782
- lp->next = 0;
844
+ while (( labels = q )) {
845
+
846
+ if ( (q = isdefinition(labels, &z, &kind)) == 0 )
847
+ break;
848
+
849
+ if ( (text = skipempty(q->next)) == 0 )
850
+ break;
851
+
852
+ if (( para = (text != q->next) ))
853
+ ___mkd_freeLineRange(q, text);
854
+
855
+ q->next = 0;
856
+ if ( kind == 1 /* discount dl */ )
857
+ for ( q = labels; q; q = q->next ) {
858
+ CLIP(q->text, 0, 1);
859
+ S(q->text)--;
783
860
  }
861
+
862
+ dd_block:
863
+ p = Pp(&d, text, LISTITEM);
864
+
865
+ text = listitem(p, clip, f->flags, (kind==2) ? is_extra_dd : 0);
866
+ p->down = compile(p->text, 0, f);
867
+ p->text = labels; labels = 0;
868
+
869
+ if ( para && p->down ) p->down->align = PARA;
870
+
871
+ if ( (q = skipempty(text)) == 0 )
872
+ break;
873
+
874
+ if (( para = (q != text) )) {
875
+ Line anchor;
876
+
877
+ anchor.next = text;
878
+ ___mkd_freeLineRange(&anchor,q);
879
+ text = q;
880
+
784
881
  }
785
- else label = 0;
786
882
 
883
+ if ( kind == 2 && is_extra_dd(q) )
884
+ goto dd_block;
885
+ }
886
+ top->text = 0;
887
+ top->down = T(d);
888
+ return text;
889
+ }
890
+
891
+
892
+ static Line *
893
+ enumerated_block(Paragraph *top, int clip, MMIOT *f, int list_class)
894
+ {
895
+ ParagraphRoot d = { 0, 0 };
896
+ Paragraph *p;
897
+ Line *q = top->text, *text;
898
+ int para = 0, z;
899
+
900
+ while (( text = q )) {
901
+
787
902
  p = Pp(&d, text, LISTITEM);
788
- text = listitem(p, trim);
903
+ text = listitem(p, clip, f->flags, 0);
789
904
 
790
905
  p->down = compile(p->text, 0, f);
791
- p->text = label;
906
+ p->text = 0;
792
907
 
793
- if ( para && (top->typ != DL) && p->down ) p->down->align = PARA;
908
+ if ( para && p->down ) p->down->align = PARA;
794
909
 
795
- if ( !(q = skipempty(text)) || ((ltype = islist(q, &trim)) == 0)
796
- || (isdl != (ltype == DL)) )
910
+ if ( (q = skipempty(text)) == 0
911
+ || islist(q, &clip, f->flags, &z) != list_class )
797
912
  break;
798
913
 
799
914
  if ( para = (q != text) ) {
@@ -801,9 +916,9 @@ listblock(Paragraph *top, int trim, MMIOT *f)
801
916
 
802
917
  anchor.next = text;
803
918
  ___mkd_freeLineRange(&anchor, q);
804
- }
805
919
 
806
- if ( para && (top->typ != DL) && p->down ) p->down->align = PARA;
920
+ if ( p->down ) p->down->align = PARA;
921
+ }
807
922
  }
808
923
  top->text = 0;
809
924
  top->down = T(d);
@@ -935,10 +1050,10 @@ compile_document(Line *ptr, MMIOT *f)
935
1050
  ANCHOR(Line) source = { 0, 0 };
936
1051
  Paragraph *p = 0;
937
1052
  struct kw *tag;
938
- int eaten;
1053
+ int eaten, unclosed;
939
1054
 
940
1055
  while ( ptr ) {
941
- if ( !(f->flags & DENY_HTML) && (tag = isopentag(ptr)) ) {
1056
+ if ( !(f->flags & MKD_NOHTML) && (tag = isopentag(ptr)) ) {
942
1057
  /* If we encounter a html/style block, compile and save all
943
1058
  * of the cached source BEFORE processing the html/style.
944
1059
  */
@@ -949,7 +1064,12 @@ compile_document(Line *ptr, MMIOT *f)
949
1064
  T(source) = E(source) = 0;
950
1065
  }
951
1066
  p = Pp(&d, ptr, strcmp(tag->id, "STYLE") == 0 ? STYLE : HTML);
952
- ptr = htmlblock(p, tag);
1067
+ ptr = htmlblock(p, tag, &unclosed);
1068
+ if ( unclosed ) {
1069
+ p->typ = SOURCE;
1070
+ p->down = compile(p->text, 1, f);
1071
+ p->text = 0;
1072
+ }
953
1073
  }
954
1074
  else if ( isfootnote(ptr) ) {
955
1075
  /* footnotes, like cats, sleep anywhere; pull them
@@ -991,7 +1111,7 @@ compile(Line *ptr, int toplevel, MMIOT *f)
991
1111
  Line *r;
992
1112
  int para = toplevel;
993
1113
  int blocks = 0;
994
- int hdr_type, list_type, indent;
1114
+ int hdr_type, list_type, list_class, indent;
995
1115
 
996
1116
  ptr = consume(ptr, &para);
997
1117
 
@@ -1014,13 +1134,19 @@ compile(Line *ptr, int toplevel, MMIOT *f)
1014
1134
  ptr = ptr->next;
1015
1135
  ___mkd_freeLine(r);
1016
1136
  }
1017
- else if (( list_type = islist(ptr, &indent) )) {
1018
- p = Pp(&d, ptr, list_type);
1019
- ptr = listblock(p, indent, f);
1137
+ else if (( list_class = islist(ptr, &indent, f->flags, &list_type) )) {
1138
+ if ( list_class == DL ) {
1139
+ p = Pp(&d, ptr, DL);
1140
+ ptr = definition_block(p, indent, f, list_type);
1141
+ }
1142
+ else {
1143
+ p = Pp(&d, ptr, list_type);
1144
+ ptr = enumerated_block(p, indent, f, list_class);
1145
+ }
1020
1146
  }
1021
1147
  else if ( isquote(ptr) ) {
1022
1148
  p = Pp(&d, ptr, QUOTE);
1023
- ptr = quoteblock(p);
1149
+ ptr = quoteblock(p, f->flags);
1024
1150
  p->down = compile(p->text, 1, f);
1025
1151
  p->text = 0;
1026
1152
  }
@@ -1028,13 +1154,13 @@ compile(Line *ptr, int toplevel, MMIOT *f)
1028
1154
  p = Pp(&d, ptr, HDR);
1029
1155
  ptr = headerblock(p, hdr_type);
1030
1156
  }
1031
- else if ( istable(ptr) && !(f->flags & (STRICT|NOTABLES)) ) {
1157
+ else if ( istable(ptr) && !(f->flags & (MKD_STRICT|MKD_NOTABLES)) ) {
1032
1158
  p = Pp(&d, ptr, TABLE);
1033
1159
  ptr = tableblock(p);
1034
1160
  }
1035
1161
  else {
1036
1162
  p = Pp(&d, ptr, MARKUP);
1037
- ptr = textblock(p, toplevel);
1163
+ ptr = textblock(p, toplevel, f->flags);
1038
1164
  }
1039
1165
 
1040
1166
  if ( (para||toplevel) && !p->align )
@@ -1052,19 +1178,6 @@ compile(Line *ptr, int toplevel, MMIOT *f)
1052
1178
  }
1053
1179
 
1054
1180
 
1055
- void
1056
- mkd_initialize()
1057
- {
1058
- static int first = 1;
1059
-
1060
- if ( first-- > 0 ) {
1061
- first = 0;
1062
- INITRNG(time(0));
1063
- mkd_prepare_tags();
1064
- }
1065
- }
1066
-
1067
-
1068
1181
  /*
1069
1182
  * the guts of the markdown() function, ripped out so I can do
1070
1183
  * debugging.
@@ -1074,7 +1187,7 @@ mkd_initialize()
1074
1187
  * prepare and compile `text`, returning a Paragraph tree.
1075
1188
  */
1076
1189
  int
1077
- mkd_compile(Document *doc, int flags)
1190
+ mkd_compile(Document *doc, DWORD flags)
1078
1191
  {
1079
1192
  if ( !doc )
1080
1193
  return 0;