rpeg-markdown 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. data/README +25 -1
  2. data/Rakefile +85 -16
  3. data/ext/extconf.h +3 -0
  4. data/ext/extconf.rb +13 -2
  5. data/ext/markdown.c +27 -71
  6. data/ext/markdown_lib.c +181 -0
  7. data/ext/markdown_lib.h +19 -0
  8. data/ext/markdown_output.c +313 -327
  9. data/ext/markdown_parser.c +2817 -2920
  10. data/ext/markdown_peg.h +10 -24
  11. data/ext/parsing_functions.c +104 -0
  12. data/ext/utility_functions.c +220 -0
  13. data/lib/markdown.rb +22 -2
  14. data/test/MarkdownTest_1.0/MarkdownTest.pl +157 -0
  15. data/test/MarkdownTest_1.0/Tests/Amps and angle encoding.html +17 -0
  16. data/test/MarkdownTest_1.0/Tests/Amps and angle encoding.text +21 -0
  17. data/test/MarkdownTest_1.0/Tests/Auto links.html +18 -0
  18. data/test/MarkdownTest_1.0/Tests/Auto links.text +13 -0
  19. data/test/MarkdownTest_1.0/Tests/Backslash escapes.html +102 -0
  20. data/test/MarkdownTest_1.0/Tests/Backslash escapes.text +104 -0
  21. data/test/MarkdownTest_1.0/Tests/Blockquotes with code blocks.html +15 -0
  22. data/test/MarkdownTest_1.0/Tests/Blockquotes with code blocks.text +11 -0
  23. data/test/MarkdownTest_1.0/Tests/Hard-wrapped paragraphs with list-like lines.html +8 -0
  24. data/test/MarkdownTest_1.0/Tests/Hard-wrapped paragraphs with list-like lines.text +8 -0
  25. data/test/MarkdownTest_1.0/Tests/Horizontal rules.html +71 -0
  26. data/test/MarkdownTest_1.0/Tests/Horizontal rules.text +67 -0
  27. data/test/MarkdownTest_1.0/Tests/Inline HTML (Advanced).html +14 -0
  28. data/test/MarkdownTest_1.0/Tests/Inline HTML (Advanced).text +14 -0
  29. data/test/MarkdownTest_1.0/Tests/Inline HTML (Simple).html +72 -0
  30. data/test/MarkdownTest_1.0/Tests/Inline HTML (Simple).text +69 -0
  31. data/test/MarkdownTest_1.0/Tests/Inline HTML comments.html +13 -0
  32. data/test/MarkdownTest_1.0/Tests/Inline HTML comments.text +13 -0
  33. data/test/MarkdownTest_1.0/Tests/Links, inline style.html +9 -0
  34. data/test/MarkdownTest_1.0/Tests/Links, inline style.text +9 -0
  35. data/test/MarkdownTest_1.0/Tests/Links, reference style.html +18 -0
  36. data/test/MarkdownTest_1.0/Tests/Links, reference style.text +31 -0
  37. data/test/MarkdownTest_1.0/Tests/Literal quotes in titles.html +3 -0
  38. data/test/MarkdownTest_1.0/Tests/Literal quotes in titles.text +7 -0
  39. data/test/MarkdownTest_1.0/Tests/Markdown Documentation - Basics.html +314 -0
  40. data/test/MarkdownTest_1.0/Tests/Markdown Documentation - Basics.text +306 -0
  41. data/test/MarkdownTest_1.0/Tests/Markdown Documentation - Syntax.html +942 -0
  42. data/test/MarkdownTest_1.0/Tests/Markdown Documentation - Syntax.text +888 -0
  43. data/test/MarkdownTest_1.0/Tests/Nested blockquotes.html +9 -0
  44. data/test/MarkdownTest_1.0/Tests/Nested blockquotes.text +5 -0
  45. data/test/MarkdownTest_1.0/Tests/Ordered and unordered lists.html +137 -0
  46. data/test/MarkdownTest_1.0/Tests/Ordered and unordered lists.text +122 -0
  47. data/test/MarkdownTest_1.0/Tests/Strong and em together.html +7 -0
  48. data/test/MarkdownTest_1.0/Tests/Strong and em together.text +7 -0
  49. data/test/MarkdownTest_1.0/Tests/Tabs.html +25 -0
  50. data/test/MarkdownTest_1.0/Tests/Tabs.text +21 -0
  51. data/test/MarkdownTest_1.0/Tests/Tidyness.html +8 -0
  52. data/test/MarkdownTest_1.0/Tests/Tidyness.text +5 -0
  53. data/test/MarkdownTest_1.0.3/MarkdownTest.pl +176 -0
  54. data/test/MarkdownTest_1.0.3/Tests/Amps and angle encoding.html +17 -0
  55. data/test/MarkdownTest_1.0.3/Tests/Amps and angle encoding.text +21 -0
  56. data/test/MarkdownTest_1.0.3/Tests/Auto links.html +18 -0
  57. data/test/MarkdownTest_1.0.3/Tests/Auto links.text +13 -0
  58. data/test/MarkdownTest_1.0.3/Tests/Backslash escapes.html +118 -0
  59. data/test/MarkdownTest_1.0.3/Tests/Backslash escapes.text +120 -0
  60. data/test/MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.html +15 -0
  61. data/test/MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.text +11 -0
  62. data/test/MarkdownTest_1.0.3/Tests/Code Blocks.html +18 -0
  63. data/test/MarkdownTest_1.0.3/Tests/Code Blocks.text +14 -0
  64. data/test/MarkdownTest_1.0.3/Tests/Code Spans.html +6 -0
  65. data/test/MarkdownTest_1.0.3/Tests/Code Spans.text +6 -0
  66. data/test/MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.html +8 -0
  67. data/test/MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.text +8 -0
  68. data/test/MarkdownTest_1.0.3/Tests/Horizontal rules.html +71 -0
  69. data/test/MarkdownTest_1.0.3/Tests/Horizontal rules.text +67 -0
  70. data/test/MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).html +15 -0
  71. data/test/MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).text +15 -0
  72. data/test/MarkdownTest_1.0.3/Tests/Inline HTML (Simple).html +72 -0
  73. data/test/MarkdownTest_1.0.3/Tests/Inline HTML (Simple).text +69 -0
  74. data/test/MarkdownTest_1.0.3/Tests/Inline HTML comments.html +13 -0
  75. data/test/MarkdownTest_1.0.3/Tests/Inline HTML comments.text +13 -0
  76. data/test/MarkdownTest_1.0.3/Tests/Links, inline style.html +11 -0
  77. data/test/MarkdownTest_1.0.3/Tests/Links, inline style.text +12 -0
  78. data/test/MarkdownTest_1.0.3/Tests/Links, reference style.html +52 -0
  79. data/test/MarkdownTest_1.0.3/Tests/Links, reference style.text +71 -0
  80. data/test/MarkdownTest_1.0.3/Tests/Links, shortcut references.html +9 -0
  81. data/test/MarkdownTest_1.0.3/Tests/Links, shortcut references.text +20 -0
  82. data/test/MarkdownTest_1.0.3/Tests/Literal quotes in titles.html +3 -0
  83. data/test/MarkdownTest_1.0.3/Tests/Literal quotes in titles.text +7 -0
  84. data/test/MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.html +314 -0
  85. data/test/MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.text +306 -0
  86. data/test/MarkdownTest_1.0.3/Tests/Markdown Documentation - Syntax.html +942 -0
  87. data/test/MarkdownTest_1.0.3/Tests/Markdown Documentation - Syntax.text +888 -0
  88. data/test/MarkdownTest_1.0.3/Tests/Nested blockquotes.html +9 -0
  89. data/test/MarkdownTest_1.0.3/Tests/Nested blockquotes.text +5 -0
  90. data/test/MarkdownTest_1.0.3/Tests/Ordered and unordered lists.html +148 -0
  91. data/test/MarkdownTest_1.0.3/Tests/Ordered and unordered lists.text +131 -0
  92. data/test/MarkdownTest_1.0.3/Tests/Strong and em together.html +7 -0
  93. data/test/MarkdownTest_1.0.3/Tests/Strong and em together.text +7 -0
  94. data/test/MarkdownTest_1.0.3/Tests/Tabs.html +25 -0
  95. data/test/MarkdownTest_1.0.3/Tests/Tabs.text +21 -0
  96. data/test/MarkdownTest_1.0.3/Tests/Tidyness.html +8 -0
  97. data/test/MarkdownTest_1.0.3/Tests/Tidyness.text +5 -0
  98. data/test/benchmark.rb +49 -0
  99. data/test/markdown_test.rb +78 -0
  100. metadata +96 -6
  101. data/ext/markdown_buffer.c +0 -46
  102. data/ext/markdown_buffer.h +0 -6
  103. data/test.rb +0 -25
