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/html5.c ADDED
@@ -0,0 +1,24 @@
1
+ /* block-level tags for passing html5 blocks through the blender
2
+ */
3
+ #include "tags.h"
4
+
5
+ void
6
+ mkd_with_html5_tags()
7
+ {
8
+ static int populated = 0;
9
+
10
+ if ( populated ) return;
11
+ populated = 1;
12
+
13
+ mkd_prepare_tags();
14
+
15
+ mkd_define_tag("ASIDE", 0);
16
+ mkd_define_tag("FOOTER", 0);
17
+ mkd_define_tag("HEADER", 0);
18
+ mkd_define_tag("HGROUP", 0);
19
+ mkd_define_tag("NAV", 0);
20
+ mkd_define_tag("SECTION", 0);
21
+ mkd_define_tag("ARTICLE", 0);
22
+
23
+ mkd_sort_tags();
24
+ }
data/ext/markdown.c CHANGED
@@ -4,6 +4,8 @@
4
4
  * The redistribution terms are provided in the COPYRIGHT file that must
5
5
  * be distributed with this source code.
6
6
  */
7
+ #include "config.h"
8
+
7
9
  #include <stdio.h>
8
10
  #include <string.h>
9
11
  #include <stdarg.h>
@@ -11,51 +13,15 @@
11
13
  #include <time.h>
12
14
  #include <ctype.h>
13
15
 
14
- #include "config.h"
15
-
16
16
  #include "cstring.h"
17
17
  #include "markdown.h"
18
18
  #include "amalloc.h"
19
-
20
- /* block-level tags for passing html blocks through the blender
21
- */
22
- struct kw {
23
- char *id;
24
- int size;
25
- int selfclose;
26
- } ;
27
-
28
- #define KW(x) { x, sizeof(x)-1, 0 }
29
- #define SC(x) { x, sizeof(x)-1, 1 }
30
-
31
- static struct kw blocktags[] = { KW("!--"), KW("STYLE"), KW("SCRIPT"),
32
- KW("ADDRESS"), KW("BDO"), KW("BLOCKQUOTE"),
33
- KW("CENTER"), KW("DFN"), KW("DIV"), KW("H1"),
34
- KW("H2"), KW("H3"), KW("H4"), KW("H5"),
35
- KW("H6"), KW("LISTING"), KW("NOBR"),
36
- KW("UL"), KW("P"), KW("OL"), KW("DL"),
37
- KW("PLAINTEXT"), KW("PRE"), KW("TABLE"),
38
- KW("WBR"), KW("XMP"), SC("HR"), SC("BR"),
39
- KW("IFRAME"), KW("MAP") };
40
- #define SZTAGS (sizeof blocktags / sizeof blocktags[0])
41
- #define MAXTAG 11 /* sizeof "BLOCKQUOTE" */
19
+ #include "tags.h"
42
20
 
43
21
  typedef int (*stfu)(const void*,const void*);
44
22
 
45
23
  typedef ANCHOR(Paragraph) ParagraphRoot;
46
24
 
47
-
48
- /* case insensitive string sort (for qsort() and bsearch() of block tags)
49
- */
50
- static int
51
- casort(struct kw *a, struct kw *b)
52
- {
53
- if ( a->size != b->size )
54
- return a->size - b->size;
55
- return strncasecmp(a->id, b->id, b->size);
56
- }
57
-
58
-
59
25
  /* case insensitive string sort for Footnote tags.
60
26
  */
61
27
  int
@@ -135,19 +101,28 @@ ___mkd_tidy(Cstring *t)
135
101
  }
136
102
 
137
103
 
104
+ static struct kw comment = { "!--", 3, 0 };
105
+
138
106
  static struct kw *
139
107
  isopentag(Line *p)
140
108
  {
141
109
  int i=0, len;
142
- struct kw key, *ret;
110
+ char *line;
143
111
 
144
112
  if ( !p ) return 0;
145
113
 
114
+ line = T(p->text);
146
115
  len = S(p->text);
147
116
 
148
- if ( len < 3 || T(p->text)[0] != '<' )
117
+ if ( len < 3 || line[0] != '<' )
149
118
  return 0;
150
119
 
120
+ if ( line[1] == '!' && line[2] == '-' && line[3] == '-' )
121
+ /* comments need special case handling, because
122
+ * the !-- doesn't need to end in a whitespace
123
+ */
124
+ return &comment;
125
+
151
126
  /* find how long the tag is so we can check to see if
152
127
  * it's a block-level tag
153
128
  */
@@ -156,13 +131,8 @@ isopentag(Line *p)
156
131
  && !isspace(T(p->text)[i]); ++i )
