rdiscount 1.6.8 → 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/BUILDING CHANGED
@@ -16,8 +16,12 @@ Gathering changes from an upstream Orc/discount.git clone requires first
16
16
  grabbing the discount submodule into the root of the project and then running
17
17
  the rake gather task to copy discount source files into the ext/ directory:
18
18
 
19
- $ git submodule init
19
+ $ git submodule update --init
20
20
  Submodule 'discount' (git://github.com/rtomayko/discount.git) registered for path 'discount'
21
+ Cloning into discount...
22
+ $ cd discount
23
+ $ ./configure.sh # to generate mkdio.h from mkdio.h.in
24
+ $ cd ..
21
25
  $ rake gather
22
26
  $ rake build
23
27
 
@@ -8,22 +8,22 @@ passes the [Markdown 1.0 test suite][2].
8
8
  CODE: `git clone git://github.com/rtomayko/rdiscount.git`
9
9
  HOME: <http://github.com/rtomayko/rdiscount>
10
10
  DOCS: <http://rdoc.info/projects/rtomayko/rdiscount>
11
- BUGS: <http://github.com/rtomayko/rdiscount/issues>
11
+ BUGS: <http://github.com/rtomayko/rdiscount/issues>
12
12
 
13
13
  Discount was developed by [David Loren Parsons][3]. The Ruby extension
14
- is maintained by [Ryan Tomayko][4].
14
+ is maintained by [David Foster][4].
15
15
 
16
16
  [1]: http://daringfireball.net/projects/markdown/syntax
17
17
  [2]: http://daringfireball.net/projects/downloads/MarkdownTest_1.0.zip
18
18
  [3]: http://www.pell.portland.or.us/~orc
19
- [4]: http://tomayko.com/about
19
+ [4]: https://github.com/davidfstr
20
20
 
21
21
  INSTALL, HACKING
22
22
  ----------------
23
23
 
24
- New releases of RDiscount are published to [gemcutter][]:
24
+ New releases of RDiscount are published to [RubyGems][]:
25
25
 
26
- $ [sudo] gem install rdiscount -s http://gemcutter.org
26
+ $ [sudo] gem install rdiscount
27
27
 
28
28
  The RDiscount sources are available via Git:
29
29
 
@@ -33,8 +33,8 @@ The RDiscount sources are available via Git:
33
33
 
34
34
  See the file [BUILDING][] for hacking instructions.
35
35
 
36
- [gemcutter]: http://gemcutter.org/gems/rdiscount
37
- [BUILDING]: BUILDING
36
+ [RubyGems]: https://rubygems.org/gems/rdiscount
37
+ [BUILDING]: https://github.com/rtomayko/rdiscount/blob/master/BUILDING
38
38
 
39
39
  USAGE
40
40
  -----
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ task :default => :test
9
9
  # ==========================================================
10
10
 
11
11
  DLEXT = Config::MAKEFILE_CONFIG['DLEXT']
12
- RUBYDIGEST = Digest::MD5.hexdigest(`#{RUBY} --version`)
12
+ RUBYDIGEST = Digest::MD5.hexdigest(`ruby --version`)
13
13
 
14
14
  file "ext/ruby-#{RUBYDIGEST}" do |f|
15
15
  rm_f FileList["ext/ruby-*"]
@@ -61,8 +61,9 @@ desc 'Run conformance tests (MARKDOWN_TEST_VER=1.0)'
61
61
  task 'test:conformance' => [:build] do |t|
62
62
  script = "#{pwd}/bin/rdiscount"
63
63
  test_version = ENV['MARKDOWN_TEST_VER'] || '1.0.3'
64
+ lib_dir = "#{pwd}/lib"
64
65
  chdir("test/MarkdownTest_#{test_version}") do
65
- sh "./MarkdownTest.pl --script='#{script}' --tidy"
66
+ sh "RUBYLIB=#{lib_dir} ./MarkdownTest.pl --script='#{script}' --tidy"
66
67
  end
67
68
  end
68
69
 
@@ -1,10 +1,13 @@
1
+ /*
2
+ * rdiscount extension discount configuration
3
+ */
4
+ #ifndef __MARKDOWN_D
5
+ #define __MARKDOWN_D 1
1
6
 
2
- /* rdiscount extension configuration */
3
-
4
- #undef USE_AMALLOC
5
-
7
+ /* tabs are four spaces */
6
8
  #define TABSTOP 4
7
9
 
10
+ /* these are setup by extconf.rb */
8
11
  #if HAVE_RANDOM
9
12
  #define COINTOSS() (random()&1)
10
13
  #elif HAVE_RAND
@@ -17,5 +20,4 @@
17
20
  #define INITRNG(x) srand((unsigned int)x)
18
21
  #endif
19
22
 
20
- #define RELAXED_EMPHASIS 1
21
- #define SUPERSCRIPT 1
23
+ #endif/* __MARKDOWN_D */
data/ext/css.c CHANGED
@@ -28,9 +28,10 @@ stylesheets(Paragraph *p, Cstring *f)
28
28
 
29
29
  for ( ; p ; p = p->next ) {
30
30
  if ( p->typ == STYLE ) {
31
- for ( q = p->text; q ; q = q->next )
31
+ for ( q = p->text; q ; q = q->next ) {
32
32
  Cswrite(f, T(q->text), S(q->text));
33
33
  Csputc('\n', f);
34
+ }
34
35
  }
35
36
  if ( p->down )
36
37
  stylesheets(p->down, f);
@@ -44,17 +45,25 @@ int
44
45
  mkd_css(Document *d, char **res)
45
46
  {
46
47
  Cstring f;
48
+ int size;
47
49
 
48
- if ( res && *res && d && d->compiled ) {
50
+ if ( res && d && d->compiled ) {
51
+ *res = 0;
49
52
  CREATE(f);
50
53
  RESERVE(f, 100);
51
54
  stylesheets(d->code, &f);
52
55
 
56
+ if ( (size = S(f)) > 0 ) {
57
+ EXPAND(f) = 0;
53
58
  /* HACK ALERT! HACK ALERT! HACK ALERT! */
54
- *res = T(f); /* we know that a T(Cstring) is a character pointer */
59
+ *res = T(f);/* we know that a T(Cstring) is a character pointer */
55
60
  /* so we can simply pick it up and carry it away, */
56
- return S(f); /* leaving the husk of the Ctring on the stack */
61
+ /* leaving the husk of the Ctring on the stack */
57
62
  /* END HACK ALERT */
63
+ }
64
+ else
65
+ DELETE(f);
66
+ return size;
58
67
  }
59
68
  return EOF;
60
69
  }
@@ -69,7 +78,7 @@ mkd_generatecss(Document *d, FILE *f)
69
78
  int written = EOF, size = mkd_css(d, &res);
70
79
 
71
80
  if ( size > 0 )
72
- written = fwrite(res, size, 1, f);
81
+ written = fwrite(res, 1, size, f);
73
82
  if ( res )
74
83
  free(res);
75
84
  return (written == size) ? size : EOF;
@@ -18,7 +18,7 @@
18
18
  */
19
19
  #define STRING(type) struct { type *text; int size, alloc; }
20
20
 
21
- #define CREATE(x) T(x) = (void*)(S(x) = (x).alloc = 0)
21
+ #define CREATE(x) ( (T(x) = (void*)0), (S(x) = (x).alloc = 0) )
22
22
  #define EXPAND(x) (S(x)++)[(S(x) < (x).alloc) \
23
23
  ? (T(x)) \
24
24
  : (T(x) = T(x) ? realloc(T(x), sizeof T(x)[0] * ((x).alloc += 100)) \
@@ -14,13 +14,19 @@
14
14
  #include "markdown.h"
15
15
  #include "amalloc.h"
16
16
 
17
- #define afterdle(t) (T((t)->text) + (t)->dle)
17
+ static char *
18
+ onlyifset(Line *l)
19
+ {
20
+ char *ret = T(l->text) + l->dle;
21
+
22
+ return ret[0] ? ret : 0;
23
+ }
18
24
 
19
25
  char *
20
26
  mkd_doc_title(Document *doc)
21
27
  {
22
- if ( doc && doc->headers )
23
- return afterdle(doc->headers);
28
+ if ( doc && doc->title )
29
+ return onlyifset(doc->title);
24
30
  return 0;
25
31
  }
26
32
 
@@ -28,8 +34,8 @@ mkd_doc_title(Document *doc)
28
34
  char *
29
35
  mkd_doc_author(Document *doc)
30
36
  {
31
- if ( doc && doc->headers && doc->headers->next )
32
- return afterdle(doc->headers->next);
37
+ if ( doc && doc->author )
38
+ return onlyifset(doc->author);
33
39
  return 0;
34
40
  }
35
41
 
@@ -37,7 +43,7 @@ mkd_doc_author(Document *doc)
37
43
  char *
38
44
  mkd_doc_date(Document *doc)
39
45
  {
40
- if ( doc && doc->headers && doc->headers->next && doc->headers->next->next )
41
- return afterdle(doc->headers->next->next);
46
+ if ( doc && doc->date )
47
+ return onlyifset(doc->date);
42
48
  return 0;
43
49
  }
@@ -111,7 +111,7 @@ dumptree(Paragraph *pp, Stack *sp, FILE *f)
111
111
  d = fprintf(f, "[%s", Pptype(pp->typ));
112
112
  if ( pp->ident )
113
113
  d += fprintf(f, " %s", pp->ident);
114
- if ( pp->align )
114
+ if ( pp->align > 1 )
115
115
  d += fprintf(f, ", <%s>", Begin[pp->align]);
116
116
 
117
117
  for (count=0, p=pp->text; p; ++count, (p = p->next) )
@@ -163,7 +163,7 @@ emblock(MMIOT *f, int first, int last)
163
163
  } /* emblock */
164
164
 
165
165
 
166
- /* ___mkd_emblock() -- emblock a string of blocks, then concatinate the
166
+ /* ___mkd_emblock() -- emblock a string of blocks, then concatenate the
167
167
  * resulting text onto f->out.
168
168
  */
169
169
  void
@@ -7,4 +7,17 @@ HAVE_SRANDOM = have_func('srandom')
7
7
  HAVE_RAND = have_func('rand')
8
8
  HAVE_SRAND = have_func('srand')
9
9
 
10
+ def sized_int(size, types)
11
+ types.find { |type| check_sizeof(type) == 4 } ||
12
+ abort("no int with size #{size}")
13
+ end
14
+
15
+ DWORD = sized_int(4, ["unsigned long", "unsigned int"])
16
+ WORD = sized_int(2, ["unsigned int", "unsigned short"])
17
+ BYTE = "unsigned char"
18
+
19
+ $defs.push("-DDWORD='#{DWORD}'")
20
+ $defs.push("-DWORD='#{WORD}'")
21
+ $defs.push("-DBYTE='#{BYTE}'")
22
+
10
23
  create_makefile('rdiscount')
@@ -191,6 +191,7 @@ ___mkd_reparse(char *bfr, int size, int flags, MMIOT *f)
191
191
 
192
192
  sub.flags = f->flags | flags;
193
193
  sub.cb = f->cb;
194
+ sub.ref_prefix = f->ref_prefix;
194
195
 
195
196
  push(bfr, size, &sub);
196
197
  EXPAND(sub.in) = 0;
@@ -351,6 +352,53 @@ linkysize(MMIOT *f, Footnote *ref)
351
352
  }
352
353
 
353
354
 
355
+ /* extract a <...>-encased url from the input stream.
356
+ * (markdown 1.0.2b8 compatibility; older versions
357
+ * of markdown treated the < and > as syntactic
358
+ * sugar that didn't have to be there. 1.0.2b8
359
+ * requires a closing >, and then falls into the
360
+ * title or closing )
361
+ */
362
+ static int
363
+ linkybroket(MMIOT *f, int image, Footnote *p)
364
+ {
365
+ int c;
366
+ int good = 0;
367
+
368
+ T(p->link) = cursor(f);
369
+ for ( S(p->link)=0; (c = pull(f)) != '>'; ++S(p->link) ) {
370
+ /* pull in all input until a '>' is found, or die trying.
371
+ */
372
+ if ( c == EOF )
373
+ return 0;
374
+ else if ( (c == '\\') && ispunct(peek(f,2)) ) {
375
+ ++S(p->link);
376
+ pull(f);
377
+ }
378
+ }
379
+
380
+ c = eatspace(f);
381
+
382
+ /* next nonspace needs to be a title, a size, or )
383
+ */
384
+ if ( ( c == '\'' || c == '"' ) && linkytitle(f,c,p) )
385
+ good=1;
386
+ else if ( image && (c == '=') && linkysize(f,p) )
387
+ good=1;
388
+ else
389
+ good=( c == ')' );
390
+
391
+ if ( good ) {
392
+ if ( peek(f, 1) == ')' )
393
+ pull(f);
394
+
395
+ ___mkd_tidy(&p->link);
396
+ }
397
+
398
+ return good;
399
+ } /* linkybroket */
400
+
401
+
354
402
  /* extract a (-prefixed url from the input stream.
355
403
  * the label is either of the format `<link>`, where I
356
404
  * extract until I find a >, or it is of the format
@@ -368,6 +416,8 @@ linkyurl(MMIOT *f, int image, Footnote *p)
368
416
 
369
417
  if ( c == '<' ) {
370
418
  pull(f);
419
+ if ( !(f->flags & MKD_1_COMPAT) )
420
+ return linkybroket(f,image,p);
371
421
  mayneedtotrim=1;
372
422
  }
373
423
 
@@ -405,10 +455,10 @@ static struct _protocol {
405
455
  int nlen;
406
456
  } protocol[] = {
407
457
  #define _aprotocol(x) { x, (sizeof x)-1 }
408
- _aprotocol( "https://" ),
409
- _aprotocol( "http://" ),
410
- _aprotocol( "news://" ),
411
- _aprotocol( "ftp://" ),
458
+ _aprotocol( "https:" ),
459
+ _aprotocol( "http:" ),
460
+ _aprotocol( "news:" ),
461
+ _aprotocol( "ftp:" ),
412
462
  #undef _aprotocol
413
463
  };
414
464
  #define NRPROTOCOLS (sizeof protocol / sizeof protocol[0])
@@ -445,9 +495,9 @@ typedef struct linkytype {
445
495
  } linkytype;
446
496
 
447
497
  static linkytype imaget = { 0, 0, "<img src=\"", "\"",
448
- 1, " alt=\"", "\" />", DENY_IMG|INSIDE_TAG, IS_URL };
498
+ 1, " alt=\"", "\" />", MKD_NOIMAGE|MKD_TAGTEXT, IS_URL };
449
499
  static linkytype linkt = { 0, 0, "<a href=\"", "\"",
450
- 0, ">", "</a>", DENY_A, IS_URL };
500
+ 0, ">", "</a>", MKD_NOLINKS, IS_URL };
451
501
 
452
502
  /*
453
503
  * pseudo-protocols for [][];
@@ -457,8 +507,8 @@ static linkytype linkt = { 0, 0, "<a href=\"", "\"",
457
507
  * raw: just dump the link without any processing
458
508
  */
459
509
  static linkytype specials[] = {
460
- { "id:", 3, "<a id=\"", "\"", 0, ">", "</a>", 0, IS_URL },
461
- { "raw:", 4, 0, 0, 0, 0, 0, DENY_HTML, 0 },
510
+ { "id:", 3, "<span id=\"", "\"", 0, ">", "</span>", 0, 0 },
511
+ { "raw:", 4, 0, 0, 0, 0, 0, MKD_NOHTML, 0 },
462
512
  { "lang:", 5, "<span lang=\"", "\"", 0, ">", "</span>", 0, 0 },
463
513
  { "abbr:", 5, "<abbr title=\"", "\"", 0, ">", "</abbr>", 0, 0 },
464
514
  { "class:", 6, "<span class=\"", "\"", 0, ">", "</span>", 0, 0 },
@@ -489,10 +539,13 @@ printlinkyref(MMIOT *f, linkytype *tag, char *link, int size)
489
539
  {
490
540
  char *edit;
491
541
 
542
+ if ( f->flags & IS_LABEL )
543
+ return;
544
+
492
545
  Qstring(tag->link_pfx, f);
493
546
 
494
547
  if ( tag->kind & IS_URL ) {
495
- if ( f->cb->e_url && (edit = (*f->cb->e_url)(link, size, f->cb->e_data)) ) {
548
+ if ( f->cb && f->cb->e_url && (edit = (*f->cb->e_url)(link, size, f->cb->e_data)) ) {
496
549
  puturl(edit, strlen(edit), f, 0);
497
550
  if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data);
498
551
  }
@@ -500,11 +553,11 @@ printlinkyref(MMIOT *f, linkytype *tag, char *link, int size)
500
553
  puturl(link + tag->szpat, size - tag->szpat, f, 0);
501
554
  }
502
555
  else
503
- ___mkd_reparse(link + tag->szpat, size - tag->szpat, INSIDE_TAG, f);
556
+ ___mkd_reparse(link + tag->szpat, size - tag->szpat, MKD_TAGTEXT, f);
504
557
 
505
558
  Qstring(tag->link_sfx, f);
506
559
 
507
- if ( f->cb->e_flags && (edit = (*f->cb->e_flags)(link, size, f->cb->e_data)) ) {
560
+ if ( f->cb && f->cb->e_flags && (edit = (*f->cb->e_flags)(link, size, f->cb->e_data)) ) {
508
561
  Qchar(' ', f);
509
562
  Qstring(edit, f);
510
563
  if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data);
@@ -512,6 +565,38 @@ printlinkyref(MMIOT *f, linkytype *tag, char *link, int size)
512
565
  } /* printlinkyref */
513
566
 
514
567
 
568
+ /* helper function for php markdown extra footnotes; allow the user to
569
+ * define a prefix tag instead of just `fn`
570
+ */
571
+ static char *
572
+ p_or_nothing(p)
573
+ MMIOT *p;
574
+ {
575
+ return p->ref_prefix ? p->ref_prefix : "fn";
576
+ }
577
+
578
+
579
+ /* php markdown extra/daring fireball style print footnotes
580
+ */
581
+ static int
582
+ extra_linky(MMIOT *f, Cstring text, Footnote *ref)
583
+ {
584
+ if ( ref->flags & REFERENCED )
585
+ return 0;
586
+
587
+ if ( f->flags & IS_LABEL )
588
+ ___mkd_reparse(T(text), S(text), linkt.flags, f);
589
+ else {
590
+ ref->flags |= REFERENCED;
591
+ ref->refnumber = ++ f->reference;
592
+ Qprintf(f, "<sup id=\"%sref:%d\"><a href=\"#%s:%d\" rel=\"footnote\">%d</a></sup>",
593
+ p_or_nothing(f), ref->refnumber,
594
+ p_or_nothing(f), ref->refnumber, ref->refnumber);
595
+ }
596
+ return 1;
597
+ } /* extra_linky */
598
+
599
+
515
600
  /* print out a linky (or fail if it's Not Allowed)
516
601
  */
517
602
  static int
@@ -519,16 +604,16 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
519
604
  {
520
605
  linkytype *tag;
521
606
 
522
- if ( image )
607
+ if ( image || (ref == 0) )
523
608
  tag = &imaget;
524
609
  else if ( tag = pseudo(ref->link) ) {
525
- if ( f->flags & (NO_PSEUDO_PROTO|SAFELINK) )
610
+ if ( f->flags & (MKD_NO_EXT|MKD_SAFELINK) )
526
611
  return 0;
527
612
  }
528
- else if ( (f->flags & SAFELINK) && T(ref->link)
529
- && (T(ref->link)[0] != '/')
530
- && !isautoprefix(T(ref->link), S(ref->link)) )
531
- /* if SAFELINK, only accept links that are local or
613
+ else if ( (f->flags & MKD_SAFELINK) && T(ref->link)
614
+ && (T(ref->link)[0] != '/')
615
+ && !isautoprefix(T(ref->link), S(ref->link)) )
616
+ /* if MKD_SAFELINK, only accept links that are local or
532
617
  * a well-known protocol
533
618
  */
534
619
  return 0;
@@ -538,7 +623,9 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
538
623
  if ( f->flags & tag->flags )
539
624
  return 0;
540
625
 
541
- if ( tag->link_pfx ) {
626
+ if ( f->flags & IS_LABEL )
627
+ ___mkd_reparse(T(text), S(text), tag->flags, f);
628
+ else if ( tag->link_pfx ) {
542
629
  printlinkyref(f, tag, T(ref->link), S(ref->link));
543
630
 
544
631
  if ( tag->WxH ) {
@@ -548,7 +635,7 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
548
635
 
549
636
  if ( S(ref->title) ) {
550
637
  Qstring(" title=\"", f);
551
- ___mkd_reparse(T(ref->title), S(ref->title), INSIDE_TAG, f);
638
+ ___mkd_reparse(T(ref->title), S(ref->title), MKD_TAGTEXT, f);
552
639
  Qchar('"', f);
553
640
  }
554
641
 
@@ -574,6 +661,7 @@ linkylinky(int image, MMIOT *f)
574
661
  Footnote key, *ref;
575
662
 
576
663
  int status = 0;
664
+ int extra_footnote = 0;
577
665
 
578
666
  CREATE(name);
579
667
  memset(&key, 0, sizeof key);
@@ -587,7 +675,10 @@ linkylinky(int image, MMIOT *f)
587
675
  else {
588
676
  int goodlink, implicit_mark = mmiottell(f);
589
677
 
590
- if ( eatspace(f) == '[' ) {
678
+ if ( isspace(peek(f,1)) )
679
+ pull(f);
680
+
681
+ if ( peek(f,1) == '[' ) {
591
682
  pull(f); /* consume leading '[' */
592
683
  goodlink = linkylabel(f, &key.tag);
593
684
  }
@@ -597,6 +688,9 @@ linkylinky(int image, MMIOT *f)
597
688
  */
598
689
  mmiotseek(f, implicit_mark);
599
690
  goodlink = !(f->flags & MKD_1_COMPAT);
691
+
692
+ if ( (f->flags & MKD_EXTRA_FOOTNOTE) && (!image) && S(name) && T(name)[0] == '^' )
693
+ extra_footnote = 1;
600
694
  }
601
695
 
602
696
  if ( goodlink ) {
@@ -607,8 +701,14 @@ linkylinky(int image, MMIOT *f)
607
701
  }
608
702
 
609
703
  if ( ref = bsearch(&key, T(*f->footnotes), S(*f->footnotes),
610
- sizeof key, (stfu)__mkd_footsort) )
611
- status = linkyformat(f, name, image, ref);
704
+ sizeof key, (stfu)__mkd_footsort) ) {
705
+ if ( extra_footnote )
706
+ status = extra_linky(f,name,ref);
707
+ else
708
+ status = linkyformat(f, name, image, ref);
709
+ }
710
+ else if ( f->flags & IS_LABEL )
711
+ status = linkyformat(f, name, image, 0);
612
712
  }
613
713
  }
614
714
  }
@@ -744,19 +844,19 @@ codespan(MMIOT *f, int size)
744
844
 
745
845
 
746
846
  /* before letting a tag through, validate against
747
- * DENY_A and DENY_IMG
847
+ * MKD_NOLINKS and MKD_NOIMAGE
748
848
  */
749
849
  static int
750
850
  forbidden_tag(MMIOT *f)
751
851
  {
752
852
  int c = toupper(peek(f, 1));
753
853
 
754
- if ( f->flags & DENY_HTML )
854
+ if ( f->flags & MKD_NOHTML )
755
855
  return 1;
756
856
 
757
- if ( c == 'A' && (f->flags & DENY_A) && !isthisalnum(f,2) )
857
+ if ( c == 'A' && (f->flags & MKD_NOLINKS) && !isthisalnum(f,2) )
758
858
  return 1;
759
- if ( c == 'I' && (f->flags & DENY_IMG)
859
+ if ( c == 'I' && (f->flags & MKD_NOIMAGE)
760
860
  && strncasecmp(cursor(f)+1, "MG", 2) == 0
761
861
  && !isthisalnum(f,4) )
762
862
  return 1;
@@ -803,7 +903,7 @@ process_possible_link(MMIOT *f, int size)
803
903
  int mailto = 0;
804
904
  char *text = cursor(f);
805
905
 
806
- if ( f->flags & DENY_A ) return 0;
906
+ if ( f->flags & MKD_NOLINKS ) return 0;
807
907
 
808
908
  if ( (size > 7) && strncasecmp(text, "mailto:", 7) == 0 ) {
809
909
  /* if it says it's a mailto, it's a mailto -- who am
@@ -850,7 +950,7 @@ maybe_tag_or_link(MMIOT *f)
850
950
  int c, size;
851
951
  int maybetag = 1;
852
952
 
853
- if ( f->flags & INSIDE_TAG )
953
+ if ( f->flags & MKD_TAGTEXT )
854
954
  return 0;
855
955
 
856
956
  for ( size=0; (c = peek(f, size+1)) != '>'; size++) {
@@ -1013,7 +1113,7 @@ smartypants(int c, int *flags, MMIOT *f)
1013
1113
  {
1014
1114
  int i;
1015
1115
 
1016
- if ( f->flags & (DENY_SMARTY|INSIDE_TAG) )
1116
+ if ( f->flags & (MKD_NOPANTS|MKD_TAGTEXT|IS_LABEL) )
1017
1117
  return 0;
1018
1118
 
1019
1119
  for ( i=0; i < NRSMART; i++)
@@ -1081,7 +1181,7 @@ tickhandler(MMIOT *f, int tickchar, int minticks, spanhandler spanner)
1081
1181
  return 0;
1082
1182
  }
1083
1183
 
1084
- #define tag_text(f) (f->flags & INSIDE_TAG)
1184
+ #define tag_text(f) (f->flags & MKD_TAGTEXT)
1085
1185
 
1086
1186
 
1087
1187
  static void
@@ -1092,7 +1192,7 @@ text(MMIOT *f)
1092
1192
  int smartyflags = 0;
1093
1193
 
1094
1194
  while (1) {
1095
- if ( (f->flags & AUTOLINK) && isalpha(peek(f,1)) && !tag_text(f) )
1195
+ if ( (f->flags & MKD_AUTOLINK) && isalpha(peek(f,1)) && !tag_text(f) )
1096
1196
  maybe_autolink(f);
1097
1197
 
1098
1198
  c = pull(f);
@@ -1131,32 +1231,48 @@ text(MMIOT *f)
1131
1231
  case '[': if ( tag_text(f) || !linkylinky(0, f) )
1132
1232
  Qchar(c, f);
1133
1233
  break;
1134
- #if SUPERSCRIPT
1135
1234
  /* A^B -> A<sup>B</sup> */
1136
- case '^': if ( (f->flags & (STRICT|INSIDE_TAG)) || isthisspace(f,-1) || isthisspace(f,1) )
1235
+ case '^': if ( (f->flags & (MKD_NOSUPERSCRIPT|MKD_STRICT|MKD_TAGTEXT))
1236
+ || (isthisnonword(f,-1) && peek(f,-1) != ')')
1237
+ || isthisspace(f,1) )
1137
1238
  Qchar(c,f);
1138
1239
  else {
1139
1240
  char *sup = cursor(f);
1140
1241
  int len = 0;
1141
- Qstring("<sup>",f);
1142
- while ( !isthisspace(f,1+len) ) {
1143
- ++len;
1242
+
1243
+ if ( peek(f,1) == '(' ) {
1244
+ int here = mmiottell(f);
1245
+ pull(f);
1246
+
1247
+ if ( (len = parenthetical('(',')',f)) <= 0 ) {
1248
+ mmiotseek(f,here);
1249
+ Qchar(c, f);
1250
+ break;
1251
+ }
1252
+ sup++;
1144
1253
  }
1145
- shift(f,len);
1254
+ else {
1255
+ while ( isthisalnum(f,1+len) )
1256
+ ++len;
1257
+ if ( !len ) {
1258
+ Qchar(c,f);
1259
+ break;
1260
+ }
1261
+ shift(f,len);
1262
+ }
1263
+ Qstring("<sup>",f);
1146
1264
  ___mkd_reparse(sup, len, 0, f);
1147
1265
  Qstring("</sup>", f);
1148
1266
  }
1149
1267
  break;
1150
- #endif
1151
1268
  case '_':
1152
- #if RELAXED_EMPHASIS
1153
1269
  /* Underscores don't count if they're in the middle of a word */
1154
- if ( !(f->flags & STRICT) && isthisalnum(f,-1)
1155
- && isthisalnum(f,1) ) {
1270
+ if ( !(f->flags & (MKD_NORELAXED|MKD_STRICT))
1271
+ && isthisalnum(f,-1)
1272
+ && isthisalnum(f,1) ) {
1156
1273
  Qchar(c, f);
1157
1274
  break;
1158
1275
  }
1159
- #endif
1160
1276
  case '*':
1161
1277
  /* Underscores & stars don't count if they're out in the middle
1162
1278
  * of whitespace */
@@ -1174,7 +1290,7 @@ text(MMIOT *f)
1174
1290
  }
1175
1291
  break;
1176
1292
 
1177
- case '~': if ( (f->flags & (NOSTRIKETHROUGH|INSIDE_TAG|STRICT)) || !tickhandler(f,c,2,delspan) )
1293
+ case '~': if ( (f->flags & (MKD_NOSTRIKETHROUGH|MKD_TAGTEXT|MKD_STRICT)) || !tickhandler(f,c,2,delspan) )
1178
1294
  Qchar(c, f);
1179
1295
  break;
1180
1296
 
@@ -1187,6 +1303,14 @@ text(MMIOT *f)
1187
1303
  break;
1188
1304
  case '<': Qstring("&lt;", f);
1189
1305
  break;
1306
+ case '^': if ( f->flags & (MKD_STRICT|MKD_NOSUPERSCRIPT) ) {
1307
+ Qchar('\\', f);
1308
+ shift(f,-1);
1309
+ break;
1310
+ }
1311
+ Qchar(c, f);
1312
+ break;
1313
+
1190
1314
  case '>': case '#': case '.': case '-':
1191
1315
  case '+': case '{': case '}': case ']':
1192
1316
  case '!': case '[': case '*': case '_':
@@ -1229,13 +1353,14 @@ text(MMIOT *f)
1229
1353
  static void
1230
1354
  printheader(Paragraph *pp, MMIOT *f)
1231
1355
  {
1232
- Qprintf(f, "<h%d", pp->hnumber);
1233
- if ( f->flags & TOC ) {
1234
- Qprintf(f, " id=\"", pp->hnumber);
1235
- mkd_string_to_anchor(T(pp->text->text), S(pp->text->text), Qchar, f);
1236
- Qchar('"', f);
1356
+ if ( f->flags & MKD_TOC ) {
1357
+ Qstring("<a name=\"", f);
1358
+ mkd_string_to_anchor(T(pp->text->text),
1359
+ S(pp->text->text),
1360
+ (mkd_sta_function_t)Qchar, f, 1);
1361
+ Qstring("\"></a>\n", f);
1237
1362
  }
1238
- Qchar('>', f);
1363
+ Qprintf(f, "<h%d>", pp->hnumber);
1239
1364
  push(T(pp->text->text), S(pp->text->text), f);
1240
1365
  text(f);
1241
1366
  Qprintf(f, "</h%d>", pp->hnumber);
@@ -1432,7 +1557,6 @@ htmlify(Paragraph *p, char *block, char *arguments, MMIOT *f)
1432
1557
  }
1433
1558
 
1434
1559
 
1435
- #if DL_TAG_EXTENSION
1436
1560
  static void
1437
1561
  definitionlist(Paragraph *p, MMIOT *f)
1438
1562
  {
@@ -1455,7 +1579,6 @@ definitionlist(Paragraph *p, MMIOT *f)
1455
1579
  Qstring("</dl>", f);
1456
1580
  }
1457
1581
  }
1458
- #endif
1459
1582
 
1460
1583
 
1461
1584
  static void
@@ -1464,7 +1587,7 @@ listdisplay(int typ, Paragraph *p, MMIOT* f)
1464
1587
  if ( p ) {
1465
1588
  Qprintf(f, "<%cl", (typ==UL)?'u':'o');
1466
1589
  if ( typ == AL )
1467
- Qprintf(f, " type=a");
1590
+ Qprintf(f, " type=\"a\"");
1468
1591
  Qprintf(f, ">\n");
1469
1592
 
1470
1593
  for ( ; p ; p = p->next ) {
@@ -1507,11 +1630,9 @@ display(Paragraph *p, MMIOT *f)
1507
1630
  listdisplay(p->typ, p->down, f);
1508
1631
  break;
1509
1632
 
1510
- #if DL_TAG_EXTENSION
1511
1633
  case DL:
1512
1634
  definitionlist(p->down, f);
1513
1635
  break;
1514
- #endif
1515
1636
 
1516
1637
  case HR:
1517
1638
  Qstring("<hr />", f);
@@ -1537,20 +1658,59 @@ display(Paragraph *p, MMIOT *f)
1537
1658
  }
1538
1659
 
1539
1660
 
1661
+ /* dump out a list of footnotes
1662
+ */
1663
+ static void
1664
+ mkd_extra_footnotes(MMIOT *m)
1665
+ {
1666
+ int j, i;
1667
+ Footnote *t;
1668
+
1669
+ if ( m->reference == 0 )
1670
+ return;
1671
+
1672
+ Csprintf(&m->out, "\n<div class=\"footnotes\">\n<hr/>\n<ol>\n");
1673
+
1674
+ for ( i=1; i <= m->reference; i++ ) {
1675
+ for ( j=0; j < S(*m->footnotes); j++ ) {
1676
+ t = &T(*m->footnotes)[j];
1677
+ if ( (t->refnumber == i) && (t->flags & REFERENCED) ) {
1678
+ Csprintf(&m->out, "<li id=\"%s:%d\">\n<p>",
1679
+ p_or_nothing(m), t->refnumber);
1680
+ Csreparse(&m->out, T(t->title), S(t->title), 0);
1681
+ Csprintf(&m->out, "<a href=\"#%sref:%d\" rev=\"footnote\">&#8617;</a>",
1682
+ p_or_nothing(m), t->refnumber);
1683
+ Csprintf(&m->out, "</p></li>\n");
1684
+ }
1685
+ }
1686
+ }
1687
+ Csprintf(&m->out, "</ol>\n</div>\n");
1688
+ }
1689
+
1690
+
1540
1691
  /* return a pointer to the compiled markdown
1541
1692
  * document.
1542
1693
  */
1543
1694
  int
1544
1695
  mkd_document(Document *p, char **res)
1545
1696
  {
1697
+ int size;
1698
+
1546
1699
  if ( p && p->compiled ) {
1547
1700
  if ( ! p->html ) {
1548
1701
  htmlify(p->code, 0, 0, p->ctx);
1702
+ if ( p->ctx->flags & MKD_EXTRA_FOOTNOTE )
1703
+ mkd_extra_footnotes(p->ctx);
1549
1704
  p->html = 1;
1550
1705
  }
1551
1706
 
1707
+ size = S(p->ctx->out);
1708
+
1709
+ if ( (size == 0) || T(p->ctx->out)[size-1] )
1710
+ EXPAND(p->ctx->out) = 0;
1711
+
1552
1712
  *res = T(p->ctx->out);
1553
- return S(p->ctx->out);
1713
+ return size;
1554
1714
  }
1555
1715
  return EOF;
1556
1716
  }