data/README CHANGED
@@ -7,7 +7,31 @@ Markdown (see [peg-markdown][1]) in a Ruby extension.
7
7
  [1]: http://github.com/jgm/peg-markdown/
8
8
  "Jon MacFarleane's peg-markdown project"
9
9
 
10
- ### COPYING
10
+ Installation/Hacking
11
+ --------------------
12
+
13
+ This library requires a recent version of glib2.
14
+
15
+ The rpeg-markdown gem is available from Rubyforge:
16
+
17
+ $ sudo gem install rpeg-markdown
18
+
19
+ A Git repository is available for hacking:
20
+
21
+ $ git clone git://github.com/rtomayko/rpeg-markdown.git
22
+ $ cd rpeg-markdown
23
+ $ rake test
24
+
25
+ Patches happily accepted via fork or email.
26
+
27
+ Changes
28
+ -------
29
+
30
+ 0.2.0 / 2008-07-12 - Adds test suite and plugs all memory leaks.
31
+ 0.1.0 / 2008-05-30 - Initial release.
32
+
33
+ COPYING
34
+ -------
11
35
 
12
36
  The peg-markdown sources are licensed under the GPL and the Ruby extension
13
37
  sources adopts this license. See the file LICENSE included with this
data/Rakefile CHANGED
@@ -2,21 +2,28 @@ require 'rake/clean'
2
2
  require 'rake/packagetask'