157
132
  ;
158
133
 
159
- key.id = T(p->text)+1;
160
- key.size = i-1;
161
-
162
- if ( ret = bsearch(&key, blocktags, SZTAGS, sizeof key, (stfu)casort))
163
- return ret;
164
134
 
165
- return 0;
135
+ return mkd_search_tags(T(p->text)+1, i-1);
166
136
  }
167
137
 
168
138
 
@@ -171,6 +141,8 @@ typedef struct _flo {
171
141
  int i;
172
142
  } FLO;
173
143
 
144
+ #define floindex(x) (x.i)
145
+
174
146
 
175
147
  static int
176
148
  flogetc(FLO *f)
@@ -186,6 +158,41 @@ flogetc(FLO *f)
186
158
  }
187
159
 
188
160
 
161
+ static void
162
+ splitline(Line *t, int cutpoint)
163
+ {
164
+ if ( t && (cutpoint < S(t->text)) ) {
165
+ Line *tmp = calloc(1, sizeof *tmp);
166
+
167
+ tmp->next = t->next;
168
+ t->next = tmp;
169
+
170
+ tmp->dle = t->dle;
171
+ SUFFIX(tmp->text, T(t->text)+cutpoint, S(t->text)-cutpoint);
172
+ S(t->text) = cutpoint;
173
+ }
174
+ }
175
+
176
+
177
+ static Line *
178
+ commentblock(Paragraph *p)
179
+ {
180
+ Line *t, *ret;
181
+ char *end;
182
+
183
+ for ( t = p->text; t ; t = t->next) {
184
+ if ( end = strstr(T(t->text), "-->") ) {
185
+ splitline(t, 3 + (end - T(t->text)) );
186
+ ret = t->next;
187
+ t->next = 0;
188
+ return ret;
189
+ }
190
+ }
191
+ return t;
192
+
193
+ }
194
+
195
+
189
196
  static Line *
190
197
  htmlblock(Paragraph *p, struct kw *tag)
191
198
  {
@@ -194,7 +201,10 @@ htmlblock(Paragraph *p, struct kw *tag)
194
201
  int c;
195
202
  int i, closing, depth=0;
196
203
 
197
- if ( tag->selfclose || (tag->size >= MAXTAG) ) {
204
+ if ( tag == &comment )
205
+ return commentblock(p);
206
+
207
+ if ( tag->selfclose ) {
198
208
  ret = f.t->next;
199
209
  f.t->next = 0;
200
210
  return ret;
@@ -232,6 +242,7 @@ htmlblock(Paragraph *p, struct kw *tag)
232
242
  }
233
243
  if ( !f.t )
234
244
  return 0;
245
+ splitline(f.t, floindex(f));
235
246
  ret = f.t->next;
236
247
  f.t->next = 0;
237
248
  return ret;
@@ -244,23 +255,6 @@ htmlblock(Paragraph *p, struct kw *tag)
244
255
  }
245
256
 
246
257
 
247
- static Line *
248
- comment(Paragraph *p)
249
- {
250
- Line *t, *ret;
251
-
252
- for ( t = p->text; t ; t = t->next) {
253
- if ( strstr(T(t->text), "-->") ) {
254
- ret = t->next;
255
- t->next = 0;
256
- return ret;
257
- }
258
- }
259
- return t;
260
-
261
- }
262
-
263
-
264
258
  /* tables look like
265
259
  * header|header{|header}
266
260
  * ------|------{|......}
@@ -305,8 +299,8 @@ isfootnote(Line *t)
305
299
  for ( ++i; i < S(t->text) ; ++i ) {
306
300
  if ( T(t->text)[i] == '[' )
307
301
  return 0;
308
- else if ( T(t->text)[i] == ']' && T(t->text)[i+1] == ':' )
309
- return 1;
302
+ else if ( T(t->text)[i] == ']' )
303
+ return ( T(t->text)[i+1] == ':' ) ;
310
304
  }
311
305
  return 0;
312
306
  }
@@ -315,7 +309,14 @@ isfootnote(Line *t)
315
309
  static int
316
310
  isquote(Line *t)
317
311
  {
318
- return ( T(t->text)[0] == '>' );
312
+ int j;
313
+
314
+ for ( j=0; j < 4; j++ )
315
+ if ( T(t->text)[j] == '>' )
316
+ return 1;
317
+ else if ( !isspace(T(t->text)[j]) )
318
+ return 0;
319
+ return 0;
319
320
  }
320
321
 
321
322
 
@@ -355,6 +356,34 @@ ishr(Line *t)
355
356
  }
356
357
 
357
358
 
359
+ static int
360
+ issetext(Line *t, int *htyp)
361
+ {
362
+ int i;
363
+ /* then check for setext-style HEADER
364
+ * ======
365
+ */
366
+
367
+ if ( t->next ) {
368
+ char *q = T(t->next->text);
369
+ int last = S(t->next->text);
370
+
371
+ if ( (*q == '=') || (*q == '-') ) {
372
+ /* ignore trailing whitespace */
373
+ while ( (last > 1) && isspace(q[last-1]) )
374
+ --last;
375
+
376
+ for (i=1; i < last; i++)
377
+ if ( q[0] != q[i] )
378
+ return 0;
379
+ *htyp = SETEXT;
380
+ return 1;
381
+ }
382
+ }
383
+ return 0;
384
+ }
385
+
386
+
358
387
  static int
