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/generate.c CHANGED
@@ -56,16 +56,16 @@ peek(MMIOT *f, int i)
56
56
 
57
57
  i += (f->isp-1);
58
58
 
59
- return (i >= 0) && (i < S(f->in)) ? T(f->in)[i] : EOF;
59
+ return (i >= 0) && (i < S(f->in)) ? (unsigned char)T(f->in)[i] : EOF;
60
60
  }
61
61
 
62
62
 
63
63
  /* pull a byte from the input buffer
64
64
  */
65
- static inline int
65
+ static inline unsigned int
66
66
  pull(MMIOT *f)
67
67
  {
68
- return ( f->isp < S(f->in) ) ? T(f->in)[f->isp++] : EOF;
68
+ return ( f->isp < S(f->in) ) ? (unsigned char)T(f->in)[f->isp++] : EOF;
69
69
  }
70
70
 
71
71
 
@@ -108,8 +108,10 @@ isthisnonword(MMIOT *f, int i)
108
108
 
109
109
 
110
110
  /* return/set the current cursor position
111
+ * (when setting the current cursor position we also need to flush the
112
+ * last character written cache)
111
113
  */
112
- #define mmiotseek(f,x) (f->isp = x)
114
+ #define mmiotseek(f,x) ((f->isp = x), (f->last = 0))
113
115
  #define mmiottell(f) (f->isp)
114
116
 
115
117
 
@@ -129,7 +131,7 @@ static void
129
131
  Qchar(int c, MMIOT *f)
130
132
  {
131
133
  block *cur;
132
-
134
+
133
135
  if ( S(f->Q) == 0 ) {
134
136
  cur = &EXPAND(f->Q);
135
137
  memset(cur, 0, sizeof *cur);
@@ -139,7 +141,7 @@ Qchar(int c, MMIOT *f)
139
141
  cur = &T(f->Q)[S(f->Q)-1];
140
142
 
141
143
  EXPAND(cur->b_text) = c;
142
-
144
+
143
145
  }
144
146
 
145
147
 
@@ -178,6 +180,16 @@ Qprintf(MMIOT *f, char *fmt, ...)
178
180
  }
179
181
 
180
182
 
183
+ /* Qanchor() prints out a suitable-for-id-tag version of a string
184
+ */
185
+ static void
186
+ Qanchor(struct line *p, MMIOT *f)
187
+ {
188
+ mkd_string_to_anchor(T(p->text), S(p->text),
189
+ (mkd_sta_function_t)Qchar, f, 1, f);
190
+ }
191
+
192
+
181
193
  /* Qem()
182
194
  */
183
195
  static void
@@ -197,13 +209,13 @@ Qem(MMIOT *f, char c, int count)
197
209
  /* generate html from a markup fragment
198
210
  */
199
211
  void
200
- ___mkd_reparse(char *bfr, int size, int flags, MMIOT *f, char *esc)
212
+ ___mkd_reparse(char *bfr, int size, mkd_flag_t flags, MMIOT *f, char *esc)
201
213
  {
202
214
  MMIOT sub;
203
215
  struct escaped e;
204
216
 
205
217
  ___mkd_initmmiot(&sub, f->footnotes);
206
-
218
+
207
219
  sub.flags = f->flags | flags;
208
220
  sub.cb = f->cb;
209
221
  sub.ref_prefix = f->ref_prefix;
@@ -219,11 +231,16 @@ ___mkd_reparse(char *bfr, int size, int flags, MMIOT *f, char *esc)
219
231
  push(bfr, size, &sub);
220
232
  pushc(0, &sub);
221
233
  S(sub.in)--;
222
-
234
+
223
235
  text(&sub);
224
236
  ___mkd_emblock(&sub);
225
-
237
+
226
238
  Qwrite(T(sub.out), S(sub.out), f);
239
+ /* inherit the last character printed from the reparsed
240
+ * text; this way superscripts can work when they're
241
+ * applied to something embedded in a link
242
+ */
243
+ f->last = sub.last;
227
244
 
228
245
  ___mkd_freemmiot(&sub, f->footnotes);
229
246
  }
@@ -263,7 +280,7 @@ puturl(char *s, int size, MMIOT *f, int display)
263
280
  if ( !( ispunct(c) || isspace(c) ) )
264
281
  Qchar('\\', f);
265
282
  }
266
-
283
+
267
284
  if ( c == '&' )
268
285
  Qstring("&amp;", f);
269
286
  else if ( c == '<' )
@@ -431,7 +448,7 @@ linkybroket(MMIOT *f, int image, Footnote *p)
431
448
  if ( good ) {
432
449
  if ( peek(f, 1) == ')' )
433
450
  pull(f);
434
-
451
+
435
452
  ___mkd_tidy(&p->link);
436
453
  }
437
454
 
@@ -456,7 +473,7 @@ linkyurl(MMIOT *f, int image, Footnote *p)
456
473
 
457
474
  if ( c == '<' ) {
458
475
  pull(f);
459
- if ( !(f->flags & MKD_1_COMPAT) )
476
+ if ( !is_flag_set(f->flags, MKD_1_COMPAT) )
460
477
  return linkybroket(f,image,p);
461
478
  mayneedtotrim=1;
462
479
  }
@@ -477,12 +494,12 @@ linkyurl(MMIOT *f, int image, Footnote *p)
477
494
  }
478
495
  if ( peek(f, 1) == ')' )
479
496
  pull(f);
480
-
497
+
481
498
  ___mkd_tidy(&p->link);