3
3
  require 'rake/gempackagetask'
4
4
 
5
+ task :default => :test
6
+
5
7
  DLEXT = Config::CONFIG['DLEXT']
6
- VERS = '0.1.0'
8
+ VERS = '0.2.0'
7
9
 
8
10
  spec =
9
11
  Gem::Specification.new do |s|
10
12
  s.name = "rpeg-markdown"
11
13
  s.version = VERS
12
14
  s.summary = "Ruby extension library for peg-markdown"
13
- s.files = FileList['README','LICENSE','Rakefile','test.rb','{lib,ext}/**.rb','ext/*.{c,h}','bin/rpeg-markdown']
15
+ s.files = FileList[
16
+ 'README','LICENSE','Rakefile',
17
+ '{lib,ext,test}/**.rb','ext/*.{c,h}',
18
+ 'test/MarkdownTest*/**/*',
19
+ 'bin/rpeg-markdown'
20
+ ]
14
21
  s.bindir = 'bin'
15
22
  s.executables << 'rpeg-markdown'
16
23
  s.require_path = 'lib'
17
24
  s.has_rdoc = true
18
25
  s.extra_rdoc_files = ['README', 'LICENSE']
19
- s.test_files = Dir['test.rb']
26
+ s.test_files = FileList['test/markdown_test.rb']
20
27
  s.extensions = ['ext/extconf.rb']
21
28
 
22
29
  s.author = 'Ryan Tomayko'
@@ -42,19 +49,29 @@ namespace :submodule do
42
49
  end
