redcarpet 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of redcarpet might be problematic. Click here for more details.

data/ext/markdown.c CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  /*
4
4
  * Copyright (c) 2009, Natacha Porté
5
+ * Copyright (c) 2011, Vicent Marti
5
6
  *
6
7
  * Permission to use, copy, modify, and distribute this software for any
7
8
  * purpose with or without fee is hereby granted, provided that the above
@@ -35,10 +36,10 @@
35
36
 
36
37
  /* link_ref • reference to a link */
37
38
  struct link_ref {
38
- struct buf * id;
39
- struct buf * link;
40
- struct buf * title; };
41
-
39
+ struct buf *id;
40
+ struct buf *link;
41
+ struct buf *title;
42
+ };
42
43
 
43
44
  /* char_trigger • function pointer to render active chars */
44
45
  /* returns the number of chars taken care of */
@@ -46,27 +47,24 @@ struct link_ref {
46
47
  /* offset is the number of valid chars before data */
47
48
  struct render;
48
49
  typedef size_t
49
- (*char_trigger)(struct buf *ob, struct render *rndr,
50
- char *data, size_t offset, size_t size);
50
+ (*char_trigger)(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);
51
51
 
52
52
 
53
53
  /* render • structure containing one particular render */
54
54
  struct render {
55
55
  struct mkd_renderer make;
56
- struct array refs;
57
- char_trigger active_char[256];
58
- struct parray work;
56
+ struct array refs;
57
+ char_trigger active_char[256];
58
+ struct parray work;
59
+ int header_count;
59
60
  };
60
61
 
61
-
62
62
  /* html_tag • structure for quick HTML tag search (inspired from discount) */
63
63
  struct html_tag {
64
64
  const char *text;
65
65
  size_t size;
66
66
  };
67
67
 
68
-
69
-
70
68
  /********************
71
69
  * GLOBAL VARIABLES *
72
70
  ********************/
@@ -94,44 +92,48 @@ static struct html_tag block_tags[] = {
94
92
  { "script", 6 },
95
93
  { "fieldset", 8 },
96
94
  { "noscript", 8 },
97
- { "blockquote", 10 } };
95
+ { "blockquote", 10 }
96
+ };
98
97
 
99
98
  #define INS_TAG (block_tags + 12)
100
99
  #define DEL_TAG (block_tags + 10)
101
100
 
102
-
103
-
104
101
  /***************************
105
102
  * STATIC HELPER FUNCTIONS *
106
103
  ***************************/
107
104
 
108
105
  /* cmp_link_ref • comparison function for link_ref sorted arrays */
109
106
  static int
110
- cmp_link_ref(void *key, void *array_entry) {
107
+ cmp_link_ref(void *key, void *array_entry)
108
+ {
111
109
  struct link_ref *lr = array_entry;
112
- return bufcasecmp(key, lr->id); }
113
-
110
+ return bufcasecmp(key, lr->id);
111
+ }
114
112
 
115
113
  /* cmp_link_ref_sort • comparison function for link_ref qsort */
116
114
  static int
117
- cmp_link_ref_sort(const void *a, const void *b) {
115
+ cmp_link_ref_sort(const void *a, const void *b)
116
+ {
118
117
  const struct link_ref *lra = a;
119
118
  const struct link_ref *lrb = b;
120
- return bufcasecmp(lra->id, lrb->id); }
121
-
119
+ return bufcasecmp(lra->id, lrb->id);
120
+ }
122
121
 
123
122
  /* cmp_html_tag • comparison function for bsearch() (stolen from discount) */
124
123
  static int
125
- cmp_html_tag(const void *a, const void *b) {
124
+ cmp_html_tag(const void *a, const void *b)
125
+ {
126
126
  const struct html_tag *hta = a;
127
127
  const struct html_tag *htb = b;
128
128
  if (hta->size != htb->size) return (int)((ssize_t)hta->size - (ssize_t)htb->size);
129
- return strncasecmp(hta->text, htb->text, hta->size); }
129
+ return strncasecmp(hta->text, htb->text, hta->size);
130
+ }
130
131
 
131
132
 
132
133
  /* find_block_tag • returns the current block tag */
133
134
  static struct html_tag *
134
- find_block_tag(char *data, size_t size) {
135
+ find_block_tag(char *data, size_t size)
136
+ {
135
137
  size_t i = 0;
136
138
  struct html_tag key;
137
139
 
@@ -147,9 +149,8 @@ find_block_tag(char *data, size_t size) {
147
149
  key.size = i;
148
150
  return bsearch(&key, block_tags,
149
151
  sizeof block_tags / sizeof block_tags[0],
150
- sizeof block_tags[0], cmp_html_tag); }
151
-
152
-
152
+ sizeof block_tags[0], cmp_html_tag);
153
+ }
153
154
 
154
155
  /****************************
155
156
  * INLINE PARSING FUNCTIONS *
@@ -158,7 +159,8 @@ find_block_tag(char *data, size_t size) {
158
159
  /* is_mail_autolink • looks for the address part of a mail autolink and '>' */
159
160
  /* this is less strict than the original markdown e-mail address matching */
160
161
  static size_t