359
388
  ishdr(Line *t, int *htyp)
360
389
  {
@@ -376,22 +405,7 @@ ishdr(Line *t, int *htyp)
376
405
  return 1;
377
406
  }
378
407
 
379
- /* then check for setext-style HEADER
380
- * ======
381
- */
382
-
383
- if ( t->next ) {
384
- char *q = T(t->next->text);
385
-
386
- if ( (*q == '=') || (*q == '-') ) {
387
- for (i=1; i < S(t->next->text); i++)
388
- if ( q[0] != q[i] )
389
- return 0;
390
- *htyp = SETEXT;
391
- return 1;
392
- }
393
- }
394
- return 0;
408
+ return issetext(t, htyp);
395
409
  }
396
410
 
397
411
 
@@ -475,7 +489,8 @@ headerblock(Paragraph *pp, int htyp)
475
489
  * the leading and trailing `#`'s
476
490
  */
477
491
 
478
- for (i=0; (T(p->text)[i] == T(p->text)[0]) && (i < S(p->text)-1); i++)
492
+ for (i=0; (T(p->text)[i] == T(p->text)[0]) && (i < S(p->text)-1)
493
+ && (i < 6); i++)
479
494
  ;
480
495
 
481
496
  pp->hnumber = i;
@@ -629,7 +644,16 @@ quoteblock(Paragraph *p)
629
644
 
630
645
  for ( t = p->text; t ; t = q ) {
631
646
  if ( isquote(t) ) {
632
- qp = (T(t->text)[1] == ' ') ? 2 : 1;
647
+ /* clip leading spaces */
648
+ for (qp = 0; T(t->text)[qp] != '>'; qp ++)
649
+ /* assert: the first nonblank character on this line
650
+ * will be a >
651
+ */;
652
+ /* clip '>' */
653
+ qp++;
654
+ /* clip next space, if any */
655
+ if ( T(t->text)[qp] == ' ' )
656
+ qp++;
633
657
  CLIP(t->text, 0, qp);
634
658
  t->dle = mkd_firstnonblank(t);
635
659
  }
@@ -709,8 +733,9 @@ listitem(Paragraph *p, int indent)
709
733
  }
710
734
 
711
735
  /* after a blank line, the next block needs to start with a line
712
- * that's indented 4 spaces, but after that the line doesn't
713
- * need any indentation
736
+ * that's indented 4(? -- reference implementation allows a 1
737
+ * character indent, but that has unfortunate side effects here)
738
+ * spaces, but after that the line doesn't need any indentation
714
739
  */
715
740
  if ( q != t->next ) {
716
741
  if (q->dle < indent) {
@@ -718,10 +743,12 @@ listitem(Paragraph *p, int indent)
718
743
  t->next = 0;
719
744
  return q;
720
745
  }
721
- indent = 4;
746
+ /* indent at least 2, and at most as
747
+ * as far as the initial line was indented. */
748
+ indent = clip ? clip : 2;
722
749
  }
723
750
 
724
- if ( (q->dle < indent) && (ishr(q) || islist(q,&z)) && !ishdr(q,&z) ) {
751
+ if ( (q->dle < indent) && (ishr(q) || islist(q,&z)) && !issetext(q,&z) ) {
725
752
  q = t->next;
726
753
  t->next = 0;
727
754
  return q;
@@ -922,10 +949,7 @@ compile_document(Line *ptr, MMIOT *f)
922
949
  T(source) = E(source) = 0;
923
950
  }
924
951
  p = Pp(&d, ptr, strcmp(tag->id, "STYLE") == 0 ? STYLE : HTML);
925
- if ( strcmp(tag->id, "!--") == 0 )
926
- ptr = comment(p);
927
- else
928
- ptr = htmlblock(p, tag);
952
+ ptr = htmlblock(p, tag);
929
953
  }
930
954
  else if ( isfootnote(ptr) ) {
931
955
  /* footnotes, like cats, sleep anywhere; pull them
@@ -1028,15 +1052,15 @@ compile(Line *ptr, int toplevel, MMIOT *f)
1028
1052
  }
1029
1053
 
1030
1054
 
1031
- static void
1032
- initialize()
1055
+ void
1056
+ mkd_initialize()
1033
1057
  {
1034
1058
  static int first = 1;
1035
1059
 
1036
1060
  if ( first-- > 0 ) {
1037
1061
  first = 0;
1038
1062
  INITRNG(time(0));
1039
- qsort(blocktags, SZTAGS, sizeof blocktags[0], (stfu)casort);
1063
+ mkd_prepare_tags();
1040
1064
  }
1041
1065
  }
1042
1066
 
@@ -1060,13 +1084,13 @@ mkd_compile(Document *doc, int flags)
1060
1084
 
1061
1085
  doc->compiled = 1;
1062
1086
  memset(doc->ctx, 0, sizeof(MMIOT) );
1063
- doc->ctx->flags = flags & USER_FLAGS;
1064
- doc->ctx->base = doc->base;
1087
+ doc->ctx->cb = &(doc->cb);
1088
+ doc->ctx->flags = flags & USER_FLAGS;
1065
1089
  CREATE(doc->ctx->in);
1066
1090
  doc->ctx->footnotes = malloc(sizeof doc->ctx->footnotes[0]);
1067
1091
  CREATE(*doc->ctx->footnotes);
1068
1092
 
1069
- initialize();
1093
+ mkd_initialize();
1070
1094
 
1071
1095
  doc->code = compile_document(T(doc->content), doc->ctx);
1072
1096
  qsort(T(*doc->ctx->footnotes), S(*doc->ctx->footnotes),
data/ext/markdown.h CHANGED
@@ -56,6 +56,17 @@ typedef struct block {
56
56
  typedef STRING(block) Qblock;
57
57
 
58
58
 
59
+ typedef char* (*mkd_callback_t)(const char*, const int, void*);
60
+ typedef void (*mkd_free_t)(char*, void*);
61
+
62
+ typedef struct callback_data {
63
+ void *e_data; /* private data for callbacks */
64
+ mkd_callback_t e_url; /* url edit callback */
65
+ mkd_callback_t e_flags; /* extra href flags callback */
66
+ mkd_free_t e_free; /* edit/flags callback memory deallocator */
67
+ } Callback_data;
68
+
69
+
59
70
  /* a magic markdown io thing holds all the data structures needed to
60
71
  * do the backend processing of a markdown document
61
72
  */
@@ -75,13 +86,14 @@ typedef struct mmiot {
75
86
  #define NO_PSEUDO_PROTO 0x0040
76
87
  #define CDATA_OUTPUT 0x0080
77
88
  #define NOTABLES 0x0400
89
+ #define NOSTRIKETHROUGH 0x0800
78
90
  #define TOC 0x1000
79
91
  #define MKD_1_COMPAT 0x2000
80
92
  #define AUTOLINK 0x4000
81
93
  #define SAFELINK 0x8000
82
94
  #define USER_FLAGS 0xFCFF
83
95
  #define EMBEDDED DENY_A|DENY_IMG|NO_PSEUDO_PROTO|CDATA_OUTPUT
84
- char *base;
96
+ Callback_data *cb;
85
97
  } MMIOT;
86
98
 
87
99
 
@@ -93,6 +105,8 @@ typedef struct mmiot {
93
105
  * root of the linked list of Lines.
94
106
  */
95
107
  typedef struct document {
108
+ int magic; /* "I AM VALID" magic number */
109
+ #define VALID_DOCUMENT 0x19600731
96
110
  Line *headers; /* title -> author(s) -> date */
97
111
  ANCHOR(Line) content; /* uncompiled text, not valid after compile() */
98
112
  Paragraph *code; /* intermediate code generated by compile() */
@@ -100,7 +114,7 @@ typedef struct document {
100
114
  int html; /* set after (internal) htmlify() */
101
115
  int tabstop; /* for properly expanding tabs (ick) */
102
116
  MMIOT *ctx; /* backend buffers, flags, and structures */
103
- char *base; /* url basename for url fragments */
117
+ Callback_data cb; /* callback functions & private data */
104
118
  } Document;
105
119
 
106
120