43
50
  end
44
51
 
52
+ desc 'Update the peg-markdown submodule'
45
53
  task :update => :init do
46
- sh 'git submodule update peg-markdown'
54
+ sh 'git submodule update peg-markdown' unless File.symlink?('peg-markdown')
55
+ end
56
+
57
+ file 'peg-markdown/markdown.c' do
58
+ Rake::Task['submodule:init'].invoke
47
59
  end
60
+ task :exist => 'peg-markdown/markdown.c'
48
61
  end
49
62
 
50
63
  desc 'Gather required peg-markdown sources into extension directory'
51
- task :gather => 'submodule:update' do |t|
64
+ task :gather => 'submodule:exist' do |t|
52
65
  sh 'cd peg-markdown && make markdown_parser.c'
53
- cp FileList['peg-markdown/markdown_{peg.h,parser.c,output.c}'], 'ext/',
66
+ files =
67
+ FileList[
68
+ 'peg-markdown/markdown_{peg.h,parser.c,output.c,lib.c,lib.h}',
69
+ 'peg-markdown/{utility,parsing}_functions.c'
70
+ ]
71
+ cp files, 'ext/',
54
72
  :preserve => true,
55
73
  :verbose => true
56
74
  end
57
- CLOBBER.include 'ext/markdown_{peg.h,parser.c,output.c}'
58
75
 
59
76
  file 'ext/Makefile' => FileList['ext/{extconf.rb,*.c,*.h,*.rb}'] do
60
77
  chdir('ext') { ruby 'extconf.rb' }
@@ -73,24 +90,76 @@ end
73
90
  desc 'Build the peg-markdown extension'
74
91
  task :build => "lib/markdown.#{DLEXT}"
75
92
 
76
- task 'test:unit' => [ :build ] do |t|
77
- ruby 'test.rb'
93
+ desc 'Run unit and conformance tests'
94
+ task :test => [ 'test:unit', 'test:conformance' ]
95
+
96
+ desc 'Run unit tests'
97
+ task 'test:unit' => [:build] do |t|
98
+ ruby 'test/markdown_test.rb'
78
99
  end
79
100
 
80
- task 'test:conformance' => [ 'submodule:update', :build ] do |t|
81
- chdir('peg-markdown/MarkdownTest_1.0.3') do
82
- sh "./MarkdownTest.pl --script=../../bin/rpeg-markdown --tidy"
101
+ desc 'Run conformance tests (MARKDOWN_TEST_VER=1.0)'
102
+ task 'test:conformance' => [:build] do |t|
103
+ script = "#{pwd}/bin/rpeg-markdown"
104
+ test_version = ENV['MARKDOWN_TEST_VER'] || '1.0'
105
+ chdir("test/MarkdownTest_#{test_version}") do
106
+ sh "./MarkdownTest.pl --script='#{script}' --tidy"
83
107
  end
84
108
  end
85
109
 
110
+ desc 'Run version 1.0 conformance suite'
111
+ task 'test:conformance:1.0' => 'test:conformance'
112
+
113
+ desc 'Run 1.0.3 conformance suite'
114
+ task 'test:conformance:1.0.3' => [:build] do |t|
115
+ ENV['MARKDOWN_TEST_VER'] = '1.0.3'
116
+ Rake::Task['test:conformance'].invoke
117
+ end
118
+
119
+ desc 'Run unit and conformance tests'
120
+ task :test => %w[test:unit test:conformance]
86
121
 
122
+ desc 'Run benchmarks'
123
+ task :benchmark => :build do |t|
124
+ $:.unshift 'lib'
125
+ load 'test/benchmark.rb'
126
+ end
127
+
128
+ desc "See how much memory we're losing"
129
+ task 'test:mem' => %w[submodule:exist build] do |t|
130
+ $: << File.join(File.dirname(__FILE__), "lib")
131
+ require 'markdown'
132
+ FileList['test.txt', 'peg-markdown/MarkdownTest_1.0.3/Tests/*.text'].each do |file|
133
+ printf "%s: \n", file
134
+ markdown = Markdown.new(File.read(file))
135
+ iterations = (ENV['N'] || 100).to_i
136
+ total, growth = [], []
137
+ iterations.times do |i|
138
+ start = Time.now
139
+ GC.start
140
+ markdown.to_html
141
+ duration = Time.now - start
142
+ GC.start
143
+ total << `ps -o rss= -p #{Process.pid}`.to_i
144
+ next if i == 0
145
+ growth << (total.last - (total[-2] || 0))
146
+ # puts "%03d: %06.02f ms / %dK used / %dK growth" % [ i, duration, total.last, growth.last ]
147
+ end
148
+ average = growth.inject(0) { |sum,x| sum + x } / growth.length
149
+ printf " %dK avg growth (per run) / %dK used (after %d runs)\n", average, total.last, iterations
150
+ end
151
+ end
87
152
 
88
153
  # ==========================================================
89
154
  # Rubyforge
90
155
  # ==========================================================
91
156
 
92
- task 'release' => [ "pkg/rpeg-markdown-#{VERS}.gem", "pkg/rpeg-markdown-#{VERS}.tar.gz" ] do |t|
93
- # "pkg/rpeg-markdown-#{VERS}.gem",
94
- # "pkg/rpeg-markdown-#{VERS}.tar.gz"
95
- sh "rubyforge add_release wink rpeg-markdown #{VERS} pkg/rpeg-markdown-#{VERS}.gem"
157
+ PKGNAME = "pkg/rpeg-markdown-#{VERS}"
158
+
159
+ desc 'Publish new release to rubyforge'
160
+ task :release => [ "#{PKGNAME}.gem", "#{PKGNAME}.tar.gz" ] do |t|
161
+ sh <<-end
162
+ rubyforge add_release wink rpeg-markdown #{VERS} #{PKGNAME}.gem &&
163
+ rubyforge add_file wink rpeg-markdown #{VERS} #{PKGNAME}.tar.gz
164
+ end
96
165
  end
data/ext/extconf.h ADDED
@@ -0,0 +1,3 @@
1
+ #ifndef EXTCONF_H
2
+ #define EXTCONF_H
3
+ #endif
data/ext/extconf.rb CHANGED
@@ -1,6 +1,17 @@
1
1
  require 'mkmf'
2
2
 
3
- $CFLAGS = "-Wall"
4
-
5
3
  dir_config('markdown')
4
+
5
+ require 'pp'
6
+
7
+ $objs = %w[markdown.o markdown_lib.o markdown_output.o markdown_parser.o]
8
+
9
+ if pkg_config = find_executable('pkg-config')
10
+ $CFLAGS = `#{pkg_config} --cflags glib-2.0`
11
+ $LDFLAGS = `#{pkg_config} --libs glib-2.0`
12
+ else
13
+ fail "glib2 not found"
14
+ end
15
+
16
+ create_header
6
17
  create_makefile('markdown')
data/ext/markdown.c CHANGED
@@ -1,6 +1,5 @@
1
1
  #include "ruby.h"
2
- #include "markdown_peg.h"
3
- #include "markdown_buffer.h"
2
+ #include "markdown_lib.h"
4
3
 
5
4
  static VALUE rb_cMarkdown;
6
5
 
@@ -12,79 +11,36 @@ static ID id_notes;
12
11
  #define INCREMENT 4096 /* size of chunks in which to allocate memory */
13
12
 
14
13
  static VALUE
