rdiscount 2.2.0.1 → 2.2.7

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/ext/markdown.c CHANGED
@@ -147,12 +147,12 @@ typedef struct _flo {
147
147
  #define floindex(x) (x.i)
148
148
 
149
149
 
150
- static int
150
+ static unsigned int
151
151
  flogetc(FLO *f)
152
152
  {
153
153
  if ( f && f->t ) {
154
154
  if ( f->i < S(f->t->text) )
155
- return T(f->t->text)[f->i++];
155
+ return (unsigned char)T(f->t->text)[f->i++];
156
156
  f->t = f->t->next;
157
157
  f->i = 0;
158
158
  return flogetc(f);
@@ -170,8 +170,10 @@ splitline(Line *t, int cutpoint)
170
170
  tmp->next = t->next;
171
171
  t->next = tmp;
172
172
 
173
- tmp->dle = t->dle;
174
173
  SUFFIX(tmp->text, T(t->text)+cutpoint, S(t->text)-cutpoint);
174
+ EXPAND(tmp->text) = 0;
175
+ S(tmp->text)--;
176
+
175
177
  S(t->text) = cutpoint;
176
178
  }
177
179
  }
@@ -187,7 +189,7 @@ splitline(Line *t, int cutpoint)
187
189
  * types.
188
190
  */
189
191
  static void
190
- checkline(Line *l, DWORD flags)
192
+ checkline(Line *l, mkd_flag_t flags)
191
193
  {
192
194
  int eol, i;
193
195
  int dashes = 0, spaces = 0,
@@ -213,11 +215,11 @@ checkline(Line *l, DWORD flags)
213
215
  switch (c) {
214
216
  case '-': UNLESS_FENCED(dashes = 1); break;
215
217
  case ' ': UNLESS_FENCED(spaces = 1); break;
216
- case '=': equals = 1; break;
218
+ case '=': UNLESS_FENCED(equals = 1); break;
217
219
  case '_': UNLESS_FENCED(underscores = 1); break;
218
220
  case '*': stars = 1; break;
219
221
  default:
220
- if (flags & MKD_FENCEDCODE) {
222
+ if ( is_flag_set(flags, MKD_FENCEDCODE) ) {
221
223
  switch (c) {
222
224
  case '~': if (other) return; is_fence_char = 1; tildes = 1; break;
223
225
  case '`': if (other) return; is_fence_char = 1; backticks = 1; break;
@@ -379,7 +381,7 @@ iscode(Line *t)
379
381
 
380
382
 
381
383
  static inline int
382
- ishr(Line *t, DWORD flags)
384
+ ishr(Line *t, mkd_flag_t flags)
383
385
  {
384
386
  if ( ! (t->flags & CHECKED) )
385
387
  checkline(t, flags);
@@ -391,7 +393,7 @@ ishr(Line *t, DWORD flags)
391
393
 
392
394
 
393
395
  static int
394
- issetext(Line *t, int *htyp, DWORD flags)
396
+ issetext(Line *t, int *htyp, mkd_flag_t flags)
395
397
  {
396
398
  Line *n;
397
399
 
@@ -413,7 +415,7 @@ issetext(Line *t, int *htyp, DWORD flags)
413
415
 
414
416
 
415
417
  static int
416
- ishdr(Line *t, int *htyp, DWORD flags)
418
+ ishdr(Line *t, int *htyp, mkd_flag_t flags)
417
419
  {
418
420
  /* ANY leading `#`'s make this into an ETX header
419
421
  */
@@ -429,7 +431,7 @@ ishdr(Line *t, int *htyp, DWORD flags)
429
431
 
430
432
 
431
433
  static inline int
432
- end_of_block(Line *t, DWORD flags)
434
+ end_of_block(Line *t, mkd_flag_t flags)
433
435
  {
434
436
  int dummy;
435
437
 
@@ -441,9 +443,9 @@ end_of_block(Line *t, DWORD flags)
441
443
 
442
444
 
443
445
  static Line*
444
- is_discount_dt(Line *t, int *clip, DWORD flags)
446
+ is_discount_dt(Line *t, int *clip, mkd_flag_t flags)
445
447
  {
446
- if ( !(flags & MKD_NODLDISCOUNT)
448
+ if ( !is_flag_set(flags, MKD_NODLDISCOUNT)
447
449
  && t
448
450
  && t->next
449
451
  && (S(t->text) > 2)
@@ -470,9 +472,9 @@ is_extra_dd(Line *t)
470
472
 
471
473
 
472
474
  static Line*
473
- is_extra_dt(Line *t, int *clip, DWORD flags)
475
+ is_extra_dt(Line *t, int *clip, mkd_flag_t flags)
474
476
  {
475
- if ( flags & MKD_DLEXTRA
477
+ if ( is_flag_set(flags, MKD_DLEXTRA)
476
478
  && t
477
479
  && t->next && S(t->text) && T(t->text)[0] != '='
478
480
  && T(t->text)[S(t->text)-1] != '=') {
@@ -494,7 +496,7 @@ is_extra_dt(Line *t, int *clip, DWORD flags)
494
496
 
495
497
 
496
498
  static Line*
497
- isdefinition(Line *t, int *clip, int *kind, DWORD flags)
499
+ isdefinition(Line *t, int *clip, int *kind, mkd_flag_t flags)
498
500
  {
499
501
  Line *ret;
500
502
 
@@ -508,7 +510,7 @@ isdefinition(Line *t, int *clip, int *kind, DWORD flags)
508
510
 
509
511
 
510
512
  static int
511
- islist(Line *t, int *clip, DWORD flags, int *list_type)
513
+ islist(Line *t, int *clip, mkd_flag_t flags, int *list_type)
512
514
  {
513
515
  int i, j;
514
516
  char *q;
@@ -516,21 +518,22 @@ islist(Line *t, int *clip, DWORD flags, int *list_type)
516
518
  if ( end_of_block(t, flags) )
517
519
  return 0;
518
520
 
519
- if ( !(flags & (MKD_NODLIST|MKD_STRICT)) && isdefinition(t,clip,list_type,flags) )
521
+ if ( !(is_flag_set(flags, MKD_NODLIST) || is_flag_set(flags, MKD_STRICT))
522
+ && isdefinition(t,clip,list_type,flags) )
520
523
  return DL;
521
524
 
522
525
  if ( strchr("*-+", T(t->text)[t->dle]) && isspace(T(t->text)[t->dle+1]) ) {
523
526
  i = nextnonblank(t, t->dle+1);
524
527
  *clip = (i > 4) ? 4 : i;
525
528
  *list_type = UL;
526
- return AL;
529
+ return is_flag_set(flags, MKD_EXPLICITLIST) ? UL : AL;
527
530
  }
528
531
 
529
532
  if ( (j = nextblank(t,t->dle)) > t->dle ) {
530
533
  if ( T(t->text)[j-1] == '.' ) {
531
534
 
532
- if ( !(flags & (MKD_NOALPHALIST|MKD_STRICT))
533
- && (j == t->dle + 2)
535
+ if ( !(is_flag_set(flags, MKD_NOALPHALIST) || is_flag_set(flags, MKD_STRICT))
536
+ && (j == t->dle + 2)
534
537
  && isalpha(T(t->text)[t->dle]) ) {
535
538
  j = nextnonblank(t,j);
536
539
  *clip = (j > 4) ? 4 : j;
@@ -608,8 +611,7 @@ codeblock(Paragraph *p)
608
611
  Line *t = p->text, *r;
609
612
 
610
613
  for ( ; t; t = r ) {
611
- CLIP(t->text,0,4);
612
- t->dle = mkd_firstnonblank(t);
614
+ __mkd_trim_line(t,4);
613
615
 
614
616
  if ( !( (r = skipempty(t->next)) && iscode(r)) ) {
615
617
  ___mkd_freeLineRange(t,r);
@@ -622,9 +624,9 @@ codeblock(Paragraph *p)
622
624
 
623
625
 
624
626
  static int
625
- iscodefence(Line *r, int size, line_type kind, DWORD flags)
627
+ iscodefence(Line *r, int size, line_type kind, mkd_flag_t flags)
626
628
  {
627
- if ( !(flags & MKD_FENCEDCODE) )
629
+ if ( !is_flag_set(flags, MKD_FENCEDCODE) )
628
630
  return 0;
629
631
 
630
632
  if ( !(r->flags & CHECKED) )
@@ -636,39 +638,40 @@ iscodefence(Line *r, int size, line_type kind, DWORD flags)
636
638
  return (r->kind == chk_tilde || r->kind == chk_backtick) && (r->count >= size);
637
639
  }
638
640
 
641
+
639
642
  static Paragraph *
640
- fencedcodeblock(ParagraphRoot *d, Line **ptr, DWORD flags)
643
+ fencedcodeblock(ParagraphRoot *d, Line **ptr, mkd_flag_t flags)
641
644
  {
642
645
  Line *first, *r;
643
646
  Paragraph *ret;
644
647
 
645
648
  first = (*ptr);
646
-
649
+
647
650
  /* don't allow zero-length code fences
648
- */
651
+ */
649
652
  if ( (first->next == 0) || iscodefence(first->next, first->count, 0, flags) )
650
653
  return 0;
651
654
 
652
655
  /* find the closing fence, discard the fences,
653
- * return a Paragraph with the contents
654
- */
656
+ * return a Paragraph with the contents
657
+ */
655
658
  for ( r = first; r && r->next; r = r->next )
656
659
  if ( iscodefence(r->next, first->count, first->kind, flags) ) {
657
660
  (*ptr) = r->next->next;
658
661
  ret = Pp(d, first->next, CODE);
659
- if (S(first->text) - first->count > 0) {
660
- char *lang_attr = T(first->text) + first->count;
661
- while ( *lang_attr != 0 && *lang_attr == ' ' ) lang_attr++;
662
- ret->lang = strdup(lang_attr);
663
- }
664
- else {
665
- ret->lang = 0;
666
- }
667
- ___mkd_freeLine(first);
668
- ___mkd_freeLine(r->next);
669
- r->next = 0;
670
- return ret;
662
+ if (S(first->text) - first->count > 0) {
663
+ char *lang_attr = T(first->text) + first->count;
664
+ while ( *lang_attr != 0 && *lang_attr == ' ' ) lang_attr++;
665
+ ret->lang = strdup(lang_attr);
666
+ }
667
+ else {
668
+ ret->lang = 0;
671
669
  }
670
+ ___mkd_freeLine(first);
671
+ ___mkd_freeLine(r->next);
672
+ r->next = 0;
673
+ return ret;
674
+ }
672
675
  return 0;
673
676
  }
674
677
 
@@ -692,7 +695,7 @@ centered(Line *first, Line *last)
692
695
 
693
696
 
694
697
  static int
695
- endoftextblock(Line *t, int toplevelblock, DWORD flags)
698
+ endoftextblock(Line *t, int toplevelblock, mkd_flag_t flags)
696
699
  {
697
700
  int z;
698
701
 
@@ -712,7 +715,7 @@ endoftextblock(Line *t, int toplevelblock, DWORD flags)
712
715
 
713
716
 
714
717
  static Line *
715
- textblock(Paragraph *p, int toplevel, DWORD flags)
718
+ textblock(Paragraph *p, int toplevel, mkd_flag_t flags)
716
719
  {
717
720
  Line *t, *next;
718
721
 
@@ -747,12 +750,12 @@ szmarkerclass(char *p)
747
750
  #define iscsschar(c) (isalpha(c) || (c == '-') || (c == '_') )
748
751
 
749
752
  static int
750
- isdivmarker(Line *p, int start, DWORD flags)
753
+ isdivmarker(Line *p, int start, mkd_flag_t flags)
751
754
  {
752
755
  char *s;
753
756
  int last, i;
754
757
 
755
- if ( flags & (MKD_NODIVQUOTE|MKD_STRICT) )
758
+ if ( is_flag_set(flags, MKD_NODIVQUOTE) || is_flag_set(flags, MKD_STRICT) )
756
759
  return 0;
757
760
 
758
761
  start = nextnonblank(p, start);
@@ -786,7 +789,7 @@ isdivmarker(Line *p, int start, DWORD flags)
786
789
  * way the markdown sample web form at Daring Fireball works.
787
790
  */
788
791
  static Line *
789
- quoteblock(Paragraph *p, DWORD flags)
792
+ quoteblock(Paragraph *p, mkd_flag_t flags)
790
793
  {
791
794
  Line *t, *q;
792
795
  int qp;
@@ -803,9 +806,8 @@ quoteblock(Paragraph *p, DWORD flags)
803
806
  /* clip next space, if any */
804
807
  if ( T(t->text)[qp] == ' ' )
805
808
  qp++;
806
- CLIP(t->text, 0, qp);
809
+ __mkd_trim_line(t,qp);
807
810
  UNCHECK(t);
808
- t->dle = mkd_firstnonblank(t);
809
811
  }
810
812
 
811
813
  q = skipempty(t->next);
@@ -847,16 +849,40 @@ typedef int (*linefn)(Line *);
847
849
  * marker, but multiple paragraphs need to start with a 4-space indent.
848
850
  */
849
851
  static Line *
850
- listitem(Paragraph *p, int indent, DWORD flags, linefn check)
852
+ listitem(Paragraph *p, int indent, mkd_flag_t flags, linefn check)
851
853
  {
852
854
  Line *t, *q;
853
855
  int clip = indent;
854
856
  int z;
857
+ #ifdef GITHUB_CHECKBOX
858
+ int firstpara = 1;
859
+ int ischeck;
860
+ #define CHECK_NOT 0
861
+ #define CHECK_NO 1
862
+ #define CHECK_YES 2
863
+ #endif
855
864
 
856
865
  for ( t = p->text; t ; t = q) {
857
- CLIP(t->text, 0, clip);
858
866
  UNCHECK(t);
859
- t->dle = mkd_firstnonblank(t);
867
+ __mkd_trim_line(t, clip);
868
+
869
+ #ifdef GITHUB_CHECKBOX
870
+ if ( firstpara ) {
871
+ ischeck = CHECK_NOT;
872
+ if ( strncmp(T(t->text)+t->dle, "[ ]", 3) == 0 )
873
+ ischeck = CHECK_NO;
874
+ else if ( strncasecmp(T(t->text)+t->dle, "[x]", 3) == 0 )
875
+ ischeck = CHECK_YES;
876
+
877
+ if ( ischeck != CHECK_NOT ) {
878
+ __mkd_trim_line(t, 3);
879
+ p->flags |= GITHUB_CHECK;
880
+ if ( ischeck == CHECK_YES )
881
+ p->flags |= IS_CHECKED;
882
+ }
883
+ firstpara = 0;
884
+ }
885
+ #endif
860
886
 
861
887
  /* even though we had to trim a long leader off this item,
862
888
  * the indent for trailing paragraphs is still 4...
@@ -1005,6 +1031,28 @@ tgood(char c)
1005
1031
  }
1006
1032
 
1007
1033
 
1034
+ /*
1035
+ * eat lines for a markdown extra footnote
1036
+ */
1037
+ static Line *
1038
+ extrablock(Line *p)
1039
+ {
1040
+ Line *np;
1041
+
1042
+ while ( p && p->next ) {
1043
+ np = p->next;
1044
+
1045
+ if ( np->dle < 4 && np->dle < S(np->text) ) {
1046
+ p->next = 0;
1047
+ return np;
1048
+ }
1049
+ __mkd_trim_line(np,4);
1050
+ p = np;
1051
+ }
1052
+ return 0;
1053
+ }
1054
+
1055
+
1008
1056
  /*
1009
1057
  * add a new (image or link) footnote to the footnote table
1010
1058
  */
@@ -1020,20 +1068,31 @@ addfootnote(Line *p, MMIOT* f)
1020
1068
  CREATE(foot->tag);
1021
1069
  CREATE(foot->link);
1022
1070
  CREATE(foot->title);
1071
+ foot->text = 0;
1023
1072
  foot->flags = foot->height = foot->width = 0;
1024
1073
 
1074
+ /* keep the footnote label */
1025
1075
  for (j=i=p->dle+1; T(p->text)[j] != ']'; j++)
1026
1076
  EXPAND(foot->tag) = T(p->text)[j];
1027
-
1028
1077
  EXPAND(foot->tag) = 0;
1029
1078
  S(foot->tag)--;
1079
+
1080
+ /* consume the closing ]: */
1030
1081
  j = nextnonblank(p, j+2);
1031
1082
 
1032
- if ( (f->flags & MKD_EXTRA_FOOTNOTE) && (T(foot->tag)[0] == '^') ) {
1033
- /* need to consume all lines until non-indented block? */
1034
- while ( j < S(p->text) )
1035
- EXPAND(foot->title) = T(p->text)[j++];
1036
- goto skip_to_end;
1083
+ if ( is_flag_set(f->flags, MKD_EXTRA_FOOTNOTE) && (T(foot->tag)[0] == '^') ) {
1084
+ /* markdown extra footnote: All indented lines past this point;
1085
+ * the first line includes the footnote reference, so we need to
1086
+ * snip that out as we go.
1087
+ */
1088
+ foot->flags |= EXTRA_FOOTNOTE;
1089
+ __mkd_trim_line(p,j);
1090
+
1091
+ np = extrablock(p);
1092
+
1093
+ foot->text = compile(p, 0, f);
1094
+
1095
+ return np;
1037
1096
  }
1038
1097
 
1039
1098
  while ( (j < S(p->text)) && !isspace(T(p->text)[j]) )
@@ -1044,8 +1103,7 @@ addfootnote(Line *p, MMIOT* f)
1044
1103
 
1045
1104
  if ( T(p->text)[j] == '=' ) {
1046
1105
  sscanf(T(p->text)+j, "=%dx%d", &foot->width, &foot->height);
1047
- while ( (j < S(p->text)) && !isspace(T(p->text)[j]) )
1048
- ++j;
1106
+ j = nextblank(p, j);
1049
1107
  j = nextnonblank(p,j);
1050
1108
  }
1051
1109
 
@@ -1075,7 +1133,6 @@ addfootnote(Line *p, MMIOT* f)
1075
1133
  --S(foot->title);
1076
1134
  }
1077
1135
 
1078
- skip_to_end:
1079
1136
  ___mkd_freeLine(p);
1080
1137
  return np;
1081
1138
  }
@@ -1113,6 +1170,22 @@ consume(Line *ptr, int *eaten)
1113
1170
  }
1114
1171
 
1115
1172
 
1173
+ typedef ANCHOR(Line) Cache;
1174
+
1175
+ static void
1176
+ uncache(Cache *cache, ParagraphRoot *d, MMIOT *f)
1177
+ {
1178
+ Paragraph *p;
1179
+
1180
+ if ( T(*cache) ) {
1181
+ E(*cache)->next = 0;
1182
+ p = Pp(d, 0, SOURCE);
1183
+ p->down = compile(T(*cache), 1, f);
1184
+ T(*cache) = E(*cache) = 0;
1185
+ }
1186
+ }
1187
+
1188
+
1116
1189
  /*
1117
1190
  * top-level compilation; break the document into
1118
1191
  * style, html, and source blocks with footnote links
@@ -1122,25 +1195,21 @@ static Paragraph *
1122
1195
  compile_document(Line *ptr, MMIOT *f)
1123
1196
  {
1124
1197
  ParagraphRoot d = { 0, 0 };
1125
- ANCHOR(Line) source = { 0, 0 };
1198
+ Cache source = { 0, 0 };
1126
1199
  Paragraph *p = 0;
1127
1200
  struct kw *tag;
1128
1201
  int eaten, unclosed;
1202
+ int previous_was_break = 1;
1129
1203
 
1130
1204
  while ( ptr ) {
1131
- if ( !(f->flags & MKD_NOHTML) && (tag = isopentag(ptr)) ) {
1205
+ if ( !is_flag_set(f->flags, MKD_NOHTML) && (tag = isopentag(ptr)) ) {
1132
1206
  int blocktype;
1133
1207
  /* If we encounter a html/style block, compile and save all
1134
1208
  * of the cached source BEFORE processing the html/style.
1135
1209
  */
1136
- if ( T(source) ) {
1137
- E(source)->next = 0;
1138
- p = Pp(&d, 0, SOURCE);
1139
- p->down = compile(T(source), 1, f);
1140
- T(source) = E(source) = 0;
1141
- }
1210
+ uncache(&source, &d, f);
1142
1211
 
1143
- if ( f->flags & MKD_NOSTYLE )
1212
+ if (is_flag_set(f->flags, MKD_NOSTYLE) )
1144
1213
  blocktype = HTML;
1145
1214
  else
1146
1215
  blocktype = strcmp(tag->id, "STYLE") == 0 ? STYLE : HTML;
@@ -1151,6 +1220,7 @@ compile_document(Line *ptr, MMIOT *f)
1151
1220
  p->down = compile(p->text, 1, f);
1152
1221
  p->text = 0;
1153
1222
  }
1223
+ previous_was_break = 1;
1154
1224
  }
1155
1225
  else if ( isfootnote(ptr) ) {
1156
1226
  /* footnotes, like cats, sleep anywhere; pull them
@@ -1158,23 +1228,27 @@ compile_document(Line *ptr, MMIOT *f)
1158
1228
  * later processing
1159
1229
  */
1160
1230
  ptr = consume(addfootnote(ptr, f), &eaten);
1231
+ previous_was_break = 1;
1232
+ }
1233
+ else if ( previous_was_break && iscodefence(ptr,3,0,f->flags)) {
1234
+ uncache(&source, &d, f);
1235
+ if ( !fencedcodeblock(&d, &ptr, f->flags) ) /* just source */
1236
+ goto attach;
1161
1237
  }
1162
1238
  else {
1239
+ attach:
1163
1240
  /* source; cache it up to wait for eof or the
1164
1241
  * next html/style block
1165
1242
  */
1166
1243
  ATTACH(source,ptr);
1244
+ previous_was_break = blankline(ptr);
1167
1245
  ptr = ptr->next;
1168
1246
  }
1169
1247
  }
1170
- if ( T(source) ) {
1171
- /* if there's any cached source at EOF, compile
1172
- * it now.
1173
- */
1174
- E(source)->next = 0;
1175
- p = Pp(&d, 0, SOURCE);
1176
- p->down = compile(T(source), 1, f);
1177
- }
1248
+ /* if there's any cached source at EOF, compile
1249
+ * it now.
1250
+ */
1251
+ uncache(&source, &d, f);
1178
1252
  return T(d);
1179
1253
  }
1180
1254
 
@@ -1194,7 +1268,7 @@ actually_a_table(MMIOT *f, Line *pp)
1194
1268
  int c;
1195
1269
 
1196
1270
  /* tables need to be turned on */
1197
- if ( f->flags & (MKD_STRICT|MKD_NOTABLES) )
1271
+ if ( is_flag_set(f->flags, MKD_STRICT) || is_flag_set(f->flags, MKD_NOTABLES) )
1198
1272
  return 0;
1199
1273
 
1200
1274
  /* tables need three lines */
@@ -1249,10 +1323,11 @@ compile(Line *ptr, int toplevel, MMIOT *f)
1249
1323
  ptr = consume(ptr, &para);
1250
1324
 
1251
1325
  while ( ptr ) {
1326
+
1252
1327
  if ( iscode(ptr) ) {
1253
1328
  p = Pp(&d, ptr, CODE);
1254
1329
 
1255
- if ( f->flags & MKD_1_COMPAT) {
1330
+ if ( is_flag_set(f->flags, MKD_1_COMPAT) ) {
1256
1331
  /* HORRIBLE STANDARDS KLUDGE: the first line of every block
1257
1332
  * has trailing whitespace trimmed off.
1258
1333
  */
@@ -1290,13 +1365,39 @@ compile(Line *ptr, int toplevel, MMIOT *f)
1290
1365
  ptr = headerblock(p, hdr_type);
1291
1366
  }
1292
1367
  else {
1293
- p = Pp(&d, ptr, MARKUP);
1294
- ptr = textblock(p, toplevel, f->flags);
1295
- /* tables are a special kind of paragraph */
1296
- if ( actually_a_table(f, p->text) )
1297
- p->typ = TABLE;
1368
+ /* either markup or an html block element
1369
+ */
1370
+ struct kw *tag;
1371
+ int unclosed = 1;
1372
+
1373
+ p = Pp(&d, ptr, MARKUP); /* default to regular markup,
1374
+ * then check if it's an html
1375
+ * block. If it IS an html
1376
+ * block, htmlblock() will
1377
+ * populate this paragraph &
1378
+ * all we need to do is reset
1379
+ * the paragraph type to HTML,
1380
+ * otherwise the paragraph
1381
+ * remains empty and ready for
1382
+ * processing with textblock()
1383
+ */
1384
+
1385
+ if ( !is_flag_set(f->flags, MKD_NOHTML) && (tag = isopentag(ptr)) ) {
1386
+ /* possibly an html block
1387
+ */
1388
+
1389
+ ptr = htmlblock(p, tag, &unclosed);
1390
+ if ( ! unclosed ) {
1391
+ p->typ = HTML;
1392
+ }
1393
+ }
1394
+ if ( unclosed ) {
1395
+ ptr = textblock(p, toplevel, f->flags);
1396
+ /* tables are a special kind of paragraph */
1397
+ if ( actually_a_table(f, p->text) )
1398
+ p->typ = TABLE;
1399
+ }
1298
1400
  }
1299
-
1300
1401
  if ( (para||toplevel) && !p->align )
1301
1402
  p->align = PARA;
1302
1403
 
@@ -1321,7 +1422,7 @@ compile(Line *ptr, int toplevel, MMIOT *f)
1321
1422
  * prepare and compile `text`, returning a Paragraph tree.
1322
1423
  */
1323
1424
  int
1324
- mkd_compile(Document *doc, DWORD flags)
1425
+ mkd_compile(Document *doc, mkd_flag_t flags)
1325
1426
  {
1326
1427
  if ( !doc )
1327
1428
  return 0;
@@ -1329,9 +1430,10 @@ mkd_compile(Document *doc, DWORD flags)
1329
1430
  flags &= USER_FLAGS;
1330
1431
 
1331
1432
  if ( doc->compiled ) {
1332
- if ( doc->ctx->flags == flags )
1433
+ if ( doc->ctx->flags == flags && !doc->dirty)
1333
1434
  return 1;
1334
1435
  else {
1436
+ doc->compiled = doc->dirty = 0;
1335
1437
  if ( doc->code)
1336
1438
  ___mkd_freeParagraph(doc->code);
1337
1439
  if ( doc->ctx->footnotes )