161
- is_mail_autolink(char *data, size_t size) {
162
+ is_mail_autolink(char *data, size_t size)
163
+ {
162
164
  size_t i = 0, nb = 0;
163
165
  /* address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' */
164
166
  while (i < size && (data[i] == '-' || data[i] == '.'
@@ -169,12 +171,13 @@ is_mail_autolink(char *data, size_t size) {
169
171
  if (data[i] == '@') nb += 1;
170
172
  i += 1; }
171
173
  if (i >= size || data[i] != '>' || nb != 1) return 0;
172
- return i + 1; }
173
-
174
+ return i + 1;
175
+ }
174
176
 
175
177
  /* tag_length • returns the length of the given tag, or 0 is it's not valid */
176
178
  static size_t
177
- tag_length(char *data, size_t size, enum mkd_autolink *autolink) {
179
+ tag_length(char *data, size_t size, enum mkd_autolink *autolink)
180
+ {
178
181
  size_t i, j;
179
182
 
180
183
  /* a valid tag can't be shorter than 3 chars */
@@ -225,12 +228,13 @@ tag_length(char *data, size_t size, enum mkd_autolink *autolink) {
225
228
  /* looking for sometinhg looking like a tag end */
226
229
  while (i < size && data[i] != '>') i += 1;
227
230
  if (i >= size) return 0;
228
- return i + 1; }
229
-
231
+ return i + 1;
232
+ }
230
233
 
231
234
  /* parse_inline • parses inline markdown elements */
232
235
  static void
233
- parse_inline(struct buf *ob, struct render *rndr, char *data, size_t size) {
236
+ parse_inline(struct buf *ob, struct render *rndr, char *data, size_t size)
237
+ {
234
238
  size_t i = 0, end = 0;
235
239
  char_trigger action = 0;
236
240
  struct buf work = { 0, 0, 0, 0, 0 };
@@ -256,12 +260,13 @@ parse_inline(struct buf *ob, struct render *rndr, char *data, size_t size) {
256
260
  end = i + 1;
257
261
  else {
258
262
  i += end;
259
- end = i; } } }
260
-
263
+ end = i; } }
264
+ }
261
265
 
262
266
  /* find_emph_char • looks for the next emph char, skipping other constructs */
263
267
  static size_t
264
- find_emph_char(char *data, size_t size, char c) {
268
+ find_emph_char(char *data, size_t size, char c)
269
+ {
265
270
  size_t i = 1;
266
271
 
267
272
  while (i < size) {
@@ -306,14 +311,14 @@ find_emph_char(char *data, size_t size, char c) {
306
311
  i += 1; }
307
312
  if (i >= size) return tmp_i;
308
313
  i += 1; } }
309
- return 0; }
310
-
314
+ return 0;
315
+ }
311
316
 
312
317
  /* parse_emph1 • parsing single emphase */
313
318
  /* closed by a symbol not preceded by whitespace and not followed by symbol */
314
319
  static size_t
315
- parse_emph1(struct buf *ob, struct render *rndr,
316
- char *data, size_t size, char c) {
320
+ parse_emph1(struct buf *ob, struct render *rndr, char *data, size_t size, char c)
321
+ {
317
322
  size_t i = 0, len;
318
323
  struct buf *work = 0;
319
324
  int r;
@@ -359,11 +364,10 @@ parse_emph1(struct buf *ob, struct render *rndr,
359
364
  return 0;
360
365
  }
361
366
 
362
-
363
367
  /* parse_emph2 • parsing single emphase */
364
368
  static size_t
365
- parse_emph2(struct buf *ob, struct render *rndr,
366
- char *data, size_t size, char c) {
369
+ parse_emph2(struct buf *ob, struct render *rndr, char *data, size_t size, char c)
370
+ {
367
371
  size_t i = 0, len;
368
372
  struct buf *work = 0;
369
373
  int r;
@@ -389,14 +393,14 @@ parse_emph2(struct buf *ob, struct render *rndr,
389
393
  rndr->work.size -= 1;
390
394
  return r ? i + 2 : 0; }
391
395
  i += 1; }
392
- return 0; }
393
-
396
+ return 0;
397
+ }
394
398
 
395
399
  /* parse_emph3 • parsing single emphase */
396
400
  /* finds the first closing tag, and delegates to the other emph */
397
401
  static size_t
398
- parse_emph3(struct buf *ob, struct render *rndr,
399
- char *data, size_t size, char c) {
402
+ parse_emph3(struct buf *ob, struct render *rndr, char *data, size_t size, char c)
403
+ {
400
404
  size_t i = 0, len;
401
405
  int r;
402
406
 
@@ -435,13 +439,13 @@ parse_emph3(struct buf *ob, struct render *rndr,
435
439
  len = parse_emph2(ob, rndr, data - 1, size + 1, c);
436
440
  if (!len) return 0;
437
441
  else return len - 1; } }
438
- return 0; }
439
-
442
+ return 0;
443
+ }
440
444
 
441
445
  /* char_emphasis • single and double emphasis parsing */
442
446
  static size_t