15
- markdown_to_html(VALUE self)
14
+ rb_markdown_to_html(int argc, VALUE *argv, VALUE self)
16
15
  {
17
- element parsed_input;
18
- VALUE output_buffer;
19
-
20
- char *inputbuf, *curchar;
21
- int charstotab, buflength, maxlength;
22
-
23
- /* grab char pointer to markdown input text */
24
- VALUE text = rb_funcall(self, id_text, 0);
25
- Check_Type(text, T_STRING);
26
- char * ptext = StringValuePtr(text);
27
-
28
- buflength = 0;
29
- maxlength = RSTRING(text)->len >= INCREMENT ?
30
- RSTRING(text)->len :
31
- INCREMENT;
32
- inputbuf = malloc(maxlength);
33
- curchar = inputbuf;
34
-
35
- charstotab = TABSTOP;
36
- while ((*curchar = *ptext++) != '\0') {
37
- switch (*curchar) {
38
- case '\t':
39
- while (charstotab > 0)
40
- *curchar = ' ', curchar++, buflength++, charstotab--;
41
- break;
42
- case '\n':
43
- curchar++, buflength++, charstotab = TABSTOP;
44
- break;
45
- default:
46
- curchar++, buflength++, charstotab--;
47
- }
48
- if (charstotab == 0)
49
- charstotab = TABSTOP;
50
- if (buflength > maxlength - TABSTOP - 3) {
51
- maxlength += INCREMENT;
52
- inputbuf = realloc(inputbuf, maxlength);
53
- curchar = inputbuf + buflength;
54
- if (inputbuf == NULL) {
55
- /* TODO: no memory */
56
- }
57
- }
58
- }
59
- *curchar++ = '\n';
60
- *curchar++ = '\n';
61
- *curchar = '\0';
62
- buflength+= 2;
63
-
64
- /* flip extension bits */
65
- int extensions = 0;
66
- if ( rb_funcall(self, id_smart, 0) == Qtrue )
67
- extensions = extensions | EXT_SMART ;
68
- if ( rb_funcall(self, id_notes, 0) == Qtrue )
69
- extensions = extensions | EXT_NOTES ;
70
-
71
- /* parse markdown input into sematic element tree */
72
- parsed_input = markdown(inputbuf, extensions);
73
-
74
- /* allocate output buffer and generate output */
75
- output_buffer = rb_markdown_buffer_init(buflength * 2);
76
- print_element(parsed_input, HTML_FORMAT);
77
- rb_markdown_buffer_free();
78
- return output_buffer;
16
+ /* grab char pointer to markdown input text */
17
+ VALUE text = rb_funcall(self, id_text, 0);
18
+ Check_Type(text, T_STRING);
19
+ char * ptext = StringValuePtr(text);
20
+
21
+ /* flip extension bits */
22
+ int extensions = 0;
23
+ if ( rb_funcall(self, id_smart, 0) == Qtrue )
24
+ extensions = extensions | EXT_SMART ;
25
+ if ( rb_funcall(self, id_notes, 0) == Qtrue )
26
+ extensions = extensions | EXT_NOTES ;
27
+
28
+ char *html = markdown_to_string(ptext, extensions, HTML_FORMAT);
29
+ VALUE result = rb_str_new2(html);
30
+ free(html);
31
+
32
+ return result;
79
33
  }
80
34
 
81
35
  void Init_markdown()
82
36
  {
83
- /* Initialize frequently used Symbols */
84
- id_text = rb_intern("text");
85
- id_smart = rb_intern("smart");
86
- id_notes = rb_intern("notes");
37
+ /* Initialize frequently used Symbols */
38
+ id_text = rb_intern("text");
39
+ id_smart = rb_intern("smart");
40
+ id_notes = rb_intern("notes");
87
41
 
88
- rb_cMarkdown = rb_define_class("Markdown", rb_cObject);
89
- rb_define_method(rb_cMarkdown, "to_html", markdown_to_html, 0);
42
+ rb_cMarkdown = rb_define_class("Markdown", rb_cObject);
43
+ rb_define_method(rb_cMarkdown, "to_html", rb_markdown_to_html, -1);
90
44
  }
45
+
46
+ // vim: ts=4 sw=4
@@ -0,0 +1,181 @@
1
+ /**********************************************************************
2
+
3
+ markdown_lib.c - markdown in C using a PEG grammar.
4
+ (c) 2008 John MacFarlane (jgm at berkeley dot edu).
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; version 2 of the License.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ ***********************************************************************/
16
+
17
+ #include <stdio.h>
18
+ #include <stdlib.h>
19
+ #include <string.h>
20
+ #include "markdown_peg.h"
21
+
22
+ #define TABSTOP 4
23
+
24
+ /* preformat_text - allocate and copy text buffer while
25
+ * performing tab expansion. */
26
+ static GString *preformat_text(char *text) {
27
+ GString *buf;
28
+ char next_char;
29
+ int charstotab;
30
+
31
+ int len = 0;
32
+
33
+ buf = g_string_new("");
34
+
35
+ charstotab = TABSTOP;
36
+ while ((next_char = *text++) != '\0') {
37
+ switch (next_char) {
38
+ case '\t':
39
+ while (charstotab > 0)
40
+ g_string_append_c(buf, ' '), len++, charstotab--;
41
+ break;
42
+ case '\n':
43
+ g_string_append_c(buf, '\n'), len++, charstotab = TABSTOP;
44
+ break;
45
+ default:
46
+ g_string_append_c(buf, next_char), len++, charstotab--;
47
+ }
48
+ if (charstotab == 0)
49
+ charstotab = TABSTOP;
50
+ }
51
+ g_string_append(buf, "\n\n");
52
+ return(buf);
53
+ }
54
+
55
+ /* print_tree - print tree of elements, for debugging only. */
56
+ static void print_tree(element * elt, int indent) {
57
+ int i;
58
+ char * key;
59
+ while (elt != NULL) {
60
+ for (i = 0; i < indent; i++)
61
+ fputc(' ', stderr);
62
+ switch (elt->key) {
63
+ case LIST: key = "LIST"; break;
64
+ case RAW: key = "RAW"; break;
65
+ case SPACE: key = "SPACE"; break;
66
+ case LINEBREAK: key = "LINEBREAK"; break;
67
+ case ELLIPSIS: key = "ELLIPSIS"; break;
68
+ case EMDASH: key = "EMDASH"; break;
69
+ case ENDASH: key = "ENDASH"; break;
70
+ case APOSTROPHE: key = "APOSTROPHE"; break;
71
+ case SINGLEQUOTED: key = "SINGLEQUOTED"; break;
72
+ case DOUBLEQUOTED: key = "DOUBLEQUOTED"; break;
73
+ case STR: key = "STR"; break;
74
+ case LINK: key = "LINK"; break;
75
+ case IMAGE: key = "IMAGE"; break;
76
+ case CODE: key = "CODE"; break;
77
+ case HTML: key = "HTML"; break;
78
+ case EMPH: key = "EMPH"; break;
79
+ case STRONG: key = "STRONG"; break;
80
+ case PLAIN: key = "PLAIN"; break;
81
+ case PARA: key = "PARA"; break;
82
+ case LISTITEM: key = "LISTITEM"; break;
83
+ case BULLETLIST: key = "BULLETLIST"; break;
84
+ case ORDEREDLIST: key = "ORDEREDLIST"; break;
85
+ case H1: key = "H1"; break;
86
+ case H2: key = "H2"; break;
87
+ case H3: key = "H3"; break;
88
+ case H4: key = "H4"; break;
89
+ case H5: key = "H5"; break;
90
+ case H6: key = "H6"; break;
91
+ case BLOCKQUOTE: key = "BLOCKQUOTE"; break;
92
+ case VERBATIM: key = "VERBATIM"; break;
93
+ case HTMLBLOCK: key = "HTMLBLOCK"; break;
94
+ case HRULE: key = "HRULE"; break;
95
+ case REFERENCE: key = "REFERENCE"; break;
96
+ case NOTE: key = "NOTE"; break;
97
+ default: key = "?";
98
+ }
99
+ if ( elt->key == STR ) {
100
+ fprintf(stderr, "0x%x: %s '%s'\n", (int)elt, key, elt->contents.str);
101
+ } else {
102
+ fprintf(stderr, "0x%x: %s\n", (int)elt, key);
103
+ }
104
+ if (elt->children)
105
+ print_tree(elt->children, indent + 4);
106
+ elt = elt->next;
107
+ }
108
+ }
109
+
110
+ /* process_raw_blocks - traverses an element list, replacing any RAW elements with
111
+ * the result of parsing them as markdown text, and recursing into the children
112
+ * of parent elements. The result should be a tree of elements without any RAWs. */
113
+ static element * process_raw_blocks(element *input, int extensions, element *references, element *notes) {
114
+ element *current = NULL;
115
+ element *last_child = NULL;
116
+ char *contents;
117
+ current = input;
118
+
119
+ while (current != NULL) {
120
+ if (current->key == RAW) {
121
+ /* \001 is used to indicate boundaries between nested lists when there
122
+ * is no blank line. We split the string by \001 and parse
123
+ * each chunk separately. */
124
+ contents = strtok(current->contents.str, "\001");
125
+ current->key = LIST;
126
+ current->children = parse_markdown(contents, extensions, references, notes);
127
+ last_child = current->children;
128
+ while ((contents = strtok(NULL, "\001"))) {
129
+ while (last_child->next != NULL)
130
+ last_child = last_child->next;
131
+ last_child->next = parse_markdown(contents, extensions, references, notes);
132
+ }
133
+ free(current->contents.str);
134
+ current->contents.str = NULL;
135
+ }
136
+ if (current->children != NULL)
137
+ current->children = process_raw_blocks(current->children, extensions, references, notes);
138
+ current = current->next;
139
+ }
140
+ return input;
141
+ }
142
+
143
+ /* markdown_to_gstring - convert markdown text to the output format specified.
144
+ * Returns a GString, which must be freed after use using g_string_free(). */
145
+ GString * markdown_to_g_string(char *text, int extensions, int output_format) {
146
+ element *result;
147
+ element *references;
148
+ element *notes;
149
+ GString *formatted_text;
150
+ GString *out;
151
+ out = g_string_new("");
152
+
153
+ formatted_text = preformat_text(text);
154
+
155
+ references = parse_references(formatted_text->str, extensions);
156
+ notes = parse_notes(formatted_text->str, extensions, references);
157
+ result = parse_markdown(formatted_text->str, extensions, references, notes);
158
+
159
+ result = process_raw_blocks(result, extensions, references, notes);
160
+
161
+ g_string_free(formatted_text, TRUE);
162
+
163
+ print_element_list(out, result, output_format, extensions);
164
+
165
+ free_element_list(result);
166
+ free_element_list(references);
167
+ return out;
168
+ }
169
+
170
+ /* markdown_to_string - convert markdown text to the output format specified.
171
+ * Returns a null-terminated string, which must be freed after use. */
172
+ char * markdown_to_string(char *text, int extensions, int output_format) {
173
+ GString *out;
174
+ char *char_out;
175
+ out = markdown_to_g_string(text, extensions, output_format);
176
+ char_out = out->str;
177
+ g_string_free(out, FALSE);
178
+ return char_out;
179
+ }
180
+
181
+ /* vim:set ts=4 sw=4: */
@@ -0,0 +1,19 @@
1
+ #include <stdlib.h>
2
+ #include <stdio.h>
3
+ #include <glib.h>
4
+
5
+ enum markdown_extensions {
6
+ EXT_SMART = 1,
7
+ EXT_NOTES = 2
8
+ };
9
+
10
+ enum markdown_formats {
11
+ HTML_FORMAT,
12
+ LATEX_FORMAT,
13
+ GROFF_MM_FORMAT
14
+ };
15
+
16
+ GString * markdown_to_g_string(char *text, int extensions, int output_format);
17
+ char * markdown_to_string(char *text, int extensions, int output_format);
18
+
19
+ /* vim: set ts=4 sw=4 : */