482
-
499
+
483
500
  if ( mayneedtotrim && (T(p->link)[S(p->link)-1] == '>') )
484
501
  --S(p->link);
485
-
502
+
486
503
  return 1;
487
504
  }
488
505
 
@@ -578,12 +595,12 @@ static void
578
595
  printlinkyref(MMIOT *f, linkytype *tag, char *link, int size)
579
596
  {
580
597
  char *edit;
581
-
582
- if ( f->flags & IS_LABEL )
598
+
599
+ if ( is_flag_set(f->flags, IS_LABEL) )
583
600
  return;
584
-
601
+
585
602
  Qstring(tag->link_pfx, f);
586
-
603
+
587
604
  if ( tag->kind & IS_URL ) {
588
605
  if ( f->cb && f->cb->e_url && (edit = (*f->cb->e_url)(link, size, f->cb->e_data)) ) {
589
606
  puturl(edit, strlen(edit), f, 0);
@@ -623,7 +640,7 @@ extra_linky(MMIOT *f, Cstring text, Footnote *ref)
623
640
  {
624
641
  if ( ref->flags & REFERENCED )
625
642
  return 0;
626
-
643
+
627
644
  if ( f->flags & IS_LABEL )
628
645
  ___mkd_reparse(T(text), S(text), linkt.flags, f, 0);
629
646
  else {
@@ -637,6 +654,32 @@ extra_linky(MMIOT *f, Cstring text, Footnote *ref)
637
654
  } /* extra_linky */
638
655
 
639
656
 
657
+
658
+ /* check a url (or url fragment to see that it begins with a known good
659
+ * protocol (or no protocol at all)
660
+ */
661
+ static int
662
+ safelink(Cstring link)
663
+ {
664
+ char *p, *colon;
665
+
666
+ if ( T(link) == 0 ) /* no link; safe */
667
+ return 1;
668
+
669
+ p = T(link);
670
+ if ( (colon = memchr(p, ':', S(link))) == 0 )
671
+ return 1; /* no protocol specified: safe */
672
+
673
+ if ( !isalpha(*p) ) /* protocol/method is [alpha][alnum or '+.-'] */
674
+ return 1;
675
+ while ( ++p < colon )
676
+ if ( !(isalnum(*p) || *p == '.' || *p == '+' || *p == '-') )
677
+ return 1;
678
+
679
+ return isautoprefix(T(link), S(link));
680
+ }
681
+
682
+
640
683
  /* print out a linky (or fail if it's Not Allowed)
641
684
  */
642
685
  static int
@@ -648,12 +691,10 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
648
691
  if ( image )
649
692
  tag = &imaget;
650
693
  else if ( tag = pseudo(ref->link) ) {
651
- if ( f->flags & (MKD_NO_EXT|MKD_SAFELINK) )
694
+ if ( is_flag_set(f->flags, MKD_NO_EXT) || is_flag_set(f->flags, MKD_SAFELINK) )
652
695
  return 0;
653
696
  }
654
- else if ( (f->flags & MKD_SAFELINK) && T(ref->link)
655
- && (T(ref->link)[0] != '/')
656
- && !isautoprefix(T(ref->link), S(ref->link)) )
697
+ else if ( is_flag_set(f->flags, MKD_SAFELINK) && !safelink(ref->link) )
657
698
  /* if MKD_SAFELINK, only accept links that are local or
658
699
  * a well-known protocol
659
700
  */
@@ -664,7 +705,7 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
664
705
  if ( f->flags & tag->flags )
665
706
  return 0;
666
707
 
667
- if ( f->flags & IS_LABEL )
708
+ if ( is_flag_set(f->flags, IS_LABEL) )
668
709
  ___mkd_reparse(T(text), S(text), tag->flags, f, 0);
669
710
  else if ( tag->link_pfx ) {
670
711
  printlinkyref(f, tag, T(ref->link), S(ref->link));
@@ -700,7 +741,7 @@ linkylinky(int image, MMIOT *f)
700
741
  int start = mmiottell(f);
701
742
  Cstring name;
702
743
  Footnote key, *ref;
703
-
744
+
704
745
  int status = 0;
705
746
  int extra_footnote = 0;
706
747
 
@@ -718,7 +759,7 @@ linkylinky(int image, MMIOT *f)
718
759
 
719
760
  if ( isspace(peek(f,1)) )
720
761
  pull(f);
721
-
762
+
722
763
  if ( peek(f,1) == '[' ) {
723
764
  pull(f); /* consume leading '[' */
724
765
  goodlink = linkylabel(f, &key.tag);
@@ -728,12 +769,12 @@ linkylinky(int image, MMIOT *f)
728
769
  * require a second []
729
770
  */
730
771
  mmiotseek(f, implicit_mark);
731
- goodlink = !(f->flags & MKD_1_COMPAT);
772
+ goodlink = !is_flag_set(f->flags, MKD_1_COMPAT);
732
773
 
733
- if ( (f->flags & MKD_EXTRA_FOOTNOTE) && (!image) && S(name) && T(name)[0] == '^' )
774
+ if ( is_flag_set(f->flags, MKD_EXTRA_FOOTNOTE) && (!image) && S(name) && T(name)[0] == '^' )
734
775
  extra_footnote = 1;
735
776
  }
736
-
777
+
737
778
  if ( goodlink ) {
738
779
  if ( !S(key.tag) ) {
739
780
  DELETE(key.tag);
@@ -777,7 +818,7 @@ cputc(int c, MMIOT *f)
777
818
  }
778
819
  }
779
820
 
780
-
821
+
781
822
  /*
782
823
  * convert an email address to a string of nonsense
783
824
  */
@@ -819,7 +860,7 @@ matchticks(MMIOT *f, int tickchar, int ticks, int *endticks)
819
860
  {
820
861
  int size, count, c;
821
862
  int subsize=0, subtick=0;
822
-
863
+
823
864
  *endticks = ticks;
824
865
  for (size = 0; (c=peek(f,size+ticks)) != EOF; size ++) {
825
866
  if ( (c == tickchar) && ( count = nrticks(size+ticks,tickchar,f)) ) {
@@ -852,7 +893,7 @@ code(MMIOT *f, char *s, int length)
852
893
  int i,c;
853
894
 
854
895
  for ( i=0; i < length; i++ )
855
- if ( (c = s[i]) == MKD_EOLN) /* ^C: expand back to 2 spaces */
896
+ if ( (c = s[i]) == MKD_EOLN) /* expand back to 2 spaces */
856
897
  Qstring(" ", f);
857
898
  else if ( c == '\\' && (i < length-1) && escaped(f, s[i+1]) )
858
899
  cputc(s[++i], f);
@@ -870,6 +911,41 @@ delspan(MMIOT *f, int size)
870
911
  Qstring("</del>", f);
871
912
  }
872
913
 
914
+ #ifdef TYPORA
915
+ /* subspan() -- write out a chunk of text, blocking with <sub>...</sub>
916
+ */
917
+ static void
918
+ subspan(MMIOT *f, int size)
919
+ {
920
+ Qstring("<sub>", f);
921
+ ___mkd_reparse(cursor(f)-1, size, 0, f, 0);
922
+ Qstring("</sub>", f);
923
+ }
924
+
925
+
926
+ /* supspan() -- write out a chunk of text, blocking with <sup>...</sup>
927
+ */
928
+ static void
929
+ supspan(MMIOT *f, int size)
930
+ {
931
+ Qstring("<sup>", f);
932
+ ___mkd_reparse(cursor(f)-1, size, 0, f, 0);
933
+ Qstring("</sup>", f);
934
+ }
935
+
936
+
937
+ /* highlightspan() -- write out a chunk of text, blocking with <mark>...</mark>
938
+ */
939
+ static void
940
+ highlightspan(MMIOT *f, int size)
941
+ {
942
+ Qstring("<mark>", f);
943
+ ___mkd_reparse(cursor(f)-1, size, 0, f, 0);
944
+ Qstring("</mark>", f);
945
+ }
946
+ #endif
947
+
948
+
873
949
 
874
950
  /* codespan() -- write out a chunk of text as code, trimming one
875
951
  * space off the front and/or back as appropriate.
@@ -881,7 +957,7 @@ codespan(MMIOT *f, int size)
881
957
 
882
958
  if ( size > 1 && peek(f, size-1) == ' ' ) --size;
883
959
  if ( peek(f,i) == ' ' ) ++i, --size;
884
-
960
+
885
961
  Qstring("<code>", f);
886
962
  code(f, cursor(f)+(i-1), size);
887
963
  Qstring("</code>", f);
@@ -896,12 +972,12 @@ forbidden_tag(MMIOT *f)
896
972
  {
897
973
  int c = toupper(peek(f, 1));
898
974
 
899
- if ( f->flags & MKD_NOHTML )
975
+ if ( is_flag_set(f->flags, MKD_NOHTML) )
900
976
  return 1;
901
977
 
902
- if ( c == 'A' && (f->flags & MKD_NOLINKS) && !isthisalnum(f,2) )
978
+ if ( c == 'A' && is_flag_set(f->flags, MKD_NOLINKS) && !isthisalnum(f,2) )
903
979
  return 1;
904
- if ( c == 'I' && (f->flags & MKD_NOIMAGE)
980
+ if ( c == 'I' && is_flag_set(f->flags, MKD_NOIMAGE)
905
981
  && strncasecmp(cursor(f)+1, "MG", 2) == 0
906
982
  && !isthisalnum(f,4) )
907
983
  return 1;
@@ -918,17 +994,17 @@ static int
918
994
  maybe_address(char *p, int size)
919
995
  {
920
996
  int ok = 0;
921
-
997
+
922
998
  for ( ;size && (isalnum(*p) || strchr("._-+*", *p)); ++p, --size)
923
999
  ;
924
1000
 
925
1001
  if ( ! (size && *p == '@') )
926
1002
  return 0;
927
-
1003
+
928
1004
  --size, ++p;
929
1005
 
930
1006
  if ( size && *p == '.' ) return 0;
931
-
1007
+
932
1008
  for ( ;size && (isalnum(*p) || strchr("._-+", *p)); ++p, --size )
933
1009
  if ( *p == '.' && size > 1 ) ok = 1;
934
1010
 
@@ -947,8 +1023,8 @@ process_possible_link(MMIOT *f, int size)
947
1023
  int address= 0;
948
1024
  int mailto = 0;
949
1025
  char *text = cursor(f);
950
-
951
- if ( f->flags & MKD_NOLINKS ) return 0;
1026
+
1027
+ if ( is_flag_set(f->flags, MKD_NOLINKS) ) return 0;
952
1028
 
953
1029
  if ( (size > 7) && strncasecmp(text, "mailto:", 7) == 0 ) {
954
1030
  /* if it says it's a mailto, it's a mailto -- who am
@@ -983,6 +1059,17 @@ process_possible_link(MMIOT *f, int size)
983
1059
  } /* process_possible_link */
984
1060
 
985
1061
 
1062
+ /*
1063
+ * check if a character is one of the things the reference implementation considers valid for starting
1064
+ * a html(ish) tag
1065
+ */
1066
+ static inline int
1067
+ is_a_strict_tag_prefix(int c)
1068
+ {
1069
+ return isalpha(c) || (c == '/') || (c == '!') || (c == '$') || (c == '?');
1070
+ }
1071
+
1072
+
986
1073
  /* a < may be just a regular character, the start of an embedded html
987
1074
  * tag, or the start of an <automatic link>. If it's an automatic
988
1075
  * link, we also need to know if it's an email address because if it
@@ -992,54 +1079,56 @@ process_possible_link(MMIOT *f, int size)
992
1079
  static int
993
1080
  maybe_tag_or_link(MMIOT *f)
994
1081
  {
995
- int c, size;
996
- int maybetag = 1;
1082
+ int c, size=0;
997
1083
 
998
- if ( f->flags & MKD_TAGTEXT )
1084
+ if ( is_flag_set(f->flags, MKD_TAGTEXT) )
999
1085
  return 0;
1000
1086
 
1001
- for ( size=0; (c = peek(f, size+1)) != '>'; size++) {
1002
- if ( c == EOF )
1003
- return 0;
1004
- else if ( c == '\\' ) {
1005
- maybetag=0;
1006
- if ( peek(f, size+2) != EOF )
1007
- size++;
1087
+ c = peek(f, 1);
1088
+
1089
+
1090
+ if ( is_a_strict_tag_prefix(c) ) {
1091
+ /* By decree of Markdown.pl *this is a tag* and we want to absorb everything up
1092
+ * to the next '>', unless interrupted by another '<' OR a '`', at which point
1093
+ * we kick it back to the caller as plain old text.
1094
+ */
1095
+ size=1;
1096
+ while ( (c=peek(f,size+1)) != '>' ) {
1097
+ if ( c == EOF || c == '<' )
1098
+ return 0;
1099
+ if ( is_flag_set(f->flags, MKD_STRICT) ) {
1100
+ if ( c == '`' )
1101
+ return 0;
1102
+ }
1103
+ size++;
1008
1104
  }
1009
- else if ( isspace(c) )
1010
- break;
1011
- else if ( ! (c == '/'
1012
- || (f->flags & MKD_GITHUBTAGS && (c == '-' || c == '_'))
1013
- || isalnum(c) ) )
1014
- maybetag=0;
1015
1105
  }
1016
1106
 
1017
- if ( size ) {
1018
- if ( maybetag || (size >= 3 && strncmp(cursor(f), "!--", 3) == 0) ) {
1107
+ if ( size > 0 ) {
1108
+ if ( process_possible_link(f, size) ) {
1109
+ shift(f, size+1);
1110
+ return 1;
1111
+ }
1112
+ else {
1113
+ int i;
1019
1114
 
1020
- /* It is not a html tag unless we find the closing '>' in
1021
- * the same block.
1022
- */
1023
- while ( (c = peek(f, size+1)) != '>' )
1024
- if ( c == EOF )
1025
- return 0;
1026
- else
1027
- size++;
1028
-
1029
1115
  if ( forbidden_tag(f) )
1030
1116
  return 0;
1031
1117
 
1032
- Qchar('<', f);
1033
- while ( ((c = peek(f, 1)) != EOF) && (c != '>') )
1034
- Qchar(pull(f), f);
1035
- return 1;
1036
- }
1037
- else if ( !isspace(c) && process_possible_link(f, size) ) {
1118
+ for ( i=0; i <= size+1; i++ ) {
1119
+ c = peek(f,i);
1120
+
1121
+ if ( (c == '&') && (i > 0) )
1122
+ Qstring("&amp;", f);
1123
+ else
1124
+ Qchar(c, f);
1125
+ }
1126
+
1038
1127
  shift(f, size+1);
1039
1128
  return 1;
1040
1129
  }
1041
1130
  }
1042
-
1131
+
1043
1132
  return 0;
1044
1133
  }
1045
1134
 
@@ -1163,7 +1252,9 @@ smartypants(int c, int *flags, MMIOT *f)
1163
1252
  {
1164
1253
  int i;
1165
1254
 
1166
- if ( f->flags & (MKD_NOPANTS|MKD_TAGTEXT|IS_LABEL) )
1255
+ if ( is_flag_set(f->flags, MKD_NOPANTS)
1256
+ || is_flag_set(f->flags, MKD_TAGTEXT)
1257
+ || is_flag_set(f->flags, IS_LABEL) )
1167
1258
  return 0;
1168
1259
 
1169
1260
  for ( i=0; i < NRSMART; i++)
@@ -1207,7 +1298,6 @@ smartypants(int c, int *flags, MMIOT *f)
1207
1298
  } /* smartypants */
1208
1299
 
1209
1300
 
1210
- #if WITH_LATEX
1211
1301
  /* process latex with arbitrary 2-character ( $$ .. $$, \[ .. \], \( .. \)
1212
1302
  * delimiters
1213
1303
  */
@@ -1227,7 +1317,6 @@ mathhandler(MMIOT *f, int e1, int e2)
1227
1317
  }
1228
1318
  return 0;
1229
1319
  }
1230
- #endif
1231
1320
 
1232
1321
 
1233
1322
  /* process a body of text encased in some sort of tick marks. If it
@@ -1257,7 +1346,7 @@ tickhandler(MMIOT *f, int tickchar, int minticks, int allow_space, spanhandler s
1257
1346
  return 0;
1258
1347
  }
1259
1348
 
1260
- #define tag_text(f) (f->flags & MKD_TAGTEXT)
1349
+ #define tag_text(f) is_flag_set(f->flags, MKD_TAGTEXT)
1261
1350
 
1262
1351
 
1263
1352
  static void
@@ -1268,7 +1357,7 @@ text(MMIOT *f)
1268
1357
  int smartyflags = 0;
1269
1358
 
1270
1359
  while (1) {
1271
- if ( (f->flags & MKD_AUTOLINK) && isalpha(peek(f,1)) && !tag_text(f) )
1360
+ if ( is_flag_set(f->flags, MKD_AUTOLINK) && isalpha(peek(f,1)) && !tag_text(f) )
1272
1361
  maybe_autolink(f);
1273
1362
 
1274
1363
  c = pull(f);
@@ -1296,7 +1385,7 @@ text(MMIOT *f)
1296
1385
  else
1297
1386
  Qchar(c, f);
1298
1387
  break;
1299
-
1388
+
1300
1389
  case '!': if ( peek(f,1) == '[' ) {
1301
1390
  pull(f);
1302
1391
  if ( tag_text(f) || !linkylinky(1, f) )
@@ -1309,10 +1398,31 @@ text(MMIOT *f)
1309
1398
  case '[': if ( tag_text(f) || !linkylinky(0, f) )
1310
1399
  Qchar(c, f);
1311
1400
  break;
1401
+
1402
+ #ifdef TYPORA
1403
+ case '=': if ( is_flag_set(f->flags, MKD_NOSUPERSCRIPT)
1404
+ || is_flag_set(f->flags, MKD_STRICT)
1405
+ || is_flag_set(f->flags, MKD_TAGTEXT)
1406
+ || ! tickhandler(f,c,2,0, highlightspan))
1407
+ Qchar(c, f);
1408
+ break;
1409
+
1410
+ /* A^B^ -> A<sup>B</sup> */
1411
+ case '^': if ( is_flag_set(f->flags, MKD_NOSUPERSCRIPT)
1412
+ || is_flag_set(f->flags, MKD_STRICT)
1413
+ || is_flag_set(f->flags, MKD_TAGTEXT)
1414
+ || ! tickhandler(f,c,1,0, supspan))
1415
+ Qchar(c, f);
1416
+ break;
1417
+ #else /* !TYPORA */
1312
1418
  /* A^B -> A<sup>B</sup> */
1313
- case '^': if ( (f->flags & (MKD_NOSUPERSCRIPT|MKD_STRICT|MKD_TAGTEXT))
1314
- || (isthisnonword(f,-1) && peek(f,-1) != ')')
1315
- || isthisspace(f,1) )
1419
+ case '^': if ( is_flag_set(f->flags, MKD_NOSUPERSCRIPT)
1420
+ || is_flag_set(f->flags, MKD_STRICT)
1421
+ || is_flag_set(f->flags, MKD_TAGTEXT)
1422
+ || (f->last == 0)
1423
+ || ((ispunct(f->last) || isspace(f->last))
1424
+ && f->last != ')')
1425
+ || isthisspace(f,1) )
1316
1426
  Qchar(c,f);
1317
1427
  else {
1318
1428
  char *sup = cursor(f);
@@ -1343,11 +1453,11 @@ text(MMIOT *f)
1343
1453
  Qstring("</sup>", f);
1344
1454
  }
1345
1455
  break;
1456
+ #endif /* TYPORA */
1346
1457
  case '_':
1347
1458
  /* Underscores don't count if they're in the middle of a word */
1348
- if ( !(f->flags & (MKD_NORELAXED|MKD_STRICT))
1349
- && isthisalnum(f,-1)
1350
- && isthisalnum(f,1) ) {
1459
+ if ( !(is_flag_set(f->flags, MKD_NORELAXED) || is_flag_set(f->flags, MKD_STRICT))
1460
+ && isthisalnum(f,-1) && isthisalnum(f,1) ) {
1351
1461
  Qchar(c, f);
1352
1462
  break;
1353
1463
  }
@@ -1367,8 +1477,17 @@ text(MMIOT *f)
1367
1477
  Qem(f,c,rep);
1368
1478
  }
1369
1479
  break;
1370
-
1371
- case '~': if ( (f->flags & (MKD_NOSTRIKETHROUGH|MKD_TAGTEXT|MKD_STRICT)) || ! tickhandler(f,c,2,0, delspan) )
1480
+
1481
+ #ifdef TYPORA
1482
+ #define ticktick(f,c) (tickhandler(f,c,2,0,delspan) || tickhandler(f,c,1,0,subspan))
1483
+ #else
1484
+ #define ticktick(f,c) tickhandler(f,c,2,0,delspan)
1485
+ #endif
1486
+
1487
+ case '~': if ( is_flag_set(f->flags, MKD_NOSTRIKETHROUGH)
1488
+ || is_flag_set(f->flags, MKD_STRICT)
1489
+ || is_flag_set(f->flags, MKD_TAGTEXT)
1490
+ || !ticktick(f,c) )
1372
1491
  Qchar(c, f);
1373
1492
  break;
1374
1493
 
@@ -1388,35 +1507,35 @@ text(MMIOT *f)
1388
1507
  Qchar('\\', f);
1389
1508
  shift(f, -1);
1390
1509
  }
1391
-
1510
+
1392
1511
  break;
1393
- case '^': if ( f->flags & (MKD_STRICT|MKD_NOSUPERSCRIPT) ) {
1512
+ case '^': if ( is_flag_set(f->flags, MKD_STRICT)
1513
+ || is_flag_set(f->flags, MKD_NOSUPERSCRIPT) ) {
1394
1514
  Qchar('\\', f);
1395
1515
  shift(f,-1);
1396
1516
  break;
1397
1517
  }
1398
1518
  Qchar(c, f);
1399
1519
  break;
1400
-
1520
+
1401
1521
  case ':': case '|':
1402
- if ( f->flags & MKD_NOTABLES ) {
1522
+ if ( is_flag_set(f->flags, MKD_NOTABLES) ) {
1403
1523
  Qchar('\\', f);
1404
1524
  shift(f,-1);
1405
1525
  break;
1406
1526
  }
1407
1527
  Qchar(c, f);
1408
1528
  break;
1409
-
1529
+
1410
1530
  case EOF: Qchar('\\', f);
1411
1531
  break;
1412
1532
 
1413
- #if WITH_LATEX
1414
1533
  case '[':
1415
- case '(': if ( mathhandler(f, '\\', (c =='(')?')':']') )
1534
+ case '(': if ( is_flag_set(f->flags, MKD_LATEX)
1535
+ && mathhandler(f, '\\', (c =='(')?')':']') )
1416
1536
  break;
1417
1537
  /* else fall through to default */
1418
- #endif
1419
-
1538
+
1420
1539
  default: if ( escaped(f,c) ||
1421
1540
  strchr(">#.-+{}]![*_\\()`", c) )
1422
1541
  Qchar(c, f);
@@ -1428,8 +1547,12 @@ text(MMIOT *f)
1428
1547
  }
1429
1548
  break;
1430
1549
 
1431
- case '<': if ( !maybe_tag_or_link(f) )
1432
- Qstring("&lt;", f);
1550
+ case '<': if ( !maybe_tag_or_link(f) ) {
1551
+ if ( is_flag_set(f->flags, MKD_STRICT) && is_a_strict_tag_prefix(peek(f,1)) )
1552
+ Qchar(c, f);
1553
+ else
1554
+ Qstring("&lt;", f);
1555
+ }
1433
1556
  break;
1434
1557
 
1435
1558
  case '&': j = (peek(f,1) == '#' ) ? 2 : 1;
@@ -1442,17 +1565,16 @@ text(MMIOT *f)
1442
1565
  Qchar(c, f);
1443
1566
  break;
1444
1567
 
1445
- #if WITH_LATEX
1446
- case '$': if ( peek(f, 1) == '$' ) {
1568
+ case '$': if ( is_flag_set(f->flags, MKD_LATEX) && (peek(f, 1) == '$') ) {
1447
1569
  pull(f);
1448
1570
  if ( mathhandler(f, '$', '$') )
1449
1571
  break;
1450
1572
  Qchar('$', f);
1451
1573
  }
1452
1574
  /* fall through to default */
1453
- #endif
1454
-
1455
- default: Qchar(c, f);
1575
+
1576
+ default: f->last = c;
1577
+ Qchar(c, f);
1456
1578
  break;
1457
1579
  }
1458
1580
  }
@@ -1466,22 +1588,18 @@ text(MMIOT *f)
1466
1588
  static void
1467
1589
  printheader(Paragraph *pp, MMIOT *f)
1468
1590
  {
1469
- if ( f->flags & MKD_IDANCHOR ) {
1591
+ if ( is_flag_set(f->flags, MKD_IDANCHOR) ) {
1470
1592
  Qprintf(f, "<h%d", pp->hnumber);
1471
- if ( f->flags & MKD_TOC ) {
1593
+ if ( is_flag_set(f->flags, MKD_TOC) ) {
1472
1594
  Qstring(" id=\"", f);
1473
- mkd_string_to_anchor(T(pp->text->text),
1474
- S(pp->text->text),
1475
- (mkd_sta_function_t)Qchar, f, 1, f->flags);
1595
+ Qanchor(pp->text, f);
1476
1596
  Qchar('"', f);
1477
1597
  }
1478
1598
  Qchar('>', f);
1479
1599
  } else {
1480
- if ( f->flags & MKD_TOC ) {
1600
+ if ( is_flag_set(f->flags, MKD_TOC) ) {
1481
1601
  Qstring("<a name=\"", f);
1482
- mkd_string_to_anchor(T(pp->text->text),
1483
- S(pp->text->text),
1484
- (mkd_sta_function_t)Qchar, f, 1, f->flags);
1602
+ Qanchor(pp->text, f);
1485
1603
  Qstring("\"></a>\n", f);
1486
1604
  }
1487
1605
  Qprintf(f, "<h%d>", pp->hnumber);
@@ -1511,7 +1629,7 @@ splat(Line *p, char *block, Istring align, int force, MMIOT *f)
1511
1629
  ___mkd_tidy(&p->text);
1512
1630
  if ( T(p->text)[S(p->text)-1] == '|' )
1513
1631
  --S(p->text);
1514
-
1632
+
1515
1633
  Qstring("<tr>\n", f);
1516
1634
  while ( idx < S(p->text) ) {
1517
1635
  first = idx;
@@ -1572,7 +1690,7 @@ printtable(Paragraph *pp, MMIOT *f)
1572
1690
  for (p=T(dash->text), start=dash->dle; start < S(dash->text); ) {
1573
1691
  char first, last;
1574
1692
  int end;
1575
-
1693
+
1576
1694
  last=first=0;
1577
1695
  for (end=start ; (end < S(dash->text)) && p[end] != '|'; ++ end ) {
1578
1696
  if ( p[end] == '\\' )
@@ -1614,9 +1732,10 @@ printtable(Paragraph *pp, MMIOT *f)
1614
1732
  static int
1615
1733
  printblock(Paragraph *pp, MMIOT *f)
1616
1734
  {
1617
- Line *t = pp->text;
1618
1735
  static char *Begin[] = { "", "<p>", "<p style=\"text-align:center;\">" };
1619
1736
  static char *End[] = { "", "</p>","</p>" };
1737
+ Line *t = pp->text;
1738
+ int align = pp->align;
1620
1739
 
1621
1740
  while (t) {
1622
1741
  if ( S(t->text) ) {
@@ -1636,9 +1755,9 @@ printblock(Paragraph *pp, MMIOT *f)
1636
1755
  }
1637
1756
  t = t->next;
1638
1757
  }
1639
- Qstring(Begin[pp->align], f);
1758
+ Qstring(Begin[align], f);
1640
1759
  text(f);
1641
- Qstring(End[pp->align], f);
1760
+ Qstring(End[align], f);
1642
1761
  return 1;
1643
1762
  }
1644
1763
 
@@ -1648,8 +1767,44 @@ printcode(Line *t, char *lang, MMIOT *f)
1648
1767
  {
1649
1768
  int blanks;
1650
1769
 
1770
+ if ( f->cb->e_codefmt ) {
1771
+ /* external code block formatter; copy the text into a buffer,
1772
+ * call the formatter to style it, then dump that styled text
1773
+ * directly to the queue
1774
+ */
1775
+ char *text;
1776
+ char *fmt;
1777
+ int size, copy_p;
1778
+ Line *p;
1779
+
1780
+ for (size=0, p = t; p; p = p->next )
1781
+ size += 1+S(p->text);
1782
+
1783
+ text = malloc(1+size);
1784
+
1785
+ for ( copy_p = 0; t ; t = t->next ) {
1786
+ memcpy(text+copy_p, T(t->text), S(t->text));
1787
+ copy_p += S(t->text);
1788
+ text[copy_p++] = '\n';
1789
+ }
1790
+ text[copy_p] = 0;
1791
+
1792
+ fmt = (*(f->cb->e_codefmt))(text, copy_p, (lang && lang[0]) ? lang : 0);
1793
+ free(text);
1794
+
1795
+ if ( fmt ) {
1796
+ Qwrite(fmt, strlen(fmt), f);
1797
+ if ( f->cb->e_free )
1798
+ (*(f->cb->e_free))(fmt, f->cb->e_data);
1799
+ return;
1800
+ }
1801
+ /* otherwise the external formatter failed and we need to
1802
+ * fall back to the traditional codeblock format
1803
+ */
1804
+ }
1805
+
1651
1806
  Qstring("<pre><code", f);
1652
- if (lang) {
1807
+ if (lang && lang[0]) {
1653
1808
  Qstring(" class=\"", f);
1654
1809
  Qstring(lang, f);
1655
1810
  Qstring("\"", f);
@@ -1674,7 +1829,7 @@ static void
1674
1829
  printhtml(Line *t, MMIOT *f)
1675
1830
  {
1676
1831
  int blanks;
1677
-
1832
+
1678
1833
  for ( blanks=0; t ; t = t->next )
1679
1834
  if ( S(t->text) ) {
1680
1835
  for ( ; blanks; --blanks )
@@ -1689,17 +1844,57 @@ printhtml(Line *t, MMIOT *f)
1689
1844
 
1690
1845
 
1691
1846
  static void
1692
- htmlify(Paragraph *p, char *block, char *arguments, MMIOT *f)
1847
+ htmlify_paragraphs(Paragraph *p, MMIOT *f)
1693
1848
  {
1694
1849
  ___mkd_emblock(f);
1695
- if ( block )
1696
- Qprintf(f, arguments ? "<%s %s>" : "<%s>", block, arguments);
1697
- ___mkd_emblock(f);
1698
1850
 
1699
1851
  while (( p = display(p, f) )) {
1700
1852
  ___mkd_emblock(f);
1701
1853
  Qstring("\n\n", f);
1702
1854
  }
1855
+ }
1856
+
1857
+
1858
+ #ifdef GITHUB_CHECKBOX
1859
+ static void
1860
+ li_htmlify(Paragraph *p, char *arguments, mkd_flag_t flags, MMIOT *f)
1861
+ {
1862
+ ___mkd_emblock(f);
1863
+
1864
+ Qprintf(f, "<li");
1865
+ if ( arguments )
1866
+ Qprintf(f, " %s", arguments);
1867
+ if ( flags & GITHUB_CHECK )
1868
+ Qprintf(f, " class=\"github_checkbox\"");
1869
+ Qprintf(f, ">");
1870
+ #if CHECKBOX_AS_INPUT
1871
+ if ( flags & GITHUB_CHECK ) {
1872
+ Qprintf(f, "<input disabled=\"\" type=\"checkbox\"");
1873
+ if ( flags & IS_CHECKED )
1874
+ Qprintf(f, " checked=\"checked\"");
1875
+ Qprintf(f, "/>");
1876
+ }
1877
+ #else
1878
+ if ( flags & GITHUB_CHECK )
1879
+ Qprintf(f, flags & IS_CHECKED ? "&#x2611;" : "&#x2610;");
1880
+ #endif
1881
+
1882
+ htmlify_paragraphs(p, f);
1883
+
1884
+ Qprintf(f, "</li>");
1885
+ ___mkd_emblock(f);
1886
+ }
1887
+ #endif
1888
+
1889
+
1890
+ static void
1891
+ htmlify(Paragraph *p, char *block, char *arguments, MMIOT *f)
1892
+ {
1893
+ ___mkd_emblock(f);
1894
+ if ( block )
1895
+ Qprintf(f, arguments ? "<%s %s>" : "<%s>", block, arguments);
1896
+
1897
+ htmlify_paragraphs(p, f);
1703
1898
 
1704
1899
  if ( block )
1705
1900
  Qprintf(f, "</%s>", block);
@@ -1741,7 +1936,11 @@ listdisplay(int typ, Paragraph *p, MMIOT* f)
1741
1936
  Qprintf(f, ">\n");
1742
1937
 
1743
1938
  for ( ; p ; p = p->next ) {
1939
+ #ifdef GITHUB_CHECKBOX
1940
+ li_htmlify(p->down, p->ident, p->flags, f);
1941
+ #else
1744
1942
  htmlify(p->down, "li", p->ident, f);
1943
+ #endif
1745
1944
  Qchar('\n', f);
1746
1945
  }
1747
1946
 
@@ -1756,7 +1955,7 @@ static Paragraph*
1756
1955
  display(Paragraph *p, MMIOT *f)
1757
1956
  {
1758
1957
  if ( !p ) return 0;
1759
-
1958
+
1760
1959
  switch ( p->typ ) {
1761
1960
  case STYLE:
1762
1961
  case WHITESPACE:
@@ -1765,15 +1964,15 @@ display(Paragraph *p, MMIOT *f)
1765
1964
  case HTML:
1766
1965
  printhtml(p->text, f);
1767
1966
  break;
1768
-
1967
+
1769
1968
  case CODE:
1770
1969
  printcode(p->text, p->lang, f);
1771
1970
  break;
1772
-
1971
+
1773
1972
  case QUOTE:
1774
1973
  htmlify(p->down, p->ident ? "div" : "blockquote", p->ident, f);
1775
1974
  break;
1776
-
1975
+
1777
1976
  case UL:
1778
1977
  case OL:
1779
1978
  case AL:
@@ -1799,7 +1998,7 @@ display(Paragraph *p, MMIOT *f)
1799
1998
  case SOURCE:
1800
1999
  htmlify(p->down, 0, 0, f);
1801
2000
  break;
1802
-
2001
+
1803
2002
  default:
1804
2003
  printblock(p, f);
1805
2004
  break;
@@ -1820,17 +2019,17 @@ mkd_extra_footnotes(MMIOT *m)
1820
2019
  return;
1821
2020
 
1822
2021
  Csprintf(&m->out, "\n<div class=\"footnotes\">\n<hr/>\n<ol>\n");
1823
-
2022
+
1824
2023
  for ( i=1; i <= m->footnotes->reference; i++ ) {
1825
2024
  for ( j=0; j < S(m->footnotes->note); j++ ) {
1826
2025
  t = &T(m->footnotes->note)[j];
1827
2026
  if ( (t->refnumber == i) && (t->flags & REFERENCED) ) {
1828
- Csprintf(&m->out, "<li id=\"%s:%d\">\n<p>",
2027
+ Csprintf(&m->out, "<li id=\"%s:%d\">\n",
1829
2028
  p_or_nothing(m), t->refnumber);
1830
- Csreparse(&m->out, T(t->title), S(t->title), 0);
2029
+ htmlify(t->text, 0, 0, m);
1831
2030
  Csprintf(&m->out, "<a href=\"#%sref:%d\" rev=\"footnote\">&#8617;</a>",
1832
2031
  p_or_nothing(m), t->refnumber);
1833
- Csprintf(&m->out, "</p></li>\n");
2032
+ Csprintf(&m->out, "</li>\n");
1834
2033
  }
1835
2034
  }
1836
2035
  }
@@ -1845,15 +2044,15 @@ int
1845
2044
  mkd_document(Document *p, char **res)
1846
2045
  {
1847
2046
  int size;
1848
-
2047
+
1849
2048
  if ( p && p->compiled ) {
1850
2049
  if ( ! p->html ) {
1851
2050
  htmlify(p->code, 0, 0, p->ctx);
1852
- if ( p->ctx->flags & MKD_EXTRA_FOOTNOTE )
2051
+ if ( is_flag_set(p->ctx->flags, MKD_EXTRA_FOOTNOTE) )
1853
2052
  mkd_extra_footnotes(p->ctx);
1854
2053
  p->html = 1;
1855
2054
  size = S(p->ctx->out);
1856
-
2055
+
1857
2056
  if ( (size == 0) || T(p->ctx->out)[size-1] ) {
1858
2057
  /* Add a null byte at the end of the generated html,
1859
2058
  * but pretend it doesn't exist.
@@ -1862,10 +2061,9 @@ mkd_document(Document *p, char **res)
1862
2061
  --S(p->ctx->out);
1863
2062
  }
1864
2063
  }
1865
-
2064
+
1866
2065
  *res = T(p->ctx->out);
1867
2066
  return S(p->ctx->out);
1868
2067
  }
1869
2068
  return EOF;
1870
2069
  }
1871
-