443
- char_emphasis(struct buf *ob, struct render *rndr,
444
- char *data, size_t offset, size_t size) {
447
+ char_emphasis(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
448
+ {
445
449
  char c = data[0];
446
450
  size_t ret;
447
451
  if (size > 2 && data[1] != c) {
@@ -460,13 +464,14 @@ char_emphasis(struct buf *ob, struct render *rndr,
460
464
  || (ret = parse_emph3(ob, rndr, data + 3, size - 3, c)) == 0)
461
465
  return 0;
462
466
  return ret + 3; }
463
- return 0; }
467
+ return 0;
468
+ }
464
469
 
465
470
 
466
471
  /* char_linebreak • '\n' preceded by two spaces (assuming linebreak != 0) */
467
472
  static size_t
468
- char_linebreak(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size) {
469
-
473
+ char_linebreak(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
474
+ {
470
475
  if (offset < 2 || data[-1] != ' ' || data[-2] != ' ')
471
476
  return 0;
472
477
 
@@ -516,8 +521,8 @@ char_codespan(struct buf *ob, struct render *rndr, char *data, size_t offset, si
516
521
 
517
522
  /* char_escape • '\\' backslash escape */
518
523
  static size_t
519
- char_escape(struct buf *ob, struct render *rndr,
520
- char *data, size_t offset, size_t size) {
524
+ char_escape(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
525
+ {
521
526
  struct buf work = { 0, 0, 0, 0, 0 };
522
527
  if (size > 1) {
523
528
  if (rndr->make.normal_text) {
@@ -525,14 +530,14 @@ char_escape(struct buf *ob, struct render *rndr,
525
530
  work.size = 1;
526
531
  rndr->make.normal_text(ob, &work, &rndr->make.render_options); }
527
532
  else bufputc(ob, data[1]); }
528
- return 2; }
529
-
533
+ return 2;
534
+ }
530
535
 
531
536
  /* char_entity • '&' escaped when it doesn't belong to an entity */
532
537
  /* valid entities are assumed to be anything mathing &#?[A-Za-z0-9]+; */
533
538
  static size_t
534
- char_entity(struct buf *ob, struct render *rndr,
535
- char *data, size_t offset, size_t size) {
539
+ char_entity(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
540
+ {
536
541
  size_t end = 1;
537
542
  struct buf work;
538
543
  if (end < size && data[end] == '#') end += 1;
@@ -552,13 +557,13 @@ char_entity(struct buf *ob, struct render *rndr,
552
557
  work.size = end;
553
558
  rndr->make.entity(ob, &work, &rndr->make.render_options); }
554
559
  else bufput(ob, data, end);
555
- return end; }
556
-
560
+ return end;
561
+ }
557
562
 
558
563
  /* char_langle_tag • '<' when tags or autolinks are allowed */
559
564
  static size_t
560
- char_langle_tag(struct buf *ob, struct render *rndr,
561
- char *data, size_t offset, size_t size) {
565
+ char_langle_tag(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
566
+ {
562
567
  enum mkd_autolink altype = MKDA_NOT_AUTOLINK;
563
568
  size_t end = tag_length(data, size, &altype);
564
569
  struct buf work = { data, end, 0, 0, 0 };
@@ -573,13 +578,14 @@ char_langle_tag(struct buf *ob, struct render *rndr,
573
578
  ret = rndr->make.raw_html_tag(ob, &work,
574
579
  &rndr->make.render_options); }
575
580
  if (!ret) return 0;
576
- else return end; }
581
+ else return end;
582
+ }
577
583
 
578
584
 
579
585
  /* char_link • '[': parsing a link or an image */
580
586
  static size_t
581
- char_link(struct buf *ob, struct render *rndr,
582
- char *data, size_t offset, size_t size) {
587
+ char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
588
+ {
583
589
  int is_img = (offset && data[-1] == '!'), level;
584
590
  size_t i = 1, txt_e, link_b = 0, link_e = 0, title_b = 0, title_e = 0;
585
591
  struct buf *content = 0;
@@ -785,16 +791,18 @@ char_link(struct buf *ob, struct render *rndr,
785
791
 
786
792
  /* is_empty • returns the line length when it is empty, 0 otherwise */
787
793
  static size_t
788
- is_empty(char *data, size_t size) {
794
+ is_empty(char *data, size_t size)
795
+ {
789
796
  size_t i;
790
797
  for (i = 0; i < size && data[i] != '\n'; i += 1)
791
798
  if (data[i] != ' ' && data[i] != '\t') return 0;
792
- return i + 1; }
793
-
799
+ return i + 1;
800
+ }
794
801
 
795
802
  /* is_hrule • returns whether a line is a horizontal rule */
796
803
  static int
797
- is_hrule(char *data, size_t size) {
804
+ is_hrule(char *data, size_t size)
805
+ {
798
806
  size_t i = 0, n = 0;
799
807
  char c;
800
808
 
@@ -817,12 +825,13 @@ is_hrule(char *data, size_t size) {
817
825
  return 0;
818
826
  i += 1; }
819
827
 
820
- return n >= 3; }
821
-
828
+ return n >= 3;
829
+ }
822
830
 
823
831
  /* is_headerline • returns whether the line is a setext-style hdr underline */
824
832
  static int
825
- is_headerline(char *data, size_t size) {
833
+ is_headerline(char *data, size_t size)
834
+ {
826
835
  size_t i = 0;
827
836
 
828
837
  /* test of level 1 header */
@@ -837,12 +846,13 @@ is_headerline(char *data, size_t size) {
837
846
  while (i < size && (data[i] == ' ' || data[i] == '\t')) i += 1;
838
847
  return (i >= size || data[i] == '\n') ? 2 : 0; }
839
848
 
840
- return 0; }
841
-
849
+ return 0;
850
+ }
842
851
 
843
852
  /* prefix_quote • returns blockquote prefix length */
844
853
  static size_t
845
- prefix_quote(char *data, size_t size) {
854
+ prefix_quote(char *data, size_t size)
855
+ {
846
856
  size_t i = 0;
847
857
  if (i < size && data[i] == ' ') i += 1;
848
858
  if (i < size && data[i] == ' ') i += 1;
@@ -851,20 +861,23 @@ prefix_quote(char *data, size_t size) {
851
861
  if (i + 1 < size && (data[i + 1] == ' ' || data[i+1] == '\t'))
852
862
  return i + 2;
853
863
  else return i + 1; }
854
- else return 0; }
855
-
864
+ else return 0;
865
+ }
856
866
 
857
867
  /* prefix_code • returns prefix length for block code*/
858
868
  static size_t
859
- prefix_code(char *data, size_t size) {
869
+ prefix_code(char *data, size_t size)
870
+ {
860
871
  if (size > 0 && data[0] == '\t') return 1;
861
872
  if (size > 3 && data[0] == ' ' && data[1] == ' '
862
873
  && data[2] == ' ' && data[3] == ' ') return 4;
863
- return 0; }
874
+ return 0;
875
+ }
864
876
 
865
877
  /* prefix_oli • returns ordered list item prefix */
866
878
  static size_t
867
- prefix_oli(char *data, size_t size) {
879
+ prefix_oli(char *data, size_t size)
880
+ {
868
881
  size_t i = 0;
869
882
  if (i < size && data[i] == ' ') i += 1;
870
883
  if (i < size && data[i] == ' ') i += 1;
@@ -873,12 +886,13 @@ prefix_oli(char *data, size_t size) {
873
886
  while (i < size && data[i] >= '0' && data[i] <= '9') i += 1;
874
887
  if (i + 1 >= size || data[i] != '.'
875
888
  || (data[i + 1] != ' ' && data[i + 1] != '\t')) return 0;
876
- return i + 2; }
877
-
889
+ return i + 2;
890
+ }
878
891
 
879
892
  /* prefix_uli • returns ordered list item prefix */
880
893
  static size_t
881
- prefix_uli(char *data, size_t size) {
894
+ prefix_uli(char *data, size_t size)
895
+ {
882
896
  size_t i = 0;
883
897
  if (i < size && data[i] == ' ') i += 1;
884
898
  if (i < size && data[i] == ' ') i += 1;
@@ -887,7 +901,8 @@ prefix_uli(char *data, size_t size) {
887
901
  || (data[i] != '*' && data[i] != '+' && data[i] != '-')
888
902
  || (data[i + 1] != ' ' && data[i + 1] != '\t'))
889
903
  return 0;
890
- return i + 2; }
904
+ return i + 2;
905
+ }
891
906
 
892
907
 
893
908
  /* parse_block • parsing of one block, returning next char to parse */
@@ -897,7 +912,8 @@ static void parse_block(struct buf *ob, struct render *rndr,
897
912
 
898
913
  /* parse_blockquote • hanldes parsing of a blockquote fragment */
899
914
  static size_t
900
- parse_blockquote(struct buf *ob, struct render *rndr, char *data, size_t size, int depth) {
915
+ parse_blockquote(struct buf *ob, struct render *rndr, char *data, size_t size, int depth)
916
+ {
901
917
  size_t beg, end = 0, pre, work_size = 0;
902
918
  char *work_data = 0;
903
919
  struct buf *out = 0;
@@ -942,8 +958,8 @@ parse_htmlblock(struct buf *ob, struct render *rndr, char *data, size_t size, in
942
958
 
943
959
  /* parse_blockquote • hanldes parsing of a regular paragraph */
944
960
  static size_t
945
- parse_paragraph(struct buf *ob, struct render *rndr,
946
- char *data, size_t size) {
961
+ parse_paragraph(struct buf *ob, struct render *rndr, char *data, size_t size)
962
+ {
947
963
  size_t i = 0, end = 0;
948
964
  int level = 0;
949
965
  struct buf work = { data, 0, 0, 0, 0 }; /* volatile working buffer */
@@ -1015,14 +1031,14 @@ parse_paragraph(struct buf *ob, struct render *rndr,
1015
1031
  work.size = i - beg; }
1016
1032
  else work.size = i; }
1017
1033
  if (rndr->make.header)
1018
- rndr->make.header(ob, &work, level, &rndr->make.render_options);}
1019
- return end; }
1020
-
1034
+ rndr->make.header(ob, &work, level, rndr->header_count++, &rndr->make.render_options);}
1035
+ return end;
1036
+ }
1021
1037
 
1022
1038
  /* parse_blockquote • hanldes parsing of a block-level code fragment */
1023
1039
  static size_t
1024
- parse_blockcode(struct buf *ob, struct render *rndr,
1025
- char *data, size_t size) {
1040
+ parse_blockcode(struct buf *ob, struct render *rndr, char *data, size_t size)
1041
+ {
1026
1042
  size_t beg, end, pre;
1027
1043
  struct buf *work = 0;
1028
1044
 
@@ -1056,8 +1072,8 @@ parse_blockcode(struct buf *ob, struct render *rndr,
1056
1072
  if (rndr->make.blockcode)
1057
1073
  rndr->make.blockcode(ob, work, &rndr->make.render_options);
1058
1074
  rndr->work.size -= 1;
1059
- return beg; }
1060
-
1075
+ return beg;
1076
+ }
1061
1077
 
1062
1078
  /* parse_listitem • parsing of a single list item */
1063
1079
  /* assuming initial prefix is already removed */
@@ -1188,7 +1204,8 @@ parse_listitem(struct buf *ob, struct render *rndr, char *data, size_t size, int
1188
1204
 
1189
1205
  /* parse_list • parsing ordered or unordered list block */
1190
1206
  static size_t
1191
- parse_list(struct buf *ob, struct render *rndr, char *data, size_t size, int flags, int depth) {
1207
+ parse_list(struct buf *ob, struct render *rndr, char *data, size_t size, int flags, int depth)
1208
+ {
1192
1209
  struct buf *work = 0;
1193
1210
  size_t i = 0, j;
1194
1211
 
@@ -1216,7 +1233,8 @@ parse_list(struct buf *ob, struct render *rndr, char *data, size_t size, int fla
1216
1233
 
1217
1234
  /* parse_atxheader • parsing of atx-style headers */
1218
1235
  static size_t
1219
- parse_atxheader(struct buf *ob, struct render *rndr, char *data, size_t size) {
1236
+ parse_atxheader(struct buf *ob, struct render *rndr, char *data, size_t size)
1237
+ {
1220
1238
  size_t level = 0;
1221
1239
  size_t i, end, skip;
1222
1240
  struct buf work = { data, 0, 0, 0, 0 };
@@ -1232,7 +1250,7 @@ parse_atxheader(struct buf *ob, struct render *rndr, char *data, size_t size) {
1232
1250
  while (end && (data[end - 1] == ' ' || data[end - 1] == '\t')) end -= 1;
1233
1251
  work.size = end - i;
1234
1252
  if (rndr->make.header)
1235
- rndr->make.header(ob, &work, (int)level, &rndr->make.render_options);
1253
+ rndr->make.header(ob, &work, (int)level, rndr->header_count++, &rndr->make.render_options);
1236
1254
  return skip;
1237
1255
  }
1238
1256
 
@@ -1240,7 +1258,8 @@ parse_atxheader(struct buf *ob, struct render *rndr, char *data, size_t size) {
1240
1258
  /* htmlblock_end • checking end of HTML block : </tag>[ \t]*\n[ \t*]\n */
1241
1259
  /* returns the length on match, 0 otherwise */
1242
1260
  static size_t
1243
- htmlblock_end(struct html_tag *tag, char *data, size_t size) {
1261
+ htmlblock_end(struct html_tag *tag, char *data, size_t size)
1262
+ {
1244
1263
  size_t i, w;
1245
1264
 
1246
1265
  /* assuming data[0] == '<' && data[1] == '/' already tested */
@@ -1274,7 +1293,8 @@ htmlblock_end(struct html_tag *tag, char *data, size_t size) {
1274
1293
 
1275
1294
  /* parse_htmlblock • parsing of inline HTML block */
1276
1295
  static size_t
1277
- parse_htmlblock(struct buf *ob, struct render *rndr, char *data, size_t size, int do_render) {
1296
+ parse_htmlblock(struct buf *ob, struct render *rndr, char *data, size_t size, int do_render)
1297
+ {
1278
1298
  size_t i, j = 0;
1279
1299
  struct html_tag *curtag;
1280
1300
  int found;
@@ -1382,7 +1402,8 @@ parse_htmlblock(struct buf *ob, struct render *rndr, char *data, size_t size, in
1382
1402
 
1383
1403
  /* parse_block • parsing of one block, returning next char to parse */
1384
1404
  static void
1385
- parse_block(struct buf *ob, struct render *rndr, char *data, size_t size, int depth) {
1405
+ parse_block(struct buf *ob, struct render *rndr, char *data, size_t size, int depth)
1406
+ {
1386
1407
  size_t beg, end, i;
1387
1408
  char *txt_data;
1388
1409
  beg = 0;
@@ -1426,7 +1447,8 @@ parse_block(struct buf *ob, struct render *rndr, char *data, size_t size, int de
1426
1447
 
1427
1448
  /* is_ref • returns whether a line is a reference or not */
1428
1449
  static int
1429
- is_ref(char *data, size_t beg, size_t end, size_t *last, struct array *refs) {
1450
+ is_ref(char *data, size_t beg, size_t end, size_t *last, struct array *refs)
1451
+ {
1430
1452
  /* int n; */
1431
1453
  size_t i = 0;
1432
1454
  size_t id_offset, id_end;
@@ -1523,13 +1545,9 @@ is_ref(char *data, size_t beg, size_t end, size_t *last, struct array *refs) {
1523
1545
  bufput(lr->title, data + title_offset,
1524
1546
  title_end - title_offset); }
1525
1547
  else lr->title = 0;
1526
- return 1; }
1527
-
1528
-
1548
+ return 1;
1549
+ }
1529
1550
 
1530
- /**********************
1531
- * EXPORTED FUNCTIONS *
1532
- **********************/
1533
1551
  static void expand_tabs(struct buf *ob, const char *line, size_t size)
1534
1552
  {
1535
1553
  size_t i = 0, tab = 0;
@@ -1555,6 +1573,10 @@ static void expand_tabs(struct buf *ob, const char *line, size_t size)
1555
1573
  }
1556
1574
  }
1557
1575
 
1576
+ /**********************
1577
+ * EXPORTED FUNCTIONS *
1578
+ **********************/
1579
+
1558
1580
  /* markdown • parses the input buffer and renders it into the output buffer */
1559
1581
  void
1560
1582
  markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer) {
@@ -1564,7 +1586,9 @@ markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer) {
1564
1586
  struct render rndr;
1565
1587
 
1566
1588
  /* filling the render structure */
1567
- if (!rndrer) return;
1589
+ if (!rndrer)
1590
+ return;
1591
+
1568
1592
  rndr.make = *rndrer;
1569
1593
  arr_init(&rndr.refs, sizeof (struct link_ref));
1570
1594
  parr_init(&rndr.work);
@@ -1591,6 +1615,8 @@ markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer) {
1591
1615
  rndr.active_char['\\'] = char_escape;
1592
1616
  rndr.active_char['&'] = char_entity;
1593
1617
 
1618
+ rndr.header_count = 1;
1619
+
1594
1620
  /* first pass: looking for references, copying everything else */
1595
1621
  beg = 0;
1596
1622
  while (beg < ib->size) /* iterating over lines */
@@ -1628,6 +1654,8 @@ markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer) {
1628
1654
 
1629
1655
  /* second pass: actual rendering */
1630
1656
  parse_block(ob, &rndr, text->data, text->size, 0 /* initial depth */);
1657
+ if (rndr.make.finalize)
1658
+ rndr.make.finalize(ob, &rndr.make.render_options);
1631
1659
 
1632
1660
  /* clean-up */
1633
1661
  bufrelease(text);
data/ext/markdown.h CHANGED
@@ -37,7 +37,11 @@ enum mkd_autolink {
37
37
  };
38
38
 
39
39
  struct mkd_renderopt {
40
- void *opaque;
40
+ union {
41
+ int data;
42
+ void *ptr;
43
+ } opaque;
44
+
41
45
  unsigned int flags;
42
46
  };
43
47
 
@@ -52,7 +56,7 @@ struct mkd_renderer {
52
56
  void (*blockcode)(struct buf *ob, struct buf *text, struct mkd_renderopt *opaque);
53
57
  void (*blockquote)(struct buf *ob, struct buf *text, struct mkd_renderopt *opaque);
54
58
  void (*blockhtml)(struct buf *ob, struct buf *text, struct mkd_renderopt *opaque);
55
- void (*header)(struct buf *ob, struct buf *text, int level, struct mkd_renderopt *opaque);
59
+ void (*header)(struct buf *ob, struct buf *text, int level, int header_count, struct mkd_renderopt *opaque);
56
60
  void (*hrule)(struct buf *ob, struct mkd_renderopt *opaque);
57
61
  void (*list)(struct buf *ob, struct buf *text, int flags, struct mkd_renderopt *opaque);
58
62
  void (*listitem)(struct buf *ob, struct buf *text, int flags, struct mkd_renderopt *opaque);
@@ -73,6 +77,9 @@ struct mkd_renderer {
73
77
  void (*entity)(struct buf *ob, struct buf *entity, struct mkd_renderopt *opaque);
74
78
  void (*normal_text)(struct buf *ob, struct buf *text, struct mkd_renderopt *opaque);
75
79
 
80
+ /* finalizer */
81
+ void (*finalize)(struct buf *ob, struct mkd_renderopt *opaque);
82
+
76
83
  /* renderer data */
77
84
  const char *emph_chars; /* chars that trigger emphasis rendering */
78
85
 
@@ -99,6 +106,7 @@ typedef enum {
99
106
  RENDER_EXPAND_TABS = (1 << 5),
100
107
  RENDER_AUTOLINK = (1 << 6),
101
108
  RENDER_SAFELINK = (1 << 7),
109
+ RENDER_TOC = (1 << 8),
102
110
  } render_mode;
103
111
 
104
112
  typedef enum {
@@ -114,10 +122,12 @@ void
114
122
  markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndr);
115
123
 
116
124
  void
117
- init_renderer(struct mkd_renderer *renderer,
118
- unsigned int render_flags, void *opaque,
125
+ init_xhtml_renderer(struct mkd_renderer *renderer,
126
+ unsigned int render_flags,
119
127
  unsigned int parser_flags, int recursion_depth);
120
128
 
129
+ void
130
+ init_toc_renderer(struct mkd_renderer *renderer, int recursion_depth);
121
131
 
122
132
  #endif /* ndef LITHIUM_MARKDOWN_H */
123
133
 
data/ext/redcarpet.c CHANGED
@@ -3,9 +3,17 @@
3
3
 
4
4
  #include "markdown.h"
5
5
 
6
+ #define REDCARPET_RECURSION_LIMIT 16
7
+
8
+ typedef enum
9
+ {
10
+ REDCARPET_RENDER_XHTML,
11
+ REDCARPET_RENDER_TOC
12
+ } RendererType;
13
+
6
14
  static VALUE rb_cRedcarpet;
7
15
 
8
- static void rb_redcarpet__setup_render(VALUE ruby_obj, struct mkd_renderer *rnd)
16
+ static void rb_redcarpet__setup_xhtml(struct mkd_renderer *rnd, VALUE ruby_obj)
9
17
  {
10
18
  unsigned int render_flags = RENDER_EXPAND_TABS;
11
19
  unsigned int parser_flags = 0;
@@ -38,22 +46,23 @@ static void rb_redcarpet__setup_render(VALUE ruby_obj, struct mkd_renderer *rnd)
38
46
  if (rb_funcall(ruby_obj, rb_intern("safelink"), 0) == Qtrue)
39
47
  render_flags |= RENDER_SAFELINK;
40
48
 
49
+ if (rb_funcall(ruby_obj, rb_intern("generate_toc"), 0) == Qtrue)
50
+ render_flags |= RENDER_TOC;
41
51
 
42
52
  /* parser - strict */
43
53
  if (rb_funcall(ruby_obj, rb_intern("strict"), 0) == Qtrue)
44
54
  parser_flags |= PARSER_STRICT;
45
55
 
46
-
47
- init_renderer(rnd, render_flags, NULL, parser_flags, 16);
56
+ init_xhtml_renderer(rnd, render_flags, parser_flags, REDCARPET_RECURSION_LIMIT);
48
57
  }
49
58
 
50
- static VALUE rb_redcarpet_to_html(int argc, VALUE *argv, VALUE self)
59
+ static VALUE rb_redcarpet__render(VALUE self, RendererType render_type)
51
60
  {
52
61
  VALUE text = rb_funcall(self, rb_intern("text"), 0);
53
62
  VALUE result;
54
63
 
55
64
  struct buf input_buf, *output_buf;
56
- struct mkd_renderer redcarpet_render;
65
+ struct mkd_renderer renderer;
57
66
 
58
67
  Check_Type(text, T_STRING);
59
68
 
@@ -63,8 +72,20 @@ static VALUE rb_redcarpet_to_html(int argc, VALUE *argv, VALUE self)
63
72
 
64
73
  output_buf = bufnew(64);
65
74
 
66
- rb_redcarpet__setup_render(self, &redcarpet_render);
67
- markdown(output_buf, &input_buf, &redcarpet_render);
75
+ switch (render_type) {
76
+ case REDCARPET_RENDER_XHTML:
77
+ rb_redcarpet__setup_xhtml(&renderer, self);
78
+ break;
79
+
80
+ case REDCARPET_RENDER_TOC:
81
+ init_toc_renderer(&renderer, REDCARPET_RECURSION_LIMIT);
82
+ break;
83
+
84
+ default:
85
+ return Qnil;
86
+ }
87
+
88
+ markdown(output_buf, &input_buf, &renderer);
68
89
 
69
90
  result = rb_str_new(output_buf->data, output_buf->size);
70
91
  bufrelease(output_buf);
@@ -78,9 +99,22 @@ static VALUE rb_redcarpet_to_html(int argc, VALUE *argv, VALUE self)
78
99
  return result;
79
100
  }
80
101
 
102
+ static VALUE
103
+ rb_redcarpet_toc(int argc, VALUE *argv, VALUE self)
104
+ {
105
+ return rb_redcarpet__render(self, REDCARPET_RENDER_TOC);
106
+ }
107
+
108
+ static VALUE
109
+ rb_redcarpet_to_html(int argc, VALUE *argv, VALUE self)
110
+ {
111
+ return rb_redcarpet__render(self, REDCARPET_RENDER_XHTML);
112
+ }
113
+
81
114
  void Init_redcarpet()
82
115
  {
83
116
  rb_cRedcarpet = rb_define_class("Redcarpet", rb_cObject);
84
117
  rb_define_method(rb_cRedcarpet, "to_html", rb_redcarpet_to_html, -1);
118
+ rb_define_method(rb_cRedcarpet, "toc_content", rb_redcarpet_toc, -1);
85
119
  }
86
120
 
data/ext/render.c CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
- * Copyright (c) 2011, Vicent Marti
3
2
  * Copyright (c) 2009, Natacha Porté
3
+ * Copyright (c) 2011, Vicent Marti
4
4
  *
5
5
  * Permission to use, copy, modify, and distribute this software for any
6
6
  * purpose with or without fee is hereby granted, provided that the above
@@ -53,7 +53,6 @@ put_scaped_char(struct buf *ob, char c)
53
53
  }
54
54
  }
55
55
 
56
-
57
56
  /* lus_attr_escape • copy the buffer entity-escaping '<', '>', '&' and '"' */
58
57
  static void
59
58
  lus_attr_escape(struct buf *ob, const char *src, size_t size)
@@ -168,9 +167,14 @@ rndr_emphasis(struct buf *ob, struct buf *text, char c, struct mkd_renderopt *op
168
167
  }
169
168
 
170
169
  static void
171
- rndr_header(struct buf *ob, struct buf *text, int level, struct mkd_renderopt *options)
170
+ rndr_header(struct buf *ob, struct buf *text, int level, int header_count, struct mkd_renderopt *options)
172
171
  {
173
- if (ob->size) bufputc(ob, '\n');
172
+ if (ob->size)
173
+ bufputc(ob, '\n');
174
+
175
+ if (options->flags & RENDER_TOC)
176
+ bufprintf(ob, "<a name=\"toc_%d\"></a>", header_count);
177
+
174
178
  bufprintf(ob, "<h%d>", level);
175
179
  if (text) bufput(ob, text->data, text->size);
176
180
  bufprintf(ob, "</h%d>\n", level);
@@ -552,8 +556,8 @@ rndr_normal_text(struct buf *ob, struct buf *text, struct mkd_renderopt *options
552
556
  }
553
557
 
554
558
  void
555
- init_renderer(struct mkd_renderer *renderer,
556
- unsigned int render_flags, void *opaque,
559
+ init_xhtml_renderer(struct mkd_renderer *renderer,
560
+ unsigned int render_flags,
557
561
  unsigned int parser_flags, int recursion_depth)
558
562
  {
559
563
  static const struct mkd_renderer renderer_default = {
@@ -578,10 +582,11 @@ init_renderer(struct mkd_renderer *renderer,
578
582
 
579
583
  NULL,
580
584
  rndr_normal_text,
585
+ NULL,
581
586
 
582
587
  "*_",
583
588
 
584
- { NULL, 0 },
589
+ { 0, 0 },
585
590
  { 0, 0 },
586
591
  };
587
592
 
@@ -597,8 +602,6 @@ init_renderer(struct mkd_renderer *renderer,
597
602
 
598
603
  renderer->parser_options.recursion_depth = recursion_depth;
599
604
  renderer->parser_options.flags = parser_flags;
600
-
601
- renderer->render_options.opaque = opaque;
602
605
  renderer->render_options.flags = render_flags;
603
606
  }
604
607
 
data/ext/toc.c ADDED
@@ -0,0 +1,101 @@
1
+ /*
2
+ * Copyright (c) 2011, Vicent Marti
3
+ *
4
+ * Permission to use, copy, modify, and distribute this software for any
5
+ * purpose with or without fee is hereby granted, provided that the above
6
+ * copyright notice and this permission notice appear in all copies.
7
+ *
8
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+ */
16
+
17
+ #include "markdown.h"
18
+
19
+ #include <strings.h>
20
+ #include <stdlib.h>
21
+ #include <stdio.h>
22
+
23
+ static void
24
+ toc_header(struct buf *ob, struct buf *text, int level, int header_id, struct mkd_renderopt *options)
25
+ {
26
+ int current_level = (int)options->opaque.data;
27
+
28
+ if (level > current_level) {
29
+ if (level > 1)
30
+ BUFPUTSL(ob, "<li>");
31
+ BUFPUTSL(ob, "<ul>\n");
32
+ }
33
+
34
+ if (level < current_level) {
35
+ BUFPUTSL(ob, "</ul>");
36
+ if (current_level > 1)
37
+ BUFPUTSL(ob, "</li>\n");
38
+ }
39
+
40
+ options->opaque.data = level;
41
+
42
+ bufprintf(ob, "<li><a href=\"#toc_%d\">", header_id);
43
+ if (text)
44
+ bufput(ob, text->data, text->size);
45
+ BUFPUTSL(ob, "</a></li>\n");
46
+ }
47
+
48
+ static void
49
+ toc_finalize(struct buf *ob, struct mkd_renderopt *options)
50
+ {
51
+ int current_level = (int)options->opaque.data;
52
+
53
+ while (current_level > 1) {
54
+ BUFPUTSL(ob, "</ul></li>\n");
55
+ current_level--;
56
+ }
57
+
58
+ if (current_level)
59
+ BUFPUTSL(ob, "</ul>\n");
60
+ }
61
+
62
+ void
63
+ init_toc_renderer(struct mkd_renderer *renderer, int recursion_depth)
64
+ {
65
+ static const struct mkd_renderer toc_render = {
66
+ NULL,
67
+ NULL,
68
+ NULL,
69
+ toc_header,
70
+ NULL,
71
+ NULL,
72
+ NULL,
73
+ NULL,
74
+
75
+ NULL,
76
+ NULL,
77
+ NULL,
78
+ NULL,
79
+ NULL,
80
+ NULL,
81
+ NULL,
82
+ NULL,
83
+ NULL,
84
+
85
+ NULL,
86
+ NULL,
87
+ toc_finalize,
88
+
89
+ NULL,
90
+
91
+ { 0, 0 },
92
+ { 0, 0 },
93
+ };
94
+
95
+ memcpy(renderer, &toc_render, sizeof(struct mkd_renderer));
96
+
97
+ renderer->parser_options.recursion_depth = recursion_depth;
98
+ renderer->render_options.flags = RENDER_TOC;
99
+ renderer->render_options.opaque.data = 0;
100
+ }
101
+
data/lib/redcarpet.rb CHANGED
@@ -26,7 +26,7 @@
26
26
  # end
27
27
  #
28
28
  class Redcarpet
29
- VERSION = '1.1.1'
29
+ VERSION = '1.2.0'
30
30
 
31
31
  # Original Markdown formatted text.
32
32
  attr_reader :text
@@ -57,14 +57,13 @@ class Redcarpet
57
57
  # Don't make hyperlinks from <tt>[][]</tt> links that have unknown URL types.
58
58
  attr_accessor :safelink
59
59
 
60
+ # Add TOC anchors to every header
61
+ attr_accessor :generate_toc
62
+
60
63
  def initialize(text, *extensions)
61
64
  @text = text
62
65
  extensions.each { |e| send("#{e}=", true) }
63
66
  end
64
-
65
- def generate_toc
66
- raise NotImplementedError
67
- end
68
67
  end
69
68
 
70
69
  Markdown = Redcarpet unless defined? Markdown
data/redcarpet.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'redcarpet'
3
- s.version = '1.1.1'
3
+ s.version = '1.2.0'
4
4
  s.summary = "Ruby bindings for libupskirt"
5
5
  s.date = '2011-04-02'
6
6
  s.email = 'vicent@github.com'
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
22
22
  ext/markdown.h
23
23
  ext/redcarpet.c
24
24
  ext/render.c
25
+ ext/toc.c
25
26
  lib/markdown.rb
26
27
  lib/redcarpet.rb
27
28
  redcarpet.gemspec
@@ -109,4 +109,17 @@ class RedcarpetTest < Test::Unit::TestCase
109
109
  assert_equal "<pre><code>This is a code block\nThis is a link [[1]] inside\n</code></pre>\n",
110
110
  markdown.to_html
111
111
  end
112
+
113
+ def test_that_generate_toc_sets_toc_ids
114
+ rd = Redcarpet.new("# Level 1\n\n## Level 2", :generate_toc)
115
+ assert rd.generate_toc
116
+ assert_equal %(<a name="toc_1"></a><h1>Level 1</h1>\n\n<a name="toc_2"></a><h2>Level 2</h2>\n), rd.to_html
117
+ end
118
+
119
+ def test_should_get_the_generated_toc
120
+ rd = Redcarpet.new("# Level 1\n\n## Level 2", :generate_toc)
121
+ exp = %(<ul>\n<li><a href="#toc_1">Level 1</a></li>\n<li><ul>\n<li><a href="#toc_2">Level 2</a></li>\n</ul></li>\n</ul>)
122
+ assert_equal exp, rd.toc_content.strip
123
+ end
124
+
112
125
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redcarpet
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 1
9
- - 1
10
- version: 1.1.1
8
+ - 2
9
+ - 0
10
+ version: 1.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - "Natacha Port\xC3\xA9"
@@ -42,6 +42,7 @@ files:
42
42
  - ext/markdown.h
43
43
  - ext/redcarpet.c
44
44
  - ext/render.c
45
+ - ext/toc.c
45
46
  - lib/markdown.rb
46
47
  - lib/redcarpet.rb
47
48
  - redcarpet.gemspec