rdiscount-2.2.7.3/ 0000755 0000041 0000041 00000000000 14571373162 013736 5 ustar www-data www-data rdiscount-2.2.7.3/README.markdown 0000644 0000041 0000041 00000004403 14571373162 016440 0 ustar www-data www-data Discount Markdown Processor for Ruby
====================================
[](https://github.com/davidfstr/rdiscount/actions/workflows/main.yml)
Discount is an implementation of John Gruber's Markdown markup language in C.
It implements all of the language described in [the markdown syntax document][1] and
passes the [Markdown 1.0 test suite][2].
CODE: `git clone git://github.com/davidfstr/rdiscount.git`
HOME:
DOCS:
BUGS:
Discount was developed by [David Loren Parsons][3].
The Ruby extension is maintained by [David Foster][4].
[1]: https://daringfireball.net/projects/markdown/syntax
[2]: https://daringfireball.net/projects/downloads/MarkdownTest_1.0.zip
[3]: https://www.pell.portland.or.us/~orc
[4]: https://github.com/davidfstr
INSTALL, HACKING
----------------
New releases of RDiscount are published to [RubyGems][]:
$ [sudo] gem install rdiscount
The RDiscount sources are available via Git:
$ git clone git://github.com/davidfstr/rdiscount.git
$ cd rdiscount
$ rake --tasks
See the file [BUILDING][] for hacking instructions.
[RubyGems]: https://rubygems.org/gems/rdiscount
[BUILDING]: https://github.com/davidfstr/rdiscount/blob/master/BUILDING
USAGE
-----
RDiscount implements the basic protocol popularized by RedCloth and adopted
by BlueCloth:
require 'rdiscount'
markdown = RDiscount.new("Hello World!")
puts markdown.to_html
Additional processing options can be turned on when creating the
RDiscount object:
markdown = RDiscount.new("Hello World!", :smart, :filter_html)
Inject RDiscount into your BlueCloth-using code by replacing your bluecloth
require statements with the following:
begin
require 'rdiscount'
BlueCloth = RDiscount
rescue LoadError
require 'bluecloth'
end
COPYING
-------
Discount is free software; it is released under a BSD-style license
that allows you to do as you wish with it as long as you don't attempt
to claim it as your own work. RDiscount adopts Discount's license
verbatim. See the file `COPYING` for more information.
rdiscount-2.2.7.3/bin/ 0000755 0000041 0000041 00000000000 14571373162 014506 5 ustar www-data www-data rdiscount-2.2.7.3/bin/rdiscount 0000755 0000041 0000041 00000001404 14571373162 016445 0 ustar www-data www-data #!/usr/bin/env ruby
#
# Usage: [env RDISCOUNT_EXTENSIONS=',...'] rdiscount [...]
# no or when is '-', read Markdown source text from standard input.
#
# Convert one or more Markdown files to HTML and write to standard output.
# With no or when is '-', read Markdown source text from
# standard input. Optionally, the RDISCOUNT_EXTENSIONS environment variable
# can specify a comma-separated list of extensions to enable in RDiscount.
#
if ARGV.include?('--help')
File.read(__FILE__).split("\n").grep(/^# /).each do |line|
puts line[2..-1]
end
exit 0
end
require 'rdiscount'
extensions = ENV['RDISCOUNT_EXTENSIONS'].to_s.split(',').map{ |key| key.to_sym }
STDOUT.write(RDiscount.new(ARGF.read, *extensions).to_html)
rdiscount-2.2.7.3/rdiscount.gemspec 0000644 0000041 0000041 00000003107 14571373162 017316 0 ustar www-data www-data Gem::Specification.new do |s|
s.name = 'rdiscount'
s.version = '2.2.7.3'
s.summary = "Fast Implementation of Gruber's Markdown in C"
s.email = 'david@dafoster.net'
s.homepage = 'http://dafoster.net/projects/rdiscount/'
s.authors = ["Ryan Tomayko", "David Loren Parsons", "Andrew White", "David Foster", "l33tname"]
s.license = "BSD-3-Clause"
# = MANIFEST =
s.files = %w[
BUILDING
CHANGELOG.md
COPYING
README.markdown
Rakefile
bin/rdiscount
discount
ext/Csio.c
ext/VERSION
ext/amalloc.c
ext/amalloc.h
ext/basename.c
ext/blocktags
ext/config.h
ext/css.c
ext/cstring.h
ext/docheader.c
ext/dumptree.c
ext/emmatch.c
ext/extconf.rb
ext/flags.c
ext/generate.c
ext/gethopt.c
ext/gethopt.h
ext/github_flavoured.c
ext/h1title.c
ext/html5.c
ext/markdown.c
ext/markdown.h
ext/mkdio.c
ext/mkdio.h
ext/mktags.c
ext/notspecial.c
ext/pgm_options.c
ext/pgm_options.h
ext/rdiscount.c
ext/resource.c
ext/setup.c
ext/tags.c
ext/tags.h
ext/toc.c
ext/version.c
ext/xml.c
ext/xmlpage.c
lib/markdown.rb
lib/rdiscount.rb
man/markdown.7
man/rdiscount.1
man/rdiscount.1.ronn
rdiscount.gemspec
test/benchmark.rb
test/benchmark.txt
test/markdown_test.rb
test/rdiscount_test.rb
]
# = MANIFEST =
s.test_files = ["test/markdown_test.rb", "test/rdiscount_test.rb"]
s.extra_rdoc_files = ["COPYING"]
s.extensions = ["ext/extconf.rb"]
s.executables = ["rdiscount"]
s.require_paths = ["lib"]
end
rdiscount-2.2.7.3/lib/ 0000755 0000041 0000041 00000000000 14571373162 014504 5 ustar www-data www-data rdiscount-2.2.7.3/lib/rdiscount.rb 0000644 0000041 0000041 00000007674 14571373162 017061 0 ustar www-data www-data # Discount is an implementation of John Gruber's Markdown markup
# language in C. It implements all of the language as described in
# {Markdown Syntax}[http://daringfireball.net/projects/markdown/syntax]
# and passes the Markdown 1.0 test suite. The RDiscount extension makes
# the Discount processor available via a Ruby C Extension library.
#
# == Usage
#
# RDiscount implements the basic protocol popularized by RedCloth and adopted
# by BlueCloth:
# require 'rdiscount'
# markdown = RDiscount.new("Hello World!")
# puts markdown.to_html
#
# == Replacing BlueCloth
#
# Inject RDiscount into your BlueCloth-using code by replacing your bluecloth
# require statements with the following:
# begin
# require 'rdiscount'
# BlueCloth = RDiscount
# rescue LoadError
# require 'bluecloth'
# end
#
class RDiscount
VERSION = '2.2.7.3'
# Original Markdown formatted text.
attr_reader :text
# Set true to have smarty-like quote translation performed.
attr_accessor :smart
# Do not output tags included in the source text.
attr_accessor :filter_styles
# Do not output any raw HTML included in the source text.
attr_accessor :filter_html
# RedCloth compatible line folding -- not used for Markdown but
# included for compatibility.
attr_accessor :fold_lines
# Enable php markdown extra-style footnotes
attr_accessor :footnotes
# Enable Table Of Contents generation
attr_accessor :generate_toc
# Do not process ![] and remove tags from the output.
attr_accessor :no_image
# Do not process [] and remove tags from the output.
attr_accessor :no_links
# Do not process tables
attr_accessor :no_tables
# Disable superscript and relaxed emphasis processing.
attr_accessor :strict
# Convert URL in links, even if they aren't encased in <>
attr_accessor :autolink
# Don't make hyperlinks from [][] links that have unknown URL types.
attr_accessor :safelink
# Do not process pseudo-protocols like [](id:name)
attr_accessor :no_pseudo_protocols
# Disable superscript processing.
attr_accessor :no_superscript
# Disable strikethrough processing.
attr_accessor :no_strikethrough
# Keep LaTeX inside $$ intact.
attr_accessor :latex
# Don't merge adjacent list into a single list.
attr_accessor :explicitlist
# Not documented: run in markdown 1 compat mode (only used for MarkdownTest1.0)
attr_accessor :md1compat
# Create a RDiscount Markdown processor. The +text+ argument
# should be a string containing Markdown text. Additional arguments may be
# supplied to set various processing options:
#
# * :smart - Enable SmartyPants processing.
# * :filter_styles - Do not output tags.
# * :filter_html - Do not output any raw HTML tags included in
# the source text.
# * :fold_lines - RedCloth compatible line folding (not used).
# * :footnotes - PHP markdown extra-style footnotes.
# * :generate_toc - Enable Table Of Contents generation
# * :no_image - Do not output any tags.
# * :no_links - Do not output any tags.
# * :no_tables - Do not output any tables.
# * :strict - Disable superscript and relaxed emphasis processing.
# * :autolink - Greedily urlify links.
# * :safelink - Do not make links for unknown URL types.
# * :no_pseudo_protocols - Do not process pseudo-protocols.
# * :no_superscript - Disable superscript processing.
# * :no_strikethrough - Disable strikethrough processing.
# * :latex - Keep LaTeX inside $$ intact.
# * :explicitlist - Don't merge adjacent list into a single list.
#
def initialize(text, *extensions)
@text = text
extensions.each { |e| send("#{e}=", true) }
end
end
Markdown = RDiscount unless defined? Markdown
require 'rdiscount.so'
rdiscount-2.2.7.3/lib/markdown.rb 0000644 0000041 0000041 00000000024 14571373162 016647 0 ustar www-data www-data require 'rdiscount'
rdiscount-2.2.7.3/test/ 0000755 0000041 0000041 00000000000 14571373162 014715 5 ustar www-data www-data rdiscount-2.2.7.3/test/rdiscount_test.rb 0000644 0000041 0000041 00000020722 14571373162 020316 0 ustar www-data www-data # encoding: utf-8
rootdir = File.dirname(File.dirname(__FILE__))
$LOAD_PATH.unshift "#{rootdir}/lib"
require 'test/unit'
require 'rdiscount'
class RDiscountTest < Test::Unit::TestCase
def test_that_version_looks_valid
if not (/^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$/) =~ RDiscount::VERSION
assert false, 'Expected RDiscount::VERSION to be a 3 or 4 component version string but found ' + RDiscount::VERSION.to_s
end
end
def test_that_discount_does_not_blow_up_with_weird_formatting_case
text = (<<-TEXT).gsub(/^ {4}/, '').rstrip
1. some text
1.
TEXT
RDiscount.new(text).to_html
end
def test_that_smart_converts_double_quotes_to_curly_quotes
rd = RDiscount.new(%("Quoted text"), :smart)
assert_equal %(“Quoted text”
\n), rd.to_html
end
def test_that_smart_converts_double_quotes_to_curly_quotes_before_a_heading
rd = RDiscount.new(%("Quoted text"\n\n# Heading), :smart)
assert_equal %(“Quoted text”
\n\nHeading \n), rd.to_html
end
def test_that_smart_converts_double_quotes_to_curly_quotes_after_a_heading
rd = RDiscount.new(%(# Heading\n\n"Quoted text"), :smart)
assert_equal %(Heading \n\n“Quoted text”
\n), rd.to_html
end
def test_that_smart_gives_ve_suffix_a_rsquo
rd = RDiscount.new("I've been meaning to tell you ..", :smart)
assert_equal "I’ve been meaning to tell you ..
\n", rd.to_html
end
def test_that_smart_gives_m_suffix_a_rsquo
rd = RDiscount.new("I'm not kidding", :smart)
assert_equal "I’m not kidding
\n", rd.to_html
end
def test_that_smart_gives_d_suffix_a_rsquo
rd = RDiscount.new("what'd you say?", :smart)
assert_equal "what’d you say?
\n", rd.to_html
end
def test_that_generate_toc_sets_toc_ids
rd = RDiscount.new("# Level 1\n\n## Level 2", :generate_toc)
assert rd.generate_toc
assert_equal %( \nLevel 1 \n\n \nLevel 2 \n), rd.to_html
end
def test_should_get_the_generated_toc
rd = RDiscount.new("# Level 1\n\n## Level 2", :generate_toc)
exp = %()
assert_equal exp, rd.toc_content.strip
end
def test_toc_should_escape_apostropes
rd = RDiscount.new("# A'B\n\n## C", :generate_toc)
exp = %()
assert_equal exp, rd.toc_content.strip
end
def test_toc_should_escape_question_marks
rd = RDiscount.new("# A?B\n\n## C", :generate_toc)
exp = %()
assert_equal exp, rd.toc_content.strip
end
if "".respond_to?(:encoding)
def test_should_return_string_in_same_encoding_as_input
input = "Yogācāra"
output = RDiscount.new(input).to_html
assert_equal input.encoding.name, output.encoding.name
end
end
def test_that_no_image_flag_works
rd = RDiscount.new(%( ), :no_image)
assert rd.to_html !~ / links), :no_links)
assert rd.to_html !~ /foobar baz
\n", rd.to_html
end
def test_that_autolink_flag_works
rd = RDiscount.new("http://github.com/davidfstr/rdiscount", :autolink)
assert_equal "http://github.com/davidfstr/rdiscount
\n", rd.to_html
end
def test_that_safelink_flag_works
rd = RDiscount.new("[IRC](irc://chat.freenode.org/#freenode)", :safelink)
assert_equal "[IRC](irc://chat.freenode.org/#freenode)
\n", rd.to_html
end
def test_that_no_pseudo_protocols_flag_works
rd = RDiscount.new("[foo](id:bar)", :no_pseudo_protocols)
assert_equal "[foo](id:bar)
\n", rd.to_html
end
def test_that_no_superscript_flag_works
rd = RDiscount.new("A^B", :no_superscript)
assert_equal "A^B
\n", rd.to_html
rd = RDiscount.new("A^B")
assert_equal "AB
\n", rd.to_html
end
def test_that_no_strikethrough_flag_works
rd = RDiscount.new("~~A~~", :no_strikethrough)
assert_equal "~~A~~
\n", rd.to_html
rd = RDiscount.new("~~A~~")
assert_equal "A
\n", rd.to_html
end
def test_that_tags_can_have_dashes_and_underscores
rd = RDiscount.new("foo bar and baz ")
assert_equal "foo bar and baz
\n", rd.to_html
end
def test_that_footnotes_flag_works
rd = RDiscount.new(<1')
end
def test_that_footnotes_in_span_works
rd = RDiscount.new(<1')
end
def test_that_unicode_urls_encoded_correctly
rd = RDiscount.new("[Test](http://example.com/ß)")
assert_equal "Test
\n", rd.to_html
end
def test_that_dashes_encoded_correctly
rd = RDiscount.new("A--B", :smart)
assert_equal "A–B
\n", rd.to_html
rd = RDiscount.new("A---B", :smart)
assert_equal "A—B
\n", rd.to_html
end
def test_that_superscripts_can_be_escaped
rd = RDiscount.new("A\\^B")
assert_equal "A^B
\n", rd.to_html
rd = RDiscount.new("A^B")
assert_equal "AB
\n", rd.to_html
end
def test_that_style_tag_is_not_filtered_by_default
rd = RDiscount.new(<
p { margin: 5px; }
EOS
assert_equal "Hello
\n\n\n\n", rd.to_html
end
def test_that_style_tag_is_filtered_with_flag
rd = RDiscount.new(<
p { margin: 5px; }
EOS
assert_equal "Hello
\n\n\n", rd.to_html
end
def test_that_tables_can_have_leading_and_trailing_pipes
rd = RDiscount.new(<\n\n\n A \n B \n \n \n\n\n C \n D \n \n \n\n\n", rd.to_html
end
def test_that_gfm_code_blocks_work
rd = RDiscount.new(<line 1\n\nline 2\n
\n", rd.to_html
end
def test_that_gfm_code_blocks_work_with_language
rd = RDiscount.new(<line 1\n\nline 2\n
\n", rd.to_html
end
def test_that_pandoc_code_blocks_work
rd = RDiscount.new(<line 1\n\nline 2\n
\n", rd.to_html
end
def test_that_discount_definition_lists_work
rd = RDiscount.new(<
tag1
tag2
data.
EOS
end
def test_latex_passtrough_dont_render_link
rd = RDiscount.new("$$[(1+2)*3-4](1-2)$$", :latex)
assert_equal "$$[(1+2)*3-4](1-2)$$
\n", rd.to_html
end
def test_that_emphasis_beside_international_characters_detected
rd = RDiscount.new(%(*foo ä bar*))
assert_equal %(foo ä bar
\n), rd.to_html
rd = RDiscount.new(%(*ä foobar*))
assert_equal %(ä foobar
\n), rd.to_html
rd = RDiscount.new(%(*foobar ä*))
assert_equal %(foobar ä
\n), rd.to_html
end
def test_taht
rd = RDiscount.new(<
Bullet
Bullet
Numbered
Numbered
EOS
end
def test_that_extra_definition_lists_work
rd = RDiscount.new(<
tag1
data
EOS
end
end
rdiscount-2.2.7.3/test/benchmark.txt 0000644 0000041 0000041 00000017600 14571373162 017414 0 ustar www-data www-data Markdown: Basics
================
Getting the Gist of Markdown's Formatting Syntax
------------------------------------------------
This page offers a brief overview of what it's like to use Markdown.
The [syntax page] [s] provides complete, detailed documentation for
every feature, but Markdown should be very easy to pick up simply by
looking at a few examples of it in action. The examples on this page
are written in a before/after style, showing example syntax and the
HTML output produced by Markdown.
It's also helpful to simply try Markdown out; the [Dingus] [d] is a
web application that allows you type your own Markdown-formatted text
and translate it to XHTML.
**Note:** This document is itself written using Markdown; you
can [see the source for it by adding '.text' to the URL] [src].
[s]: /projects/markdown/syntax "Markdown Syntax"
[d]: /projects/markdown/dingus "Markdown Dingus"
[src]: /projects/markdown/basics.text
## Paragraphs, Headers, Blockquotes ##
A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing spaces or tabs is considered
blank.) Normal paragraphs should not be intended with spaces or tabs.
Markdown offers two styles of headers: *Setext* and *atx*.
Setext-style headers for `` and `` are created by
"underlining" with equal signs (`=`) and hyphens (`-`), respectively.
To create an atx-style header, you put 1-6 hash marks (`#`) at the
beginning of the line -- the number of hashes equals the resulting
HTML header level.
Blockquotes are indicated using email-style '`>`' angle brackets.
Markdown:
A First Level Header
====================
A Second Level Header
---------------------
Now is the time for all good men to come to
the aid of their country. This is just a
regular paragraph.
The quick brown fox jumped over the lazy
dog's back.
### Header 3
> This is a blockquote.
>
> This is the second paragraph in the blockquote.
>
> ## This is an H2 in a blockquote
Output:
A First Level Header
A Second Level Header
Now is the time for all good men to come to
the aid of their country. This is just a
regular paragraph.
The quick brown fox jumped over the lazy
dog's back.
Header 3
This is a blockquote.
This is the second paragraph in the blockquote.
This is an H2 in a blockquote
### Phrase Emphasis ###
Markdown uses asterisks and underscores to indicate spans of emphasis.
Markdown:
Some of these words *are emphasized*.
Some of these words _are emphasized also_.
Use two asterisks for **strong emphasis**.
Or, if you prefer, __use two underscores instead__.
Output:
Some of these words are emphasized .
Some of these words are emphasized also .
Use two asterisks for strong emphasis .
Or, if you prefer, use two underscores instead .
## Lists ##
Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
`+`, and `-`) as list markers. These three markers are
interchangable; this:
* Candy.
* Gum.
* Booze.
this:
+ Candy.
+ Gum.
+ Booze.
and this:
- Candy.
- Gum.
- Booze.
all produce the same output:
Ordered (numbered) lists use regular numbers, followed by periods, as
list markers:
1. Red
2. Green
3. Blue
Output:
Red
Green
Blue
If you put blank lines between items, you'll get `` tags for the
list item text. You can create multi-paragraph list items by indenting
the paragraphs by 4 spaces or 1 tab:
* A list item.
With multiple paragraphs.
* Another item in the list.
Output:
### Links ###
Markdown supports two styles for creating links: *inline* and
*reference*. With both styles, you use square brackets to delimit the
text you want to turn into a link.
Inline-style links use parentheses immediately after the link text.
For example:
This is an [example link](http://example.com/).
Output:
This is an
example link .
Optionally, you may include a title attribute in the parentheses:
This is an [example link](http://example.com/ "With a Title").
Output:
This is an
example link .
Reference-style links allow you to refer to your links by names, which
you define elsewhere in your document:
I get 10 times more traffic from [Google][1] than from
[Yahoo][2] or [MSN][3].
[1]: http://google.com/ "Google"
[2]: http://search.yahoo.com/ "Yahoo Search"
[3]: http://search.msn.com/ "MSN Search"
Output:
I get 10 times more traffic from Google than from Yahoo or MSN .
The title attribute is optional. Link names may contain letters,
numbers and spaces, but are *not* case sensitive:
I start my morning with a cup of coffee and
[The New York Times][NY Times].
[ny times]: http://www.nytimes.com/
Output:
I start my morning with a cup of coffee and
The New York Times .
### Images ###
Image syntax is very much like link syntax.
Inline (titles are optional):

Reference-style:
![alt text][id]
[id]: /path/to/img.jpg "Title"
Both of the above examples produce the same output:
### Code ###
In a regular paragraph, you can create code span by wrapping text in
backtick quotes. Any ampersands (`&`) and angle brackets (`<` or
`>`) will automatically be translated into HTML entities. This makes
it easy to use Markdown to write about HTML example code:
I strongly recommend against using any `` tags.
I wish SmartyPants used named entities like `—`
instead of decimal-encoded entites like `—`.
Output:
I strongly recommend against using any
<blink>
tags.
I wish SmartyPants used named entities like
—
instead of decimal-encoded
entites like —
.
To specify an entire block of pre-formatted code, indent every line of
the block by 4 spaces or 1 tab. Just like with code spans, `&`, `<`,
and `>` characters will be escaped automatically.
Markdown:
If you want your page to validate under XHTML 1.0 Strict,
you've got to put paragraph tags in your blockquotes:
For example.
Output:
If you want your page to validate under XHTML 1.0 Strict,
you've got to put paragraph tags in your blockquotes:
<blockquote>
<p>For example.</p>
</blockquote>
rdiscount-2.2.7.3/test/benchmark.rb 0000644 0000041 0000041 00000002553 14571373162 017201 0 ustar www-data www-data require 'rubygems'
iterations = 100
test_file = "#{File.dirname(__FILE__)}/benchmark.txt"
implementations = %w[BlueCloth RDiscount Maruku PEGMarkdown]
# Attempt to require each implementation and remove any that are not
# installed.
implementations.reject! do |class_name|
begin
module_path =
if class_name == 'PEGMarkdown'
'peg_markdown'
else
class_name.downcase
end
require module_path
false
rescue LoadError => boom
module_path.tr! '_', '-'
puts "#{class_name} excluded. Try: gem install #{module_path}"
true
end
end
# Grab actual class objects.
implementations.map! { |class_name| Object.const_get(class_name) }
# The actual benchmark.
def benchmark(implementation, text, iterations)
start = Time.now
iterations.times do |i|
implementation.new(text).to_html
end
Time.now - start
end
# Read test file
test_data = File.read(test_file)
# Prime the pump
puts "Spinning up ..."
implementations.each { |impl| benchmark(impl, test_data, 1) }
# Run benchmarks; gather results.
puts "Running benchmarks ..."
results =
implementations.inject([]) do |r,impl|
GC.start
r << [ impl, benchmark(impl, test_data, iterations) ]
end
puts "Results for #{iterations} iterations:"
results.each do |impl,time|
printf " %10s %09.06fs total time, %09.06fs average\n", "#{impl}:", time, time / iterations
end
rdiscount-2.2.7.3/test/markdown_test.rb 0000644 0000041 0000041 00000013316 14571373162 020127 0 ustar www-data www-data rootdir = File.dirname(File.dirname(__FILE__))
$LOAD_PATH.unshift "#{rootdir}/lib"
require 'test/unit'
require 'markdown'
MARKDOWN_TEST_DIR = "#{rootdir}/test/MarkdownTest_1.0.3"
class MarkdownTest < Test::Unit::TestCase
def test_that_extension_methods_are_present_on_markdown_class
assert Markdown.instance_methods.map{|m| m.to_s }.include?('to_html'),
"Markdown class should respond to #to_html"
end
def test_that_simple_one_liner_goes_to_html
markdown = Markdown.new('Hello World.')
assert_respond_to markdown, :to_html
assert_equal "Hello World.
", markdown.to_html.strip
end
def test_that_inline_markdown_goes_to_html
markdown = Markdown.new('_Hello World_!')
assert_equal "Hello World !
", markdown.to_html.strip
end
def test_that_inline_markdown_starts_and_ends_correctly
markdown = Markdown.new('_start _ foo_bar bar_baz _ end_ *italic* **bold** _blah_ ')
assert_respond_to markdown, :to_html
assert_equal "start _ foo_bar bar_baz _ end italic bold blah
", markdown.to_html.strip
markdown = Markdown.new("Run 'rake radiant:extensions:rbac_base:migrate'")
assert_equal "Run 'rake radiant:extensions:rbac_base:migrate'
", markdown.to_html.strip
end
def test_that_filter_html_works
markdown = Markdown.new('Through NO ', :filter_html)
assert_equal "Through <em>NO</em> <script>DOUBLE NO</script>
", markdown.to_html.strip
end
def test_that_bluecloth_restrictions_are_supported
markdown = Markdown.new('Hello World.')
[:filter_html, :filter_styles].each do |restriction|
assert_respond_to markdown, restriction
assert_respond_to markdown, "#{restriction}="
end
assert_not_equal true, markdown.filter_html
assert_not_equal true, markdown.filter_styles
markdown = Markdown.new('Hello World.', :filter_html, :filter_styles)
assert_equal true, markdown.filter_html
assert_equal true, markdown.filter_styles
end
def test_that_redcloth_attributes_are_supported
markdown = Markdown.new('Hello World.')
assert_respond_to markdown, :fold_lines
assert_respond_to markdown, :fold_lines=
assert_not_equal true, markdown.fold_lines
markdown = Markdown.new('Hello World.', :fold_lines)
assert_equal true, markdown.fold_lines
end
def test_that_redcloth_to_html_with_single_arg_is_supported
markdown = Markdown.new('Hello World.')
assert_nothing_raised(ArgumentError) { markdown.to_html(true) }
end
def test_that_smart_converts_single_quotes_in_words_that_end_in_re
markdown = Markdown.new("They're not for sale.", :smart)
assert_equal "They’re not for sale.
\n", markdown.to_html
end
def test_that_smart_converts_single_quotes_in_words_that_end_in_ll
markdown = Markdown.new("Well that'll be the day", :smart)
assert_equal "Well that’ll be the day
\n", markdown.to_html
end
def test_that_urls_are_not_doubly_escaped
markdown = Markdown.new('[Page 2](/search?query=Markdown+Test&page=2)')
assert_equal "Page 2
\n", markdown.to_html
end
def test_simple_inline_html
markdown = Markdown.new("before\n\n\n foo\n
\nafter")
assert_equal "before
\n\n\n foo\n
\n\n\nafter
\n",
markdown.to_html
end
def test_that_html_blocks_do_not_require_their_own_end_tag_line
markdown = Markdown.new("Para 1\n\n\n\nPara 2 [Link](#anchor)")
assert_equal "Para 1
\n\n\n\n\nPara 2 Link
\n",
markdown.to_html
end
def test_filter_html_doesnt_break_two_space_hard_break
markdown = Markdown.new("Lorem, \nipsum\n", :filter_html)
assert_equal "Lorem, \nipsum
\n",
markdown.to_html
end
# This isn't in the spec but is Markdown.pl behavior.
def test_block_quotes_preceded_by_spaces
markdown = Markdown.new(
"A wise man once said:\n\n" +
" > Isn't it wonderful just to be alive.\n"
)
assert_equal "A wise man once said:
\n\n" +
"Isn't it wonderful just to be alive.
\n",
markdown.to_html
end
def test_ul_with_zero_space_indent
markdown = Markdown.new("- foo\n\n- bar\n\n baz\n")
assert_equal "",
markdown.to_html.gsub("\n", "")
end
def test_ul_with_single_space_indent
markdown = Markdown.new(" - foo\n\n - bar\n\n baz\n")
assert_equal "",
markdown.to_html.gsub("\n", "")
end
# http://github.com/davidfstr/rdiscount/issues/#issue/13
def test_headings_with_trailing_space
text = "The Ant-Sugar Tales \n" +
"=================== \n\n" +
"By Candice Yellowflower \n"
markdown = Markdown.new(text)
assert_equal "The Ant-Sugar Tales \n\nBy Candice Yellowflower
\n",
markdown.to_html
end
# Build tests for each file in the MarkdownTest test suite
Dir["#{MARKDOWN_TEST_DIR}/Tests/*.text"].each do |text_file|
basename = File.basename(text_file).sub(/\.text$/, '')
method_name = basename.gsub(/[-,()]/, '').gsub(/\s+/, '_').downcase
define_method "test_#{method_name}" do
markdown = Markdown.new(File.read(text_file))
actual_html = markdown.to_html
assert_not_nil actual_html
end
define_method "test_#{method_name}_smart" do
markdown = Markdown.new(File.read(text_file), :smart)
actual_html = markdown.to_html
assert_not_nil actual_html
end
end
end
rdiscount-2.2.7.3/Rakefile 0000644 0000041 0000041 00000015737 14571373162 015420 0 ustar www-data www-data require 'date'
require 'rake/clean'
require 'digest/md5'
task :default => :test
# ==========================================================
# Ruby Extension
# ==========================================================
DLEXT = RbConfig::MAKEFILE_CONFIG['DLEXT']
RUBYDIGEST = Digest::MD5.hexdigest(`ruby --version`)
file "ext/ruby-#{RUBYDIGEST}" do |f|
rm_f FileList["ext/ruby-*"]
touch f.name
end
CLEAN.include "ext/ruby-*"
file 'ext/Makefile' => FileList['ext/*.{c,h,rb}', "ext/ruby-#{RUBYDIGEST}"] do
chdir('ext') { ruby 'extconf.rb' }
end
CLEAN.include 'ext/Makefile', 'ext/mkmf.log'
file "ext/rdiscount.#{DLEXT}" => FileList["ext/Makefile"] do |f|
sh 'cd ext && make clean && make && rm -rf conftest.dSYM'
end
CLEAN.include 'ext/*.{o,bundle,so,dll}'
file "lib/rdiscount.#{DLEXT}" => "ext/rdiscount.#{DLEXT}" do |f|
cp f.prerequisites, "lib/", :preserve => true
end
desc 'Build the rdiscount extension'
task :build => "lib/rdiscount.#{DLEXT}"
# ==========================================================
# Manual
# ==========================================================
file 'man/rdiscount.1' => 'man/rdiscount.1.ronn' do
sh "ronn --manual=RUBY -b man/rdiscount.1.ronn"
end
CLOBBER.include 'man/rdiscount.1'
desc 'Build manpages'
task :man => 'man/rdiscount.1'
# ==========================================================
# Testing
# ==========================================================
require 'rake/testtask'
Rake::TestTask.new('test:unit') do |t|
t.test_files = FileList['test/*_test.rb']
t.ruby_opts += ['-r rubygems'] if defined? Gem
end
task 'test:unit' => [:build]
desc 'Run conformance tests (MARKDOWN_TEST_VER=1.0)'
task 'test:conformance' => [:build] do |t|
script = "#{pwd}/bin/rdiscount"
test_version = ENV['MARKDOWN_TEST_VER'] || '1.0.3'
lib_dir = "#{pwd}/lib"
chdir("test/MarkdownTest_#{test_version}") do
result = `RUBYLIB=#{lib_dir} ./MarkdownTest.pl --script='#{script}' --tidy`
print result
fail unless result.include? "; 0 failed."
end
# Allow to run this rake tasks multiple times
# https://medium.com/@shaneilske/invoke-a-rake-task-multiple-times-1bcb01dee9d9
ENV.delete("MARKDOWN_TEST_VER")
ENV.delete("RDISCOUNT_EXTENSIONS")
Rake::Task["test:conformance"].reenable
end
desc 'Run version 1.0 conformance suite'
task 'test:conformance:1.0' => [:build] do |t|
ENV['MARKDOWN_TEST_VER'] = '1.0'
# see https://github.com/Orc/discount/issues/261
# requires flags -f1.0,tabstop,nopants
ENV['RDISCOUNT_EXTENSIONS'] = "md1compat"
Rake::Task['test:conformance'].invoke
end
desc 'Run 1.0.3 conformance suite'
task 'test:conformance:1.0.3' => [:build] do |t|
ENV['MARKDOWN_TEST_VER'] = '1.0.3'
Rake::Task['test:conformance'].invoke
end
desc 'Run unit and conformance tests'
task :test => %w[test:unit test:conformance:1.0 test:conformance:1.0.3]
desc 'Run benchmarks'
task :benchmark => :build do |t|
$:.unshift 'lib'
load 'test/benchmark.rb'
end
# ==========================================================
# Documentation
# ==========================================================
desc 'Generate API documentation'
task :doc => 'doc/index.html'
file 'doc/index.html' => FileList['lib/*.rb'] do |f|
sh((<<-end).gsub(/\s+/, ' '))
hanna --charset utf8 --fmt html --inline-source --line-numbers \
--main RDiscount --op doc --title 'RDiscount API Documentation' \
#{f.prerequisites.join(' ')}
end
end
CLEAN.include 'doc'
# ==========================================================
# Update package's Discount sources
# ==========================================================
desc 'Gather required discount sources into extension directory'
task :gather => 'discount/markdown.h' do |t|
# Files unique to /ext that should not be overridden
rdiscount_ext_files = [
"config.h",
"extconf.rb",
"rdiscount.c",
]
# Files in /discount that have a main function and should not be copied to /ext
discount_c_files_with_main_function = [
"main.c",
"makepage.c",
"mkd2html.c",
"theme.c",
]
# Ensure configure.sh was run
if not File.exists? 'discount/mkdio.h'
abort "discount/mkdio.h not found. Did you run ./configure.sh in the discount directory?"
end
# Delete all *.c and *.h files from ext that are not specific to RDiscount.
Dir.chdir("ext") do
c_files_to_delete = Dir["*.c"].select { |e| !rdiscount_ext_files.include? e }
h_files_to_delete = Dir["*.h"].select { |e| !rdiscount_ext_files.include? e }
rm (c_files_to_delete + h_files_to_delete),
:verbose => true
end
# Copy all *.c and *.h files from discount -> ext except those that
# RDiscount overrides. Also exclude Discount files with main functions.
Dir.chdir("discount") do
c_files_to_copy = Dir["*.c"].select { |e|
(!rdiscount_ext_files.include? e) &&
(!discount_c_files_with_main_function.include? e)
}
h_files_to_copy = Dir["*.h"].select { |e| !rdiscount_ext_files.include? e }
cp (c_files_to_copy + h_files_to_copy), '../ext/',
:preserve => true,
:verbose => true
end
# Copy special files from discount -> ext
cp 'discount/blocktags', 'ext/'
cp 'discount/VERSION', 'ext/'
# Copy man page
cp 'discount/markdown.7', 'man/'
# Apply patches
system('cat ext.diff | patch -p1 -d ext')
end
file 'discount/markdown.h' do |t|
abort "The discount submodule is required. See the file BUILDING for getting set up."
end
# PACKAGING =================================================================
require 'rubygems'
$spec = eval(File.read('rdiscount.gemspec'))
def package(ext='')
"pkg/rdiscount-#{$spec.version}" + ext
end
desc 'Build packages'
task :package => %w[.gem .tar.gz].map {|e| package(e)}
desc 'Build and install as local gem'
task :install => package('.gem') do
sh "gem install #{package('.gem')}"
end
directory 'pkg/'
file package('.gem') => %w[pkg/ rdiscount.gemspec] + $spec.files do |f|
sh "gem build rdiscount.gemspec"
mv File.basename(f.name), f.name
end
file package('.tar.gz') => %w[pkg/] + $spec.files do |f|
sh "git archive --format=tar HEAD | gzip > #{f.name}"
end
# GEMSPEC HELPERS ==========================================================
def source_version
line = File.read('lib/rdiscount.rb')[/^\s*VERSION = .*/]
line.match(/.*VERSION = '(.*)'/)[1]
end
file 'rdiscount.gemspec' => FileList['Rakefile','lib/rdiscount.rb'] do |f|
# read spec file and split out manifest section
spec = File.read(f.name)
head, manifest, tail = spec.split(" # = MANIFEST =\n")
head.sub!(/\.version = '.*'/, ".version = '#{source_version}'")
head.sub!(/\.date = '.*'/, ".date = '#{Date.today.to_s}'")
# determine file list from git ls-files
files = `git ls-files`.
split("\n").
sort.
reject{ |file| file =~ /^\./ || file =~ /^test\/MarkdownTest/ }.
map{ |file| " #{file}" }.
join("\n")
# piece file back together and write...
manifest = " s.files = %w[\n#{files}\n ]\n"
spec = [head,manifest,tail].join(" # = MANIFEST =\n")
File.open(f.name, 'w') { |io| io.write(spec) }
puts "updated #{f.name}"
end
rdiscount-2.2.7.3/COPYING 0000644 0000041 0000041 00000003117 14571373162 014773 0 ustar www-data www-data The core Discount C sources are
Copyright (C) 2007 David Loren Parsons.
The Discount Ruby extension sources are
Copyright (C) 2008 Ryan Tomayko.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of works must retain the original copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the original copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither my name (David L Parsons) nor the names of contributors to
this code may be used to endorse or promote products derived
from this work without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
rdiscount-2.2.7.3/ext/ 0000755 0000041 0000041 00000000000 14571373162 014536 5 ustar www-data www-data rdiscount-2.2.7.3/ext/dumptree.c 0000644 0000041 0000041 00000005742 14571373162 016537 0 ustar www-data www-data /* markdown: a C implementation of John Gruber's Markdown markup language.
*
* Copyright (C) 2007 David L Parsons.
* The redistribution terms are provided in the COPYRIGHT file that must
* be distributed with this source code.
*/
#include
#include "markdown.h"
#include "cstring.h"
#include "amalloc.h"
struct frame {
int indent;
char c;
};
typedef STRING(struct frame) Stack;
static char *
Pptype(int typ)
{
switch (typ) {
case WHITESPACE: return "whitespace";
case CODE : return "code";
case QUOTE : return "quote";
case MARKUP : return "markup";
case HTML : return "html";
case DL : return "dl";
case UL : return "ul";
case OL : return "ol";
case LISTITEM : return "item";
case HDR : return "header";
case HR : return "hr";
case TABLE : return "table";
case SOURCE : return "source";
case STYLE : return "style";
default : return "mystery node!";
}
}
static void
pushpfx(int indent, char c, Stack *sp)
{
struct frame *q = &EXPAND(*sp);
q->indent = indent;
q->c = c;
}
static void
poppfx(Stack *sp)
{
S(*sp)--;
}
static void
changepfx(Stack *sp, char c)
{
char ch;
if ( !S(*sp) ) return;
ch = T(*sp)[S(*sp)-1].c;
if ( ch == '+' || ch == '|' )
T(*sp)[S(*sp)-1].c = c;
}
static void
printpfx(Stack *sp, FILE *f)
{
int i;
char c;
if ( !S(*sp) ) return;
c = T(*sp)[S(*sp)-1].c;
if ( c == '+' || c == '-' ) {
fprintf(f, "--%c", c);
T(*sp)[S(*sp)-1].c = (c == '-') ? ' ' : '|';
}
else
for ( i=0; i < S(*sp); i++ ) {
if ( i )
fprintf(f, " ");
fprintf(f, "%*s%c", T(*sp)[i].indent + 2, " ", T(*sp)[i].c);
if ( T(*sp)[i].c == '`' )
T(*sp)[i].c = ' ';
}
fprintf(f, "--");
}
static void
dumptree(Paragraph *pp, Stack *sp, FILE *f)
{
int count;
Line *p;
int d;
static char *Begin[] = { 0, "P", "center" };
while ( pp ) {
if ( !pp->next )
changepfx(sp, '`');
printpfx(sp, f);
if ( pp->typ == HDR )
d += fprintf(f, "[h%d", pp->hnumber);
else
d = fprintf(f, "[%s", Pptype(pp->typ));
if ( pp->ident )
d += fprintf(f, " %s", pp->ident);
#ifdef GITHUB_CHECKBOX
if ( pp->flags )
d += fprintf(f, " %x", pp->flags);
#endif
if ( pp->align > 1 )
d += fprintf(f, ", <%s>", Begin[pp->align]);
for (count=0, p=pp->text; p; ++count, (p = p->next) )
;
if ( count )
d += fprintf(f, ", %d line%s", count, (count==1)?"":"s");
d += fprintf(f, "]");
if ( pp->down ) {
pushpfx(d, pp->down->next ? '+' : '-', sp);
dumptree(pp->down, sp, f);
poppfx(sp);
}
else fputc('\n', f);
pp = pp->next;
}
}
int
mkd_dump(Document *doc, FILE *out, mkd_flag_t flags, char *title)
{
Stack stack;
if (mkd_compile(doc, flags) ) {
CREATE(stack);
pushpfx(fprintf(out, "%s", title), doc->code->next ? '+' : '-', &stack);
dumptree(doc->code, &stack, out);
DELETE(stack);
return 0;
}
return -1;
}
rdiscount-2.2.7.3/ext/flags.c 0000644 0000041 0000041 00000004445 14571373162 016005 0 ustar www-data www-data #include
#include "markdown.h"
struct flagnames {
mkd_flag_t flag;
char *name;
};
static struct flagnames flagnames[] = {
{ MKD_NOLINKS, "!LINKS" },
{ MKD_NOIMAGE, "!IMAGE" },
{ MKD_NOPANTS, "!PANTS" },
{ MKD_NOHTML, "!HTML" },
{ MKD_STRICT, "STRICT" },
{ MKD_TAGTEXT, "TAGTEXT" },
{ MKD_NO_EXT, "!EXT" },
{ MKD_CDATA, "CDATA" },
{ MKD_NOSUPERSCRIPT, "!SUPERSCRIPT" },
{ MKD_NORELAXED, "!RELAXED" },
{ MKD_NOTABLES, "!TABLES" },
{ MKD_NOSTRIKETHROUGH,"!STRIKETHROUGH" },
{ MKD_TOC, "TOC" },
{ MKD_1_COMPAT, "MKD_1_COMPAT" },
{ MKD_AUTOLINK, "AUTOLINK" },
{ MKD_SAFELINK, "SAFELINK" },
{ MKD_NOHEADER, "!HEADER" },
{ MKD_TABSTOP, "TABSTOP" },
{ MKD_NODIVQUOTE, "!DIVQUOTE" },
{ MKD_NOALPHALIST, "!ALPHALIST" },
{ MKD_NODLIST, "!DLIST" },
{ MKD_EXTRA_FOOTNOTE, "FOOTNOTE" },
{ MKD_NOSTYLE, "!STYLE" },
{ MKD_NODLDISCOUNT, "!DLDISCOUNT" },
{ MKD_DLEXTRA, "DLEXTRA" },
{ MKD_FENCEDCODE, "FENCEDCODE" },
{ MKD_IDANCHOR, "IDANCHOR" },
{ MKD_GITHUBTAGS, "GITHUBTAGS" },
{ MKD_URLENCODEDANCHOR, "URLENCODEDANCHOR" },
{ MKD_LATEX, "LATEX" },
{ MKD_EXPLICITLIST, "EXPLICITLIST" },
};
#define NR(x) (sizeof x/sizeof x[0])
void
mkd_flags_are(FILE *f, mkd_flag_t flags, int htmlplease)
{
int i;
int not, set, even=1;
char *name;
if ( htmlplease )
fprintf(f, "\n");
for (i=0; i < NR(flagnames); i++) {
set = flags & flagnames[i].flag;
name = flagnames[i].name;
if ( not = (*name == '!') ) {
++name;
set = !set;
}
if ( htmlplease ) {
if ( even ) fprintf(f, " ");
fprintf(f, "");
}
else
fputc(' ', f);
if ( !set )
fprintf(f, htmlplease ? "" : "!");
fprintf(f, "%s", name);
if ( htmlplease ) {
if ( !set )
fprintf(f, " ");
fprintf(f, " ");
if ( !even ) fprintf(f, " \n");
}
even = !even;
}
if ( htmlplease ) {
if ( even ) fprintf(f, "\n");
fprintf(f, "
\n");
}
}
void
mkd_mmiot_flags(FILE *f, MMIOT *m, int htmlplease)
{
if ( m )
mkd_flags_are(f, m->flags, htmlplease);
}
rdiscount-2.2.7.3/ext/rdiscount.c 0000644 0000041 0000041 00000011164 14571373162 016717 0 ustar www-data www-data #include
#include
#include "ruby.h"
#include "mkdio.h"
typedef struct {
char *accessor_name;
int flag;
} AccessorFlagPair;
/*
* Maps accessor names on the RDiscount object to Discount flags.
*
* The following flags are handled specially:
* - MKD_TABSTOP: Always set.
* - MKD_NOHEADER: Always set.
* - MKD_DLEXTRA: Always set. (For compatibility with RDiscount 2.1.8 and earlier.)
* - MKD_FENCEDCODE: Always set. (For compatibility with RDiscount 2.1.8 and earlier.)
* - MKD_GITHUBTAGS: Always set. (For compatibility with RDiscount 2.1.8 and earlier.)
* - MKD_NOPANTS: Set unless the "smart" accessor returns true.
* - MKD_NOSTYLE: Set unless the "filter_styles" accessor returns true.
*
* See rb_rdiscount__get_flags() for the detailed implementation.
*/
static AccessorFlagPair ACCESSOR_2_FLAG[] = {
{ "filter_html", MKD_NOHTML },
{ "footnotes", MKD_EXTRA_FOOTNOTE },
{ "generate_toc", MKD_TOC },
{ "no_image", MKD_NOIMAGE },
{ "no_links", MKD_NOLINKS },
{ "no_tables", MKD_NOTABLES },
{ "strict", MKD_STRICT },
{ "autolink", MKD_AUTOLINK },
{ "safelink", MKD_SAFELINK },
{ "no_pseudo_protocols", MKD_NO_EXT },
{ "no_superscript", MKD_NOSUPERSCRIPT },
{ "no_strikethrough", MKD_NOSTRIKETHROUGH },
{ "latex", MKD_LATEX },
{ "explicitlist", MKD_EXPLICITLIST },
{ "md1compat", MKD_1_COMPAT },
{ NULL, 0 } /* sentinel */
};
static VALUE rb_cRDiscount;
int rb_rdiscount__get_flags(VALUE ruby_obj)
{
AccessorFlagPair *entry;
/* compile flags */
int flags = MKD_TABSTOP | MKD_NOHEADER | MKD_DLEXTRA | MKD_FENCEDCODE | MKD_GITHUBTAGS;
/* The "smart" accessor turns OFF the MKD_NOPANTS flag. */
if ( rb_funcall(ruby_obj, rb_intern("smart"), 0) != Qtrue ) {
flags = flags | MKD_NOPANTS;
}
/* The "filter_styles" accessor turns OFF the MKD_NOSTYLE flag. */
if ( rb_funcall(ruby_obj, rb_intern("filter_styles"), 0) != Qtrue ) {
flags = flags | MKD_NOSTYLE;
}
/* Handle standard flags declared in ACCESSOR_2_FLAG */
for ( entry = ACCESSOR_2_FLAG; entry->accessor_name; entry++ ) {
if ( rb_funcall(ruby_obj, rb_intern(entry->accessor_name), 0) == Qtrue ) {
flags = flags | entry->flag;
}
}
return flags;
}
static VALUE
rb_rdiscount_to_html(int argc, VALUE *argv, VALUE self)
{
/* grab char pointer to markdown input text */
char *res;
int szres;
VALUE encoding;
VALUE text = rb_funcall(self, rb_intern("text"), 0);
VALUE buf = rb_str_buf_new(1024);
Check_Type(text, T_STRING);
int flags = rb_rdiscount__get_flags(self);
/*
* Force Discount to use ASCII character encoding for isalnum(), isalpha(),
* and similar functions.
*
* Ruby tends to use UTF-8 encoding, which is ill-defined for these
* functions since they expect 8-bit codepoints (and UTF-8 has codepoints
* of at least 21 bits).
*/
char *old_locale = strdup(setlocale(LC_CTYPE, NULL));
setlocale(LC_CTYPE, "C"); /* ASCII (and passthru characters > 127) */
MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);
if ( mkd_compile(doc, flags) ) {
szres = mkd_document(doc, &res);
if ( szres != EOF ) {
rb_str_cat(buf, res, szres);
rb_str_cat(buf, "\n", 1);
}
}
mkd_cleanup(doc);
setlocale(LC_CTYPE, old_locale);
free(old_locale);
/* force the input encoding */
if ( rb_respond_to(text, rb_intern("encoding")) ) {
encoding = rb_funcall(text, rb_intern("encoding"), 0);
rb_funcall(buf, rb_intern("force_encoding"), 1, encoding);
}
return buf;
}
static VALUE
rb_rdiscount_toc_content(int argc, VALUE *argv, VALUE self)
{
char *res;
int szres;
int flags = rb_rdiscount__get_flags(self);
/* grab char pointer to markdown input text */
VALUE text = rb_funcall(self, rb_intern("text"), 0);
Check_Type(text, T_STRING);
/* allocate a ruby string buffer and wrap it in a stream */
VALUE buf = rb_str_buf_new(4096);
MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);
if ( mkd_compile(doc, flags) ) {
szres = mkd_toc(doc, &res);
if ( szres != EOF ) {
rb_str_cat(buf, res, szres);
rb_str_cat(buf, "\n", 1);
}
}
mkd_cleanup(doc);
return buf;
}
void Init_rdiscount()
{
rb_cRDiscount = rb_define_class("RDiscount", rb_cObject);
rb_define_method(rb_cRDiscount, "to_html", rb_rdiscount_to_html, -1);
rb_define_method(rb_cRDiscount, "toc_content", rb_rdiscount_toc_content, -1);
}
/* vim: set ts=4 sw=4: */
rdiscount-2.2.7.3/ext/gethopt.h 0000644 0000041 0000041 00000001626 14571373162 016366 0 ustar www-data www-data /*
* gethopt; options processing with both single-character and whole-work
* options both introduced with -
*/
#ifndef __GETHOPT_D
#define __GETHOPT_D
#include
#include
struct h_opt {
int option;
char *optword;
char optchar;
char *opthasarg;
char *optdesc;
} ;
#define HOPTERR ((struct h_opt*)-1)
struct h_context {
char **argv;
int argc;
int optchar;
int optind;
char *optarg;
char optopt;
int opterr:1;
int optend:1;
} ;
extern char *hoptarg(struct h_context *);
extern int hoptind(struct h_context *);
extern char hoptopt(struct h_context *);
extern void hoptset(struct h_context *, int, char **);
extern int hopterr(struct h_context *, int);
extern struct h_opt *gethopt(struct h_context *, struct h_opt*, int);
extern void hoptusage(char *, struct h_opt*, int, char *);
#endif/*__GETHOPT_D*/
rdiscount-2.2.7.3/ext/mktags.c 0000644 0000041 0000041 00000003415 14571373162 016173 0 ustar www-data www-data /* block-level tags for passing html blocks through the blender
*/
#include
#define __WITHOUT_AMALLOC 1
#include "config.h"
#include "cstring.h"
#include "tags.h"
STRING(struct kw) blocktags;
/* define a html block tag
*/
static void
define_one_tag(char *id, int selfclose)
{
struct kw *p = &EXPAND(blocktags);
p->id = id;
p->size = strlen(id);
p->selfclose = selfclose;
}
/* case insensitive string sort (for qsort() and bsearch() of block tags)
*/
static int
casort(struct kw *a, struct kw *b)
{
if ( a->size != b->size )
return a->size - b->size;
return strncasecmp(a->id, b->id, b->size);
}
/* stupid cast to make gcc shut up about the function types being
* passed into qsort() and bsearch()
*/
typedef int (*stfu)(const void*,const void*);
/* load in the standard collection of html tags that markdown supports
*/
int
main()
{
int i;
#define KW(x) define_one_tag(x, 0)
#define SC(x) define_one_tag(x, 1)
KW("STYLE");
KW("SCRIPT");
KW("ADDRESS");
KW("BDO");
KW("BLOCKQUOTE");
KW("CENTER");
KW("DFN");
KW("DIV");
KW("OBJECT");
KW("H1");
KW("H2");
KW("H3");
KW("H4");
KW("H5");
KW("H6");
KW("LISTING");
KW("NOBR");
KW("FORM");
KW("UL");
KW("P");
KW("OL");
KW("DL");
KW("PLAINTEXT");
KW("PRE");
KW("TABLE");
KW("WBR");
KW("XMP");
SC("HR");
KW("IFRAME");
KW("MAP");
qsort(T(blocktags), S(blocktags), sizeof(struct kw), (stfu)casort);
printf("static struct kw blocktags[] = {\n");
for (i=0; i < S(blocktags); i++)
printf(" { \"%s\", %d, %d },\n", T(blocktags)[i].id, T(blocktags)[i].size, T(blocktags)[i].selfclose );
printf("};\n\n");
printf("#define NR_blocktags %d\n", S(blocktags));
exit(0);
}
rdiscount-2.2.7.3/ext/markdown.c 0000644 0000041 0000041 00000073327 14571373162 016540 0 ustar www-data www-data /* markdown: a C implementation of John Gruber's Markdown markup language.
*
* Copyright (C) 2007 David L Parsons.
* The redistribution terms are provided in the COPYRIGHT file that must
* be distributed with this source code.
*/
#include "config.h"
#include
#include
#include
#include
#include
#include
#include "cstring.h"
#include "markdown.h"
#include "amalloc.h"
#include "tags.h"
typedef int (*stfu)(const void*,const void*);
typedef ANCHOR(Paragraph) ParagraphRoot;
static Paragraph *Pp(ParagraphRoot *, Line *, int);
static Paragraph *compile(Line *, int, MMIOT *);
/* case insensitive string sort for Footnote tags.
*/
int
__mkd_footsort(Footnote *a, Footnote *b)
{
int i;
char ac, bc;
if ( S(a->tag) != S(b->tag) )
return S(a->tag) - S(b->tag);
for ( i=0; i < S(a->tag); i++) {
ac = tolower(T(a->tag)[i]);
bc = tolower(T(b->tag)[i]);
if ( isspace(ac) && isspace(bc) )
continue;
if ( ac != bc )
return ac - bc;
}
return 0;
}
/* find the first blank character after position
*/
static int
nextblank(Line *t, int i)
{
while ( (i < S(t->text)) && !isspace(T(t->text)[i]) )
++i;
return i;
}
/* find the next nonblank character after position
*/
static int
nextnonblank(Line *t, int i)
{
while ( (i < S(t->text)) && isspace(T(t->text)[i]) )
++i;
return i;
}
/* find the first nonblank character on the Line.
*/
int
mkd_firstnonblank(Line *p)
{
return nextnonblank(p,0);
}
static inline int
blankline(Line *p)
{
return ! (p && (S(p->text) > p->dle) );
}
static Line *
skipempty(Line *p)
{
while ( p && (p->dle == S(p->text)) )
p = p->next;
return p;
}
void
___mkd_tidy(Cstring *t)
{
while ( S(*t) && isspace(T(*t)[S(*t)-1]) )
--S(*t);
}
static struct kw comment = { "!--", 3, 0 };
static struct kw *
isopentag(Line *p)
{
int i=0, len;
char *line;
if ( !p ) return 0;
line = T(p->text);
len = S(p->text);
if ( len < 3 || line[0] != '<' )
return 0;
if ( line[1] == '!' && line[2] == '-' && line[3] == '-' )
/* comments need special case handling, because
* the !-- doesn't need to end in a whitespace
*/
return &comment;
/* find how long the tag is so we can check to see if
* it's a block-level tag
*/
for ( i=1; i < len && T(p->text)[i] != '>'
&& T(p->text)[i] != '/'
&& !isspace(T(p->text)[i]); ++i )
;
return mkd_search_tags(T(p->text)+1, i-1);
}
typedef struct _flo {
Line *t;
int i;
} FLO;
#define floindex(x) (x.i)
static unsigned int
flogetc(FLO *f)
{
if ( f && f->t ) {
if ( f->i < S(f->t->text) )
return (unsigned char)T(f->t->text)[f->i++];
f->t = f->t->next;
f->i = 0;
return flogetc(f);
}
return EOF;
}
static void
splitline(Line *t, int cutpoint)
{
if ( t && (cutpoint < S(t->text)) ) {
Line *tmp = calloc(1, sizeof *tmp);
tmp->next = t->next;
t->next = tmp;
SUFFIX(tmp->text, T(t->text)+cutpoint, S(t->text)-cutpoint);
EXPAND(tmp->text) = 0;
S(tmp->text)--;
S(t->text) = cutpoint;
}
}
#define UNCHECK(l) ((l)->flags &= ~CHECKED)
#define UNLESS_FENCED(t) if (fenced) { \
other = 1; l->count += (c == ' ' ? 0 : -1); \
} else { t; }
/*
* walk a line, seeing if it's any of half a dozen interesting regular
* types.
*/
static void
checkline(Line *l, mkd_flag_t flags)
{
int eol, i;
int dashes = 0, spaces = 0,
equals = 0, underscores = 0,
stars = 0, tildes = 0, other = 0,
backticks = 0, fenced = 0;
l->flags |= CHECKED;
l->kind = chk_text;
l->count = 0;
if (l->dle >= 4) { l->kind=chk_code; return; }
for ( eol = S(l->text); eol > l->dle && isspace(T(l->text)[eol-1]); --eol )
;
for (i=l->dle; itext)[i];
int is_fence_char = 0;
if ( c != ' ' ) l->count++;
switch (c) {
case '-': UNLESS_FENCED(dashes = 1); break;
case ' ': UNLESS_FENCED(spaces = 1); break;
case '=': UNLESS_FENCED(equals = 1); break;
case '_': UNLESS_FENCED(underscores = 1); break;
case '*': stars = 1; break;
default:
if ( is_flag_set(flags, MKD_FENCEDCODE) ) {
switch (c) {
case '~': if (other) return; is_fence_char = 1; tildes = 1; break;
case '`': if (other) return; is_fence_char = 1; backticks = 1; break;
}
if (is_fence_char) {
fenced = 1;
break;
}
}
other = 1;
l->count--;
if (!fenced) return;
}
}
if ( dashes + equals + underscores + stars + tildes + backticks > 1 )
return;
if ( spaces ) {
if ( (underscores || stars || dashes) )
l->kind = chk_hr;
return;
}
if ( stars || underscores ) { l->kind = chk_hr; }
else if ( dashes ) { l->kind = chk_dash; }
else if ( equals ) { l->kind = chk_equal; }
else if ( tildes ) { l->kind = chk_tilde; }
else if ( backticks ) { l->kind = chk_backtick; }
}
/* markdown only does special handling of comments if the comment end
* is at the end of a line
*/
static Line *
commentblock(Paragraph *p, int *unclosed)
{
Line *t, *ret;
char *end;
for ( t = p->text; t ; t = t->next) {
if ( end = strstr(T(t->text), "-->") ) {
if ( nextnonblank(t, 3 + (end - T(t->text))) < S(t->text) )
continue;
/*splitline(t, 3 + (end - T(t->text)) );*/
ret = t->next;
t->next = 0;
return ret;
}
}
*unclosed = 1;
return t;
}
static Line *
htmlblock(Paragraph *p, struct kw *tag, int *unclosed)
{
Line *ret;
FLO f = { p->text, 0 };
int c;
int i, closing, depth=0;
*unclosed = 0;
if ( tag == &comment )
return commentblock(p, unclosed);
if ( tag->selfclose ) {
ret = f.t->next;
f.t->next = 0;
return ret;
}
while ( (c = flogetc(&f)) != EOF ) {
if ( c == '<' ) {
/* tag? */
c = flogetc(&f);
if ( c == '!' ) { /* comment? */
if ( flogetc(&f) == '-' && flogetc(&f) == '-' ) {
/* yes */
while ( (c = flogetc(&f)) != EOF ) {
if ( c == '-' && flogetc(&f) == '-'
&& flogetc(&f) == '>')
/* consumed whole comment */
break;
}
}
}
else {
if ( closing = (c == '/') ) c = flogetc(&f);
for ( i=0; i < tag->size; i++, c=flogetc(&f) ) {
if ( tag->id[i] != toupper(c) )
break;
}
if ( (i == tag->size) && !isalnum(c) ) {
depth = depth + (closing ? -1 : 1);
if ( depth == 0 ) {
while ( c != EOF && c != '>' ) {
/* consume trailing gunk in close tag */
c = flogetc(&f);
}
if ( c == EOF )
break;
if ( !f.t )
return 0;
splitline(f.t, floindex(f));
ret = f.t->next;
f.t->next = 0;
return ret;
}
}
}
}
}
*unclosed = 1;
return 0;
}
/* footnotes look like ^{0,3}[stuff]: $
*/
static int
isfootnote(Line *t)
{
int i;
if ( ( (i = t->dle) > 3) || (T(t->text)[i] != '[') )
return 0;
for ( ++i; i < S(t->text) ; ++i ) {
if ( T(t->text)[i] == '[' )
return 0;
else if ( T(t->text)[i] == ']' )
return ( T(t->text)[i+1] == ':' ) ;
}
return 0;
}
static inline int
isquote(Line *t)
{
return (t->dle < 4 && T(t->text)[t->dle] == '>');
}
static inline int
iscode(Line *t)
{
return (t->dle >= 4);
}
static inline int
ishr(Line *t, mkd_flag_t flags)
{
if ( ! (t->flags & CHECKED) )
checkline(t, flags);
if ( t->count > 2 )
return t->kind == chk_hr || t->kind == chk_dash || t->kind == chk_equal;
return 0;
}
static int
issetext(Line *t, int *htyp, mkd_flag_t flags)
{
Line *n;
/* check for setext-style HEADER
* ======
*/
if ( (n = t->next) ) {
if ( !(n->flags & CHECKED) )
checkline(n, flags);
if ( n->kind == chk_dash || n->kind == chk_equal ) {
*htyp = SETEXT;
return 1;
}
}
return 0;
}
static int
ishdr(Line *t, int *htyp, mkd_flag_t flags)
{
/* ANY leading `#`'s make this into an ETX header
*/
if ( (t->dle == 0) && (S(t->text) > 1) && (T(t->text)[0] == '#') ) {
*htyp = ETX;
return 1;
}
/* And if not, maybe it's a SETEXT header instead
*/
return issetext(t, htyp, flags);
}
static inline int
end_of_block(Line *t, mkd_flag_t flags)
{
int dummy;
if ( !t )
return 0;
return ( (S(t->text) <= t->dle) || ishr(t, flags) || ishdr(t, &dummy, flags) );
}
static Line*
is_discount_dt(Line *t, int *clip, mkd_flag_t flags)
{
if ( !is_flag_set(flags, MKD_NODLDISCOUNT)
&& t
&& t->next
&& (S(t->text) > 2)
&& (t->dle == 0)
&& (T(t->text)[0] == '=')
&& (T(t->text)[S(t->text)-1] == '=') ) {
if ( t->next->dle >= 4 ) {
*clip = 4;
return t;
}
else
return is_discount_dt(t->next, clip, flags);
}
return 0;
}
static int
is_extra_dd(Line *t)
{
return (t->dle < 4) && (T(t->text)[t->dle] == ':')
&& isspace(T(t->text)[t->dle+1]);
}
static Line*
is_extra_dt(Line *t, int *clip, mkd_flag_t flags)
{
if ( is_flag_set(flags, MKD_DLEXTRA)
&& t
&& t->next && S(t->text) && T(t->text)[0] != '='
&& T(t->text)[S(t->text)-1] != '=') {
Line *x;
if ( iscode(t) || end_of_block(t, flags) )
return 0;
if ( (x = skipempty(t->next)) && is_extra_dd(x) ) {
*clip = x->dle+2;
return t;
}
if ( x=is_extra_dt(t->next, clip, flags) )
return x;
}
return 0;
}
static Line*
isdefinition(Line *t, int *clip, int *kind, mkd_flag_t flags)
{
Line *ret;
*kind = 1;
if ( ret = is_discount_dt(t,clip,flags) )
return ret;
*kind=2;
return is_extra_dt(t,clip,flags);
}
static int
islist(Line *t, int *clip, mkd_flag_t flags, int *list_type)
{
int i, j;
char *q;
if ( end_of_block(t, flags) )
return 0;
if ( !(is_flag_set(flags, MKD_NODLIST) || is_flag_set(flags, MKD_STRICT))
&& isdefinition(t,clip,list_type,flags) )
return DL;
if ( strchr("*-+", T(t->text)[t->dle]) && isspace(T(t->text)[t->dle+1]) ) {
i = nextnonblank(t, t->dle+1);
*clip = (i > 4) ? 4 : i;
*list_type = UL;
return is_flag_set(flags, MKD_EXPLICITLIST) ? UL : AL;
}
if ( (j = nextblank(t,t->dle)) > t->dle ) {
if ( T(t->text)[j-1] == '.' ) {
if ( !(is_flag_set(flags, MKD_NOALPHALIST) || is_flag_set(flags, MKD_STRICT))
&& (j == t->dle + 2)
&& isalpha(T(t->text)[t->dle]) ) {
j = nextnonblank(t,j);
*clip = (j > 4) ? 4 : j;
*list_type = AL;
return AL;
}
strtoul(T(t->text)+t->dle, &q, 10);
if ( (q > T(t->text)+t->dle) && (q == T(t->text) + (j-1)) ) {
j = nextnonblank(t,j);
*clip = j;
*list_type = OL;
return AL;
}
}
}
return 0;
}
static Line *
headerblock(Paragraph *pp, int htyp)
{
Line *ret = 0;
Line *p = pp->text;
int i, j;
switch (htyp) {
case SETEXT:
/* p->text is header, p->next->text is -'s or ='s
*/
pp->hnumber = (T(p->next->text)[0] == '=') ? 1 : 2;
ret = p->next->next;
___mkd_freeLine(p->next);
p->next = 0;
break;
case ETX:
/* p->text is ###header###, so we need to trim off
* the leading and trailing `#`'s
*/
for (i=0; (T(p->text)[i] == T(p->text)[0]) && (i < S(p->text)-1)
&& (i < 6); i++)
;
pp->hnumber = i;
while ( (i < S(p->text)) && isspace(T(p->text)[i]) )
++i;
CLIP(p->text, 0, i);
UNCHECK(p);
for (j=S(p->text); (j > 1) && (T(p->text)[j-1] == '#'); --j)
;
while ( j && isspace(T(p->text)[j-1]) )
--j;
S(p->text) = j;
ret = p->next;
p->next = 0;
break;
}
return ret;
}
static Line *
codeblock(Paragraph *p)
{
Line *t = p->text, *r;
for ( ; t; t = r ) {
__mkd_trim_line(t,4);
if ( !( (r = skipempty(t->next)) && iscode(r)) ) {
___mkd_freeLineRange(t,r);
t->next = 0;
return r;
}
}
return t;
}
static int
iscodefence(Line *r, int size, line_type kind, mkd_flag_t flags)
{
if ( !is_flag_set(flags, MKD_FENCEDCODE) )
return 0;
if ( !(r->flags & CHECKED) )
checkline(r, flags);
if ( kind )
return (r->kind == kind) && (r->count >= size);
else
return (r->kind == chk_tilde || r->kind == chk_backtick) && (r->count >= size);
}
static Paragraph *
fencedcodeblock(ParagraphRoot *d, Line **ptr, mkd_flag_t flags)
{
Line *first, *r;
Paragraph *ret;
first = (*ptr);
/* don't allow zero-length code fences
*/
if ( (first->next == 0) || iscodefence(first->next, first->count, 0, flags) )
return 0;
/* find the closing fence, discard the fences,
* return a Paragraph with the contents
*/
for ( r = first; r && r->next; r = r->next )
if ( iscodefence(r->next, first->count, first->kind, flags) ) {
(*ptr) = r->next->next;
ret = Pp(d, first->next, CODE);
if (S(first->text) - first->count > 0) {
char *lang_attr = T(first->text) + first->count;
while ( *lang_attr != 0 && *lang_attr == ' ' ) lang_attr++;
ret->lang = strdup(lang_attr);
}
else {
ret->lang = 0;
}
___mkd_freeLine(first);
___mkd_freeLine(r->next);
r->next = 0;
return ret;
}
return 0;
}
static int
centered(Line *first, Line *last)
{
if ( first&&last ) {
int len = S(last->text);
if ( (len > 2) && (strncmp(T(first->text), "->", 2) == 0)
&& (strncmp(T(last->text)+len-2, "<-", 2) == 0) ) {
CLIP(first->text, 0, 2);
S(last->text) -= 2;
return CENTER;
}
}
return 0;
}
static int
endoftextblock(Line *t, int toplevelblock, mkd_flag_t flags)
{
int z;
if ( end_of_block(t, flags) || isquote(t) )
return 1;
/* HORRIBLE STANDARDS KLUDGES:
* 1. non-toplevel paragraphs absorb adjacent code blocks
* 2. Toplevel paragraphs eat absorb adjacent list items,
* but sublevel blocks behave properly.
* (What this means is that we only need to check for code
* blocks at toplevel, and only check for list items at
* nested levels.)
*/
return toplevelblock ? 0 : islist(t,&z,flags,&z);
}
static Line *
textblock(Paragraph *p, int toplevel, mkd_flag_t flags)
{
Line *t, *next;
for ( t = p->text; t ; t = next ) {
if ( ((next = t->next) == 0) || endoftextblock(next, toplevel, flags) ) {
p->align = centered(p->text, t);
t->next = 0;
return next;
}
}
return t;
}
/* length of the id: or class: kind in a special div-not-quote block
*/
static int
szmarkerclass(char *p)
{
if ( strncasecmp(p, "id:", 3) == 0 )
return 3;
if ( strncasecmp(p, "class:", 6) == 0 )
return 6;
return 0;
}
/*
* check if the first line of a quoted block is the special div-not-quote
* marker %[kind:]name%
*/
#define iscsschar(c) (isalpha(c) || (c == '-') || (c == '_') )
static int
isdivmarker(Line *p, int start, mkd_flag_t flags)
{
char *s;
int last, i;
if ( is_flag_set(flags, MKD_NODIVQUOTE) || is_flag_set(flags, MKD_STRICT) )
return 0;
start = nextnonblank(p, start);
last= S(p->text) - (1 + start);
s = T(p->text) + start;
if ( (last <= 0) || (*s != '%') || (s[last] != '%') )
return 0;
i = szmarkerclass(s+1);
if ( !iscsschar(s[i+1]) )
return 0;
while ( ++i < last )
if ( !(isdigit(s[i]) || iscsschar(s[i])) )
return 0;
return 1;
}
/*
* accumulate a blockquote.
*
* one sick horrible thing about blockquotes is that even though
* it just takes ^> to start a quote, following lines, if quoted,
* assume that the prefix is ``> ''. This means that code needs
* to be indented *5* spaces from the leading '>', but *4* spaces
* from the start of the line. This does not appear to be
* documented in the reference implementation, but it's the
* way the markdown sample web form at Daring Fireball works.
*/
static Line *
quoteblock(Paragraph *p, mkd_flag_t flags)
{
Line *t, *q;
int qp;
for ( t = p->text; t ; t = q ) {
if ( isquote(t) ) {
/* clip leading spaces */
for (qp = 0; T(t->text)[qp] != '>'; qp ++)
/* assert: the first nonblank character on this line
* will be a >
*/;
/* clip '>' */
qp++;
/* clip next space, if any */
if ( T(t->text)[qp] == ' ' )
qp++;
__mkd_trim_line(t,qp);
UNCHECK(t);
}
q = skipempty(t->next);
if ( (q == 0) || ((q != t->next) && (!isquote(q) || isdivmarker(q,1,flags))) ) {
___mkd_freeLineRange(t, q);
t = q;
break;
}
}
if ( isdivmarker(p->text,0,flags) ) {
char *prefix = "class";
int i;
q = p->text;
p->text = p->text->next;
if ( (i = szmarkerclass(1+T(q->text))) == 3 )
/* and this would be an "%id:" prefix */
prefix="id";
if ( p->ident = malloc(4+strlen(prefix)+S(q->text)) )
sprintf(p->ident, "%s=\"%.*s\"", prefix, S(q->text)-(i+2),
T(q->text)+(i+1) );
___mkd_freeLine(q);
}
return t;
}
typedef int (*linefn)(Line *);
/*
* pull in a list block. A list block starts with a list marker and
* runs until the next list marker, the next non-indented paragraph,
* or EOF. You do not have to indent nonblank lines after the list
* marker, but multiple paragraphs need to start with a 4-space indent.
*/
static Line *
listitem(Paragraph *p, int indent, mkd_flag_t flags, linefn check)
{
Line *t, *q;
int clip = indent;
int z;
#ifdef GITHUB_CHECKBOX
int firstpara = 1;
int ischeck;
#define CHECK_NOT 0
#define CHECK_NO 1
#define CHECK_YES 2
#endif
for ( t = p->text; t ; t = q) {
UNCHECK(t);
__mkd_trim_line(t, clip);
#ifdef GITHUB_CHECKBOX
if ( firstpara ) {
ischeck = CHECK_NOT;
if ( strncmp(T(t->text)+t->dle, "[ ]", 3) == 0 )
ischeck = CHECK_NO;
else if ( strncasecmp(T(t->text)+t->dle, "[x]", 3) == 0 )
ischeck = CHECK_YES;
if ( ischeck != CHECK_NOT ) {
__mkd_trim_line(t, 3);
p->flags |= GITHUB_CHECK;
if ( ischeck == CHECK_YES )
p->flags |= IS_CHECKED;
}
firstpara = 0;
}
#endif
/* even though we had to trim a long leader off this item,
* the indent for trailing paragraphs is still 4...
*/
if (indent > 4) {
indent = 4;
}
if ( (q = skipempty(t->next)) == 0 ) {
___mkd_freeLineRange(t,q);
return 0;
}
/* after a blank line, the next block needs to start with a line
* that's indented 4(? -- reference implementation allows a 1
* character indent, but that has unfortunate side effects here)
* spaces, but after that the line doesn't need any indentation
*/
if ( q != t->next ) {
if (q->dle < indent) {
q = t->next;
t->next = 0;
return q;
}
/* indent at least 2, and at most as
* as far as the initial line was indented. */
indent = clip ? clip : 2;
}
if ( (q->dle < indent) && (ishr(q,flags) || islist(q,&z,flags,&z)
|| (check && (*check)(q)))
&& !issetext(q,&z,flags) ) {
q = t->next;
t->next = 0;
return q;
}
clip = (q->dle > indent) ? indent : q->dle;
}
return t;
}
static Line *
definition_block(Paragraph *top, int clip, MMIOT *f, int kind)
{
ParagraphRoot d = { 0, 0 };
Paragraph *p;
Line *q = top->text, *text = 0, *labels;
int z, para;
while (( labels = q )) {
if ( (q = isdefinition(labels, &z, &kind, f->flags)) == 0 )
break;
if ( (text = skipempty(q->next)) == 0 )
break;
if ( para = (text != q->next) )
___mkd_freeLineRange(q, text);
q->next = 0;
if ( kind == 1 /* discount dl */ )
for ( q = labels; q; q = q->next ) {
CLIP(q->text, 0, 1);
UNCHECK(q);
S(q->text)--;
}
dd_block:
p = Pp(&d, text, LISTITEM);
text = listitem(p, clip, f->flags, (kind==2) ? is_extra_dd : 0);
p->down = compile(p->text, 0, f);
p->text = labels; labels = 0;
if ( para && p->down ) p->down->align = PARA;
if ( (q = skipempty(text)) == 0 )
break;
if ( para = (q != text) ) {
Line anchor;
anchor.next = text;
___mkd_freeLineRange(&anchor,q);
text = q;
}
if ( kind == 2 && is_extra_dd(q) )
goto dd_block;
}
top->text = 0;
top->down = T(d);
return text;
}
static Line *
enumerated_block(Paragraph *top, int clip, MMIOT *f, int list_class)
{
ParagraphRoot d = { 0, 0 };
Paragraph *p;
Line *q = top->text, *text;
int para = 0, z;
while (( text = q )) {
p = Pp(&d, text, LISTITEM);
text = listitem(p, clip, f->flags, 0);
p->down = compile(p->text, 0, f);
p->text = 0;
if ( para && p->down ) p->down->align = PARA;
if ( (q = skipempty(text)) == 0
|| islist(q, &clip, f->flags, &z) != list_class )
break;
if ( para = (q != text) ) {
Line anchor;
anchor.next = text;
___mkd_freeLineRange(&anchor, q);
if ( p->down ) p->down->align = PARA;
}
}
top->text = 0;
top->down = T(d);
return text;
}
static int
tgood(char c)
{
switch (c) {
case '\'':
case '"': return c;
case '(': return ')';
}
return 0;
}
/*
* eat lines for a markdown extra footnote
*/
static Line *
extrablock(Line *p)
{
Line *np;
while ( p && p->next ) {
np = p->next;
if ( np->dle < 4 && np->dle < S(np->text) ) {
p->next = 0;
return np;
}
__mkd_trim_line(np,4);
p = np;
}
return 0;
}
/*
* add a new (image or link) footnote to the footnote table
*/
static Line*
addfootnote(Line *p, MMIOT* f)
{
int j, i;
int c;
Line *np = p->next;
Footnote *foot = &EXPAND(f->footnotes->note);
CREATE(foot->tag);
CREATE(foot->link);
CREATE(foot->title);
foot->text = 0;
foot->flags = foot->height = foot->width = 0;
/* keep the footnote label */
for (j=i=p->dle+1; T(p->text)[j] != ']'; j++)
EXPAND(foot->tag) = T(p->text)[j];
EXPAND(foot->tag) = 0;
S(foot->tag)--;
/* consume the closing ]: */
j = nextnonblank(p, j+2);
if ( is_flag_set(f->flags, MKD_EXTRA_FOOTNOTE) && (T(foot->tag)[0] == '^') ) {
/* markdown extra footnote: All indented lines past this point;
* the first line includes the footnote reference, so we need to
* snip that out as we go.
*/
foot->flags |= EXTRA_FOOTNOTE;
__mkd_trim_line(p,j);
np = extrablock(p);
foot->text = compile(p, 0, f);
return np;
}
while ( (j < S(p->text)) && !isspace(T(p->text)[j]) )
EXPAND(foot->link) = T(p->text)[j++];
EXPAND(foot->link) = 0;
S(foot->link)--;
j = nextnonblank(p,j);
if ( T(p->text)[j] == '=' ) {
sscanf(T(p->text)+j, "=%dx%d", &foot->width, &foot->height);
j = nextblank(p, j);
j = nextnonblank(p,j);
}
if ( (j >= S(p->text)) && np && np->dle && tgood(T(np->text)[np->dle]) ) {
___mkd_freeLine(p);
p = np;
np = p->next;
j = p->dle;
}
if ( (c = tgood(T(p->text)[j])) ) {
/* Try to take the rest of the line as a comment; read to
* EOL, then shrink the string back to before the final
* quote.
*/
++j; /* skip leading quote */
while ( j < S(p->text) )
EXPAND(foot->title) = T(p->text)[j++];
while ( S(foot->title) && T(foot->title)[S(foot->title)-1] != c )
--S(foot->title);
if ( S(foot->title) ) /* skip trailing quote */
--S(foot->title);
EXPAND(foot->title) = 0;
--S(foot->title);
}
___mkd_freeLine(p);
return np;
}
/*
* allocate a paragraph header, link it to the
* tail of the current document
*/
static Paragraph *
Pp(ParagraphRoot *d, Line *ptr, int typ)
{
Paragraph *ret = calloc(sizeof *ret, 1);
ret->text = ptr;
ret->typ = typ;
return ATTACH(*d, ret);
}
static Line*
consume(Line *ptr, int *eaten)
{
Line *next;
int blanks=0;
for (; ptr && blankline(ptr); ptr = next, blanks++ ) {
next = ptr->next;
___mkd_freeLine(ptr);
}
if ( ptr ) *eaten = blanks;
return ptr;
}
typedef ANCHOR(Line) Cache;
static void
uncache(Cache *cache, ParagraphRoot *d, MMIOT *f)
{
Paragraph *p;
if ( T(*cache) ) {
E(*cache)->next = 0;
p = Pp(d, 0, SOURCE);
p->down = compile(T(*cache), 1, f);
T(*cache) = E(*cache) = 0;
}
}
/*
* top-level compilation; break the document into
* style, html, and source blocks with footnote links
* weeded out.
*/
static Paragraph *
compile_document(Line *ptr, MMIOT *f)
{
ParagraphRoot d = { 0, 0 };
Cache source = { 0, 0 };
Paragraph *p = 0;
struct kw *tag;
int eaten, unclosed;
int previous_was_break = 1;
while ( ptr ) {
if ( !is_flag_set(f->flags, MKD_NOHTML) && (tag = isopentag(ptr)) ) {
int blocktype;
/* If we encounter a html/style block, compile and save all
* of the cached source BEFORE processing the html/style.
*/
uncache(&source, &d, f);
if (is_flag_set(f->flags, MKD_NOSTYLE) )
blocktype = HTML;
else
blocktype = strcmp(tag->id, "STYLE") == 0 ? STYLE : HTML;
p = Pp(&d, ptr, blocktype);
ptr = htmlblock(p, tag, &unclosed);
if ( unclosed ) {
p->typ = SOURCE;
p->down = compile(p->text, 1, f);
p->text = 0;
}
previous_was_break = 1;
}
else if ( isfootnote(ptr) ) {
/* footnotes, like cats, sleep anywhere; pull them
* out of the input stream and file them away for
* later processing
*/
ptr = consume(addfootnote(ptr, f), &eaten);
previous_was_break = 1;
}
else if ( previous_was_break && iscodefence(ptr,3,0,f->flags)) {
uncache(&source, &d, f);
if ( !fencedcodeblock(&d, &ptr, f->flags) ) /* just source */
goto attach;
}
else {
attach:
/* source; cache it up to wait for eof or the
* next html/style block
*/
ATTACH(source,ptr);
previous_was_break = blankline(ptr);
ptr = ptr->next;
}
}
/* if there's any cached source at EOF, compile
* it now.
*/
uncache(&source, &d, f);
return T(d);
}
static int
first_nonblank_before(Line *j, int dle)
{
return (j->dle < dle) ? j->dle : dle;
}
static int
actually_a_table(MMIOT *f, Line *pp)
{
Line *r;
int j;
int c;
/* tables need to be turned on */
if ( is_flag_set(f->flags, MKD_STRICT) || is_flag_set(f->flags, MKD_NOTABLES) )
return 0;
/* tables need three lines */
if ( !(pp && pp->next && pp->next->next) ) {
return 0;
}
/* all lines must contain |'s */
for (r = pp; r; r = r->next )
if ( !(r->flags & PIPECHAR) ) {
return 0;
}
/* if the header has a leading |, all lines must have leading |'s */
if ( T(pp->text)[pp->dle] == '|' ) {
for ( r = pp; r; r = r->next )
if ( T(r->text)[first_nonblank_before(r,pp->dle)] != '|' ) {
return 0;
}
}
/* second line must be only whitespace, -, |, or : */
r = pp->next;
for ( j=r->dle; j < S(r->text); ++j ) {
c = T(r->text)[j];
if ( !(isspace(c)||(c=='-')||(c==':')||(c=='|')) ) {
return 0;
}
}
return 1;
}
/*
* break a collection of markdown input into
* blocks of lists, code, html, and text to
* be marked up.
*/
static Paragraph *
compile(Line *ptr, int toplevel, MMIOT *f)
{
ParagraphRoot d = { 0, 0 };
Paragraph *p = 0;
Line *r;
int para = toplevel;
int blocks = 0;
int hdr_type, list_type, list_class, indent;
ptr = consume(ptr, ¶);
while ( ptr ) {
if ( iscode(ptr) ) {
p = Pp(&d, ptr, CODE);
if ( is_flag_set(f->flags, MKD_1_COMPAT) ) {
/* HORRIBLE STANDARDS KLUDGE: the first line of every block
* has trailing whitespace trimmed off.
*/
___mkd_tidy(&p->text->text);
}
ptr = codeblock(p);
}
else if ( iscodefence(ptr,3,0,f->flags) && (p=fencedcodeblock(&d, &ptr, f->flags)) )
/* yay, it's already done */ ;
else if ( ishr(ptr, f->flags) ) {
p = Pp(&d, 0, HR);
r = ptr;
ptr = ptr->next;
___mkd_freeLine(r);
}
else if ( list_class = islist(ptr, &indent, f->flags, &list_type) ) {
if ( list_class == DL ) {
p = Pp(&d, ptr, DL);
ptr = definition_block(p, indent, f, list_type);
}
else {
p = Pp(&d, ptr, list_type);
ptr = enumerated_block(p, indent, f, list_class);
}
}
else if ( isquote(ptr) ) {
p = Pp(&d, ptr, QUOTE);
ptr = quoteblock(p, f->flags);
p->down = compile(p->text, 1, f);
p->text = 0;
}
else if ( ishdr(ptr, &hdr_type, f->flags) ) {
p = Pp(&d, ptr, HDR);
ptr = headerblock(p, hdr_type);
}
else {
/* either markup or an html block element
*/
struct kw *tag;
int unclosed = 1;
p = Pp(&d, ptr, MARKUP); /* default to regular markup,
* then check if it's an html
* block. If it IS an html
* block, htmlblock() will
* populate this paragraph &
* all we need to do is reset
* the paragraph type to HTML,
* otherwise the paragraph
* remains empty and ready for
* processing with textblock()
*/
if ( !is_flag_set(f->flags, MKD_NOHTML) && (tag = isopentag(ptr)) ) {
/* possibly an html block
*/
ptr = htmlblock(p, tag, &unclosed);
if ( ! unclosed ) {
p->typ = HTML;
}
}
if ( unclosed ) {
ptr = textblock(p, toplevel, f->flags);
/* tables are a special kind of paragraph */
if ( actually_a_table(f, p->text) )
p->typ = TABLE;
}
}
if ( (para||toplevel) && !p->align )
p->align = PARA;
blocks++;
para = toplevel || (blocks > 1);
ptr = consume(ptr, ¶);
if ( para && !p->align )
p->align = PARA;
}
return T(d);
}
/*
* the guts of the markdown() function, ripped out so I can do
* debugging.
*/
/*
* prepare and compile `text`, returning a Paragraph tree.
*/
int
mkd_compile(Document *doc, mkd_flag_t flags)
{
if ( !doc )
return 0;
flags &= USER_FLAGS;
if ( doc->compiled ) {
if ( doc->ctx->flags == flags && !doc->dirty)
return 1;
else {
doc->compiled = doc->dirty = 0;
if ( doc->code)
___mkd_freeParagraph(doc->code);
if ( doc->ctx->footnotes )
___mkd_freefootnotes(doc->ctx);
}
}
doc->compiled = 1;
memset(doc->ctx, 0, sizeof(MMIOT) );
doc->ctx->ref_prefix= doc->ref_prefix;
doc->ctx->cb = &(doc->cb);
doc->ctx->flags = flags;
CREATE(doc->ctx->in);
doc->ctx->footnotes = malloc(sizeof doc->ctx->footnotes[0]);
doc->ctx->footnotes->reference = 0;
CREATE(doc->ctx->footnotes->note);
mkd_initialize();
doc->code = compile_document(T(doc->content), doc->ctx);
qsort(T(doc->ctx->footnotes->note), S(doc->ctx->footnotes->note),
sizeof T(doc->ctx->footnotes->note)[0],
(stfu)__mkd_footsort);
memset(&doc->content, 0, sizeof doc->content);
return 1;
}
rdiscount-2.2.7.3/ext/basename.c 0000644 0000041 0000041 00000001573 14571373162 016463 0 ustar www-data www-data /*
* mkdio -- markdown front end input functions
*
* Copyright (C) 2007 David L Parsons.
* The redistribution terms are provided in the COPYRIGHT file that must
* be distributed with this source code.
*/
#include "config.h"
#include
#include
#include
#include "mkdio.h"
#include "cstring.h"
#include "amalloc.h"
static char *
e_basename(const char *string, const int size, void *context)
{
char *ret;
char *base = (char*)context;
if ( base && string && (*string == '/') && (ret=malloc(strlen(base)+size+2)) ) {
strcpy(ret, base);
strncat(ret, string, size);
return ret;
}
return 0;
}
static void
e_free(char *string, void *context)
{
if ( string ) free(string);
}
void
mkd_basename(MMIOT *document, char *base)
{
mkd_e_url(document, e_basename);
mkd_e_data(document, base);
mkd_e_free(document, e_free);
}
rdiscount-2.2.7.3/ext/cstring.h 0000644 0000041 0000041 00000004551 14571373162 016365 0 ustar www-data www-data /* two template types: STRING(t) which defines a pascal-style string
* of element (t) [STRING(char) is the closest to the pascal string],
* and ANCHOR(t) which defines a baseplate that a linked list can be
* built up from. [The linked list /must/ contain a ->next pointer
* for linking the list together with.]
*/
#ifndef _CSTRING_D
#define _CSTRING_D
#include
#include
#ifndef __WITHOUT_AMALLOC
# include "amalloc.h"
#endif
/* expandable Pascal-style string.
*/
#define STRING(type) struct { type *text; int size, alloc; }
#define CREATE(x) ( (T(x) = (void*)0), (S(x) = (x).alloc = 0) )
#define EXPAND(x) (S(x)++)[(S(x) < (x).alloc) \
? (T(x)) \
: (T(x) = T(x) ? realloc(T(x), sizeof T(x)[0] * ((x).alloc += 100)) \
: malloc(sizeof T(x)[0] * ((x).alloc += 100)) )]
#define DELETE(x) ALLOCATED(x) ? (free(T(x)), S(x) = (x).alloc = 0) \
: ( S(x) = 0 )
#define CLIP(t,i,sz) \
S(t) -= ( ((i) >= 0) && ((sz) > 0) && (((i)+(sz)) <= S(t)) ) ? \
(memmove(&T(t)[i], &T(t)[i+sz], (S(t)-(i+sz)+1)*sizeof(T(t)[0])), \
(sz)) : 0
#define RESERVE(x, sz) T(x) = ((x).alloc > S(x) + (sz) \
? T(x) \
: T(x) \
? realloc(T(x), sizeof T(x)[0] * ((x).alloc = 100+(sz)+S(x))) \
: malloc(sizeof T(x)[0] * ((x).alloc = 100+(sz)+S(x))))
#define SUFFIX(t,p,sz) \
memcpy(((S(t) += (sz)) - (sz)) + \
(T(t) = T(t) ? realloc(T(t), sizeof T(t)[0] * ((t).alloc += sz)) \
: malloc(sizeof T(t)[0] * ((t).alloc += sz))), \
(p), sizeof(T(t)[0])*(sz))
#define PREFIX(t,p,sz) \
RESERVE( (t), (sz) ); \
if ( S(t) ) { memmove(T(t)+(sz), T(t), S(t)); } \
memcpy( T(t), (p), (sz) ); \
S(t) += (sz)
/* reference-style links (and images) are stored in an array
*/
#define T(x) (x).text
#define S(x) (x).size
#define ALLOCATED(x) (x).alloc
/* abstract anchor type that defines a list base
* with a function that attaches an element to
* the end of the list.
*
* the list base field is named .text so that the T()
* macro will work with it.
*/
#define ANCHOR(t) struct { t *text, *end; }
#define E(t) ((t).end)
#define ATTACH(t, p) ( T(t) ? ( (E(t)->next = (p)), (E(t) = (p)) ) \
: ( (T(t) = E(t) = (p)) ) )
typedef STRING(char) Cstring;
extern void Csputc(int, Cstring *);
extern int Csprintf(Cstring *, char *, ...);
extern int Cswrite(Cstring *, char *, int);
#endif/*_CSTRING_D*/
rdiscount-2.2.7.3/ext/blocktags 0000644 0000041 0000041 00000001261 14571373162 016432 0 ustar www-data www-data static struct kw blocktags[] = {
{ "P", 1, 0 },
{ "DL", 2, 0 },
{ "H1", 2, 0 },
{ "H2", 2, 0 },
{ "H3", 2, 0 },
{ "H4", 2, 0 },
{ "H5", 2, 0 },
{ "H6", 2, 0 },
{ "HR", 2, 1 },
{ "OL", 2, 0 },
{ "UL", 2, 0 },
{ "BDO", 3, 0 },
{ "DFN", 3, 0 },
{ "DIV", 3, 0 },
{ "MAP", 3, 0 },
{ "PRE", 3, 0 },
{ "WBR", 3, 0 },
{ "XMP", 3, 0 },
{ "FORM", 4, 0 },
{ "NOBR", 4, 0 },
{ "STYLE", 5, 0 },
{ "TABLE", 5, 0 },
{ "CENTER", 6, 0 },
{ "IFRAME", 6, 0 },
{ "OBJECT", 6, 0 },
{ "SCRIPT", 6, 0 },
{ "ADDRESS", 7, 0 },
{ "LISTING", 7, 0 },
{ "PLAINTEXT", 9, 0 },
{ "BLOCKQUOTE", 10, 0 },
};
#define NR_blocktags 30
rdiscount-2.2.7.3/ext/version.c 0000644 0000041 0000041 00000000261 14571373162 016366 0 ustar www-data www-data #include "config.h"
char markdown_version[] = BRANCH VERSION
#if 4 != 4
" TAB=4"
#endif
#if USE_AMALLOC
" DEBUG"
#endif
#if GITHUB_CHECKBOX
" GITHUB_CHECKBOX"
#endif
;
rdiscount-2.2.7.3/ext/notspecial.c 0000644 0000041 0000041 00000001334 14571373162 017044 0 ustar www-data www-data /*
* check a filename to see if it's a (fifo|character special|socket) object
* (if a stat() function doesn't exist, we can't stat so we'll just return
* true no matter what.)
*/
#include "config.h"
#if HAVE_STAT && HAS_ISCHR && HAS_ISFIFO && HAS_ISSOCK
#include
int
notspecial(char *file)
{
struct stat info;
if ( stat(file, &info) != 0 )
return 1;
return !( S_ISCHR(info.st_mode) || S_ISFIFO(info.st_mode) || S_ISSOCK(info.st_mode) );
}
#else
int
notspecial(char *file)
{
return 1;
}
#endif
#if DEBUG
#include
int
main(argc, argv)
char **argv;
{
int i;
for ( i=1; i < argc; i++ )
printf("%s is %sspecial\n", argv[i], notspecial(argv[i]) ? "not " : "");
}
#endif
rdiscount-2.2.7.3/ext/tags.h 0000644 0000041 0000041 00000000506 14571373162 015646 0 ustar www-data www-data /* block-level tags for passing html blocks through the blender
*/
#ifndef _TAGS_D
#define _TAGS_D
struct kw {
char *id;
int size;
int selfclose;
} ;
struct kw* mkd_search_tags(char *, int);
void mkd_prepare_tags();
void mkd_deallocate_tags();
void mkd_sort_tags();
void mkd_define_tag(char *, int);
#endif
rdiscount-2.2.7.3/ext/markdown.h 0000644 0000041 0000041 00000017511 14571373162 016536 0 ustar www-data www-data #ifndef _MARKDOWN_D
#define _MARKDOWN_D
#include "config.h"
#include "cstring.h"
#ifdef HAVE_INTTYPES_H
# include
#elif HAVE_STDINT_H
# include
#endif
/* flags, captured into a named type
*/
typedef DWORD mkd_flag_t;
#define is_flag_set(flags, item) ((flags) & (item))
#define set_flag(flags, item) ((flags) |= (item))
#define clear_flag(flags, item) ((flags) &= ~(item))
/* each input line is read into a Line, which contains the line,
* the offset of the first non-space character [this assumes
* that all tabs will be expanded to spaces!], and a pointer to
* the next line.
*/
typedef enum { chk_text, chk_code,
chk_hr, chk_dash,
chk_tilde, chk_backtick,
chk_equal } line_type;
typedef struct line {
Cstring text;
struct line *next;
int dle; /* leading indent on the line */
int flags; /* special attributes for this line */
#define PIPECHAR 0x01 /* line contains a | */
#define CHECKED 0x02
line_type kind;
int count;
} Line;
/* a paragraph is a collection of Lines, with links to the next paragraph
* and (if it's a QUOTE, UL, or OL) to the reparsed contents of this
* paragraph.
*/
typedef struct paragraph {
struct paragraph *next; /* next paragraph */
struct paragraph *down; /* recompiled contents of this paragraph */
struct line *text; /* all the text in this paragraph */
char *ident; /* %id% tag for QUOTE */
char *lang; /* lang attribute for CODE */
enum { WHITESPACE=0, CODE, QUOTE, MARKUP,
HTML, STYLE, DL, UL, OL, AL, LISTITEM,
HDR, HR, TABLE, SOURCE } typ;
enum { IMPLICIT=0, PARA, CENTER} align;
int hnumber; /* for typ == HDR */
#if GITHUB_CHECKBOX
int flags;
#define GITHUB_CHECK 0x01
#define IS_CHECKED 0x02
#endif
} Paragraph;
enum { ETX, SETEXT }; /* header types */
/* reference-style links (and images) are stored in an array
* of footnotes.
*/
typedef struct footnote {
Cstring tag; /* the tag for the reference link */
Cstring link; /* what this footnote points to */
Cstring title; /* what it's called (TITLE= attribute) */
Paragraph *text; /* EXTRA_FOOTNOTE content */
int height, width; /* dimensions (for image link) */
int dealloc; /* deallocation needed? */
int refnumber;
int flags;
#define EXTRA_FOOTNOTE 0x01
#define REFERENCED 0x02
} Footnote;
typedef struct block {
enum { bTEXT, bSTAR, bUNDER } b_type;
int b_count;
char b_char;
Cstring b_text;
Cstring b_post;
} block;
typedef STRING(block) Qblock;
typedef char* (*mkd_callback_t)(const char*, const int, void*);
typedef void (*mkd_free_t)(char*, void*);
typedef struct callback_data {
void *e_data; /* private data for callbacks */
mkd_callback_t e_url; /* url edit callback */
mkd_callback_t e_flags; /* extra href flags callback */
mkd_callback_t e_anchor; /* callback for anchor types */
mkd_free_t e_free; /* edit/flags callback memory deallocator */
mkd_callback_t e_codefmt; /* codeblock formatter (for highlighting) */
} Callback_data;
struct escaped {
char *text;
struct escaped *up;
} ;
struct footnote_list {
int reference;
STRING(Footnote) note;
} ;
/* a magic markdown io thing holds all the data structures needed to
* do the backend processing of a markdown document
*/
typedef struct mmiot {
Cstring out;
Cstring in;
Qblock Q;
char last; /* last text character added to out */
int isp;
struct escaped *esc;
char *ref_prefix;
struct footnote_list *footnotes;
mkd_flag_t flags;
#define MKD_NOLINKS 0x00000001
#define MKD_NOIMAGE 0x00000002
#define MKD_NOPANTS 0x00000004
#define MKD_NOHTML 0x00000008
#define MKD_STRICT 0x00000010
#define MKD_TAGTEXT 0x00000020
#define MKD_NO_EXT 0x00000040
#define MKD_CDATA 0x00000080
#define MKD_NOSUPERSCRIPT 0x00000100
#define MKD_NORELAXED 0x00000200
#define MKD_NOTABLES 0x00000400
#define MKD_NOSTRIKETHROUGH 0x00000800
#define MKD_TOC 0x00001000
#define MKD_1_COMPAT 0x00002000
#define MKD_AUTOLINK 0x00004000
#define MKD_SAFELINK 0x00008000
#define MKD_NOHEADER 0x00010000
#define MKD_TABSTOP 0x00020000
#define MKD_NODIVQUOTE 0x00040000
#define MKD_NOALPHALIST 0x00080000
#define MKD_NODLIST 0x00100000
#define MKD_EXTRA_FOOTNOTE 0x00200000
#define MKD_NOSTYLE 0x00400000
#define MKD_NODLDISCOUNT 0x00800000
#define MKD_DLEXTRA 0x01000000
#define MKD_FENCEDCODE 0x02000000
#define MKD_IDANCHOR 0x04000000
#define MKD_GITHUBTAGS 0x08000000
#define MKD_URLENCODEDANCHOR 0x10000000
#define IS_LABEL 0x20000000
#define MKD_LATEX 0x40000000
#define MKD_EXPLICITLIST 0x80000000
#define USER_FLAGS 0xFFFFFFFF
#define INPUT_MASK (MKD_NOHEADER|MKD_TABSTOP)
Callback_data *cb;
} MMIOT;
#define MKD_EOLN '\r'
/*
* the mkdio text input functions return a document structure,
* which contains a header (retrieved from the document if
* markdown was configured * with the * --enable-pandoc-header
* and the document begins with a pandoc-style header) and the
* root of the linked list of Lines.
*/
typedef struct document {
int magic; /* "I AM VALID" magic number */
#define VALID_DOCUMENT 0x19600731
Line *title;
Line *author;
Line *date;
ANCHOR(Line) content; /* uncompiled text, not valid after compile() */
Paragraph *code; /* intermediate code generated by compile() */
int compiled; /* set after mkd_compile() */
int dirty; /* flags or callbacks changed */
int html; /* set after (internal) htmlify() */
int tabstop; /* for properly expanding tabs (ick) */
char *ref_prefix;
MMIOT *ctx; /* backend buffers, flags, and structures */
Callback_data cb; /* callback functions & private data */
} Document;
/*
* economy FILE-type structure for pulling characters out of a
* fixed-length string.
*/
struct string_stream {
const char *data; /* the unread data */
int size; /* and how much is there? */
} ;
extern int mkd_firstnonblank(Line *);
extern int mkd_compile(Document *, mkd_flag_t);
extern int mkd_document(Document *, char **);
extern int mkd_generatehtml(Document *, FILE *);
extern int mkd_css(Document *, char **);
extern int mkd_generatecss(Document *, FILE *);
#define mkd_style mkd_generatecss
extern int mkd_xml(char *, int , char **);
extern int mkd_generatexml(char *, int, FILE *);
extern void mkd_cleanup(Document *);
extern int mkd_line(char *, int, char **, mkd_flag_t);
extern int mkd_generateline(char *, int, FILE*, mkd_flag_t);
#define mkd_text mkd_generateline
extern void mkd_basename(Document*, char *);
typedef int (*mkd_sta_function_t)(const int,const void*);
extern void mkd_string_to_anchor(char*,int, mkd_sta_function_t, void*, int, MMIOT *);
extern Document *mkd_in(FILE *, mkd_flag_t);
extern Document *mkd_string(const char*, int, mkd_flag_t);
extern Document *gfm_in(FILE *, mkd_flag_t);
extern Document *gfm_string(const char*,int, mkd_flag_t);
extern void mkd_initialize();
extern void mkd_shlib_destructor();
extern void mkd_ref_prefix(Document*, char*);
/* internal resource handling functions.
*/
extern void ___mkd_freeLine(Line *);
extern void ___mkd_freeLines(Line *);
extern void ___mkd_freeParagraph(Paragraph *);
extern void ___mkd_freefootnote(Footnote *);
extern void ___mkd_freefootnotes(MMIOT *);
extern void ___mkd_initmmiot(MMIOT *, void *);
extern void ___mkd_freemmiot(MMIOT *, void *);
extern void ___mkd_freeLineRange(Line *, Line *);
extern void ___mkd_xml(char *, int, FILE *);
extern void ___mkd_reparse(char *, int, mkd_flag_t, MMIOT*, char*);
extern void ___mkd_emblock(MMIOT*);
extern void ___mkd_tidy(Cstring *);
extern Document *__mkd_new_Document();
extern void __mkd_enqueue(Document*, Cstring *);
extern void __mkd_trim_line(Line *, int);
extern int __mkd_io_strget(struct string_stream *);
/* utility function to do some operation and exit the current function
* if it fails
*/
#define DO_OR_DIE(op) if ( (op) == EOF ) return EOF; else 1
#endif/*_MARKDOWN_D*/
rdiscount-2.2.7.3/ext/pgm_options.h 0000644 0000041 0000041 00000000273 14571373162 017247 0 ustar www-data www-data #ifndef PGM_OPTIONS_D
#define PGM_OPTIONS_D
#include
char *set_flag(mkd_flag_t *flags, char *optionstring);
void show_flags(int byname, int verbose);
#endif/*PGM_OPTIONS_D*/
rdiscount-2.2.7.3/ext/html5.c 0000644 0000041 0000041 00000000641 14571373162 015734 0 ustar www-data www-data /* block-level tags for passing html5 blocks through the blender
*/
#include "tags.h"
void
mkd_with_html5_tags()
{
static int populated = 0;
if ( populated ) return;
populated = 1;
mkd_define_tag("ASIDE", 0);
mkd_define_tag("FOOTER", 0);
mkd_define_tag("HEADER", 0);
mkd_define_tag("NAV", 0);
mkd_define_tag("SECTION", 0);
mkd_define_tag("ARTICLE", 0);
mkd_sort_tags();
}
rdiscount-2.2.7.3/ext/github_flavoured.c 0000644 0000041 0000041 00000004314 14571373162 020235 0 ustar www-data www-data
/*
* github_flavoured -- implement the obnoxious "returns are hard newlines"
* feature in github flavoured markdown.
*
* Copyright (C) 2012 David L Parsons.
* The redistribution terms are provided in the COPYRIGHT file that must
* be distributed with this source code.
*/
#include "config.h"
#include
#include
#include
#include "cstring.h"
#include "markdown.h"
#include "amalloc.h"
/* build a Document from any old input.
*/
typedef int (*getc_func)(void*);
Document *
gfm_populate(getc_func getc, void* ctx, int flags)
{
Cstring line;
Document *a = __mkd_new_Document();
int c;
int pandoc = 0;
if ( !a ) return 0;
a->tabstop = is_flag_set(flags, MKD_TABSTOP) ? 4 : TABSTOP;
CREATE(line);
while ( (c = (*getc)(ctx)) != EOF ) {
if ( c == '\n' ) {
if ( pandoc != EOF && pandoc < 3 ) {
if ( S(line) && (T(line)[0] == '%') )
pandoc++;
else
pandoc = EOF;
}
if (pandoc == EOF) {
EXPAND(line) = ' ';
EXPAND(line) = ' ';
}
__mkd_enqueue(a, &line);
S(line) = 0;
}
else if ( isprint(c) || isspace(c) || (c & 0x80) )
EXPAND(line) = c;
}
if ( S(line) )
__mkd_enqueue(a, &line);
DELETE(line);
if ( (pandoc == 3) && !(is_flag_set(flags, MKD_NOHEADER)
|| is_flag_set(flags, MKD_STRICT)) ) {
/* the first three lines started with %, so we have a header.
* clip the first three lines out of content and hang them
* off header.
*/
Line *headers = T(a->content);
a->title = headers; __mkd_trim_line(a->title, 1);
a->author= headers->next; __mkd_trim_line(a->author, 1);
a->date = headers->next->next; __mkd_trim_line(a->date, 1);
T(a->content) = headers->next->next->next;
}
return a;
}
/* convert a block of text into a linked list
*/
Document *
gfm_string(const char *buf, int len, mkd_flag_t flags)
{
struct string_stream about;
about.data = buf;
about.size = len;
return gfm_populate((getc_func)__mkd_io_strget, &about, flags & INPUT_MASK);
}
/* convert a file into a linked list
*/
Document *
gfm_in(FILE *f, mkd_flag_t flags)
{
return gfm_populate((getc_func)fgetc, f, flags & INPUT_MASK);
}
rdiscount-2.2.7.3/ext/amalloc.h 0000644 0000041 0000041 00000000754 14571373162 016325 0 ustar www-data www-data /*
* debugging malloc()/realloc()/calloc()/free() that attempts
* to keep track of just what's been allocated today.
*/
#ifndef AMALLOC_D
#define AMALLOC_D
#include "config.h"
#ifdef USE_AMALLOC
extern void *amalloc(int);
extern void *acalloc(int,int);
extern void *arealloc(void*,int);
extern void afree(void*);
extern void adump();
#define malloc amalloc
#define calloc acalloc
#define realloc arealloc
#define free afree
#else
#define adump() (void)1
#endif
#endif/*AMALLOC_D*/
rdiscount-2.2.7.3/ext/resource.c 0000644 0000041 0000041 00000005407 14571373162 016537 0 ustar www-data www-data /* markdown: a C implementation of John Gruber's Markdown markup language.
*
* Copyright (C) 2007 David L Parsons.
* The redistribution terms are provided in the COPYRIGHT file that must
* be distributed with this source code.
*/
#include
#include
#include
#include
#include
#include
#include "config.h"
#include "cstring.h"
#include "markdown.h"
#include "amalloc.h"
/* free a (single) line
*/
void
___mkd_freeLine(Line *ptr)
{
DELETE(ptr->text);
free(ptr);
}
/* free a list of lines
*/
void
___mkd_freeLines(Line *p)
{
if (p->next)
___mkd_freeLines(p->next);
___mkd_freeLine(p);
}
/* bye bye paragraph.
*/
void
___mkd_freeParagraph(Paragraph *p)
{
if (p->next)
___mkd_freeParagraph(p->next);
if (p->down)
___mkd_freeParagraph(p->down);
if (p->text)
___mkd_freeLines(p->text);
if (p->ident)
free(p->ident);
if (p->lang)
free(p->lang);
free(p);
}
/* bye bye footnote.
*/
void
___mkd_freefootnote(Footnote *f)
{
DELETE(f->tag);
DELETE(f->link);
DELETE(f->title);
if ( f->text) ___mkd_freeParagraph(f->text);
}
/* bye bye footnotes.
*/
void
___mkd_freefootnotes(MMIOT *f)
{
int i;
if ( f->footnotes ) {
for (i=0; i < S(f->footnotes->note); i++)
___mkd_freefootnote( &T(f->footnotes->note)[i] );
DELETE(f->footnotes->note);
free(f->footnotes);
}
}
/* initialize a new MMIOT
*/
void
___mkd_initmmiot(MMIOT *f, void *footnotes)
{
if ( f ) {
memset(f, 0, sizeof *f);
CREATE(f->in);
CREATE(f->out);
CREATE(f->Q);
if ( footnotes )
f->footnotes = footnotes;
else {
f->footnotes = malloc(sizeof f->footnotes[0]);
CREATE(f->footnotes->note);
}
}
}
/* free the contents of a MMIOT, but leave the object alone.
*/
void
___mkd_freemmiot(MMIOT *f, void *footnotes)
{
if ( f ) {
DELETE(f->in);
DELETE(f->out);
DELETE(f->Q);
if ( f->footnotes != footnotes )
___mkd_freefootnotes(f);
memset(f, 0, sizeof *f);
}
}
/* free lines up to an barrier.
*/
void
___mkd_freeLineRange(Line *anchor, Line *stop)
{
Line *r = anchor->next;
if ( r != stop ) {
while ( r && (r->next != stop) )
r = r->next;
if ( r ) r->next = 0;
___mkd_freeLines(anchor->next);
}
anchor->next = 0;
}
/* clean up everything allocated in __mkd_compile()
*/
void
mkd_cleanup(Document *doc)
{
if ( doc && (doc->magic == VALID_DOCUMENT) ) {
if ( doc->ctx ) {
___mkd_freemmiot(doc->ctx, 0);
free(doc->ctx);
}
if ( doc->code) ___mkd_freeParagraph(doc->code);
if ( doc->title) ___mkd_freeLine(doc->title);
if ( doc->author) ___mkd_freeLine(doc->author);
if ( doc->date) ___mkd_freeLine(doc->date);
if ( T(doc->content) ) ___mkd_freeLines(T(doc->content));
memset(doc, 0, sizeof doc[0]);
free(doc);
}
}
rdiscount-2.2.7.3/ext/toc.c 0000644 0000041 0000041 00000005200 14571373162 015464 0 ustar www-data www-data /*
* toc -- spit out a table of contents based on header blocks
*
* Copyright (C) 2008 Jjgod Jiang, David L Parsons
* portions Copyright (C) 2011 Stefano D'Angelo
* The redistribution terms are provided in the COPYRIGHT file that must
* be distributed with this source code.
*/
#include "config.h"
#include
#include
#include
#include "cstring.h"
#include "markdown.h"
#include "amalloc.h"
static int Csputc_mkd_sta_function_t(const int n, const void* iot) {
Csputc(n, iot);
}
/* write an header index
*/
int
mkd_toc(Document *p, char **doc)
{
Paragraph *tp, *srcp;
int last_hnumber = 0;
Cstring res;
int size;
int first = 1;
extern void Csreparse(Cstring *, char *, int, mkd_flag_t);
if ( !(doc && p && p->ctx) ) return -1;
*doc = 0;
if ( ! is_flag_set(p->ctx->flags, MKD_TOC) ) return 0;
CREATE(res);
RESERVE(res, 100);
for ( tp = p->code; tp ; tp = tp->next ) {
if ( tp->typ == SOURCE ) {
for ( srcp = tp->down; srcp; srcp = srcp->next ) {
if ( (srcp->typ == HDR) && srcp->text ) {
while ( last_hnumber > srcp->hnumber ) {
if ( (last_hnumber - srcp->hnumber) > 1 )
Csprintf(&res, "\n");
Csprintf(&res, "\n%*s\n%*s",
last_hnumber-1, "", last_hnumber-1, "");
--last_hnumber;
}
if ( last_hnumber == srcp->hnumber )
Csprintf(&res, "\n");
else if ( (srcp->hnumber > last_hnumber) && !first )
Csprintf(&res, "\n");
while ( srcp->hnumber > last_hnumber ) {
Csprintf(&res, "%*s\n", last_hnumber, "");
if ( (srcp->hnumber - last_hnumber) > 1 )
Csprintf(&res, "%*s\n", last_hnumber+1, "");
++last_hnumber;
}
Csprintf(&res, "%*s hnumber, "");
mkd_string_to_anchor(T(srcp->text->text),
S(srcp->text->text),
Csputc_mkd_sta_function_t,
&res,1,p->ctx);
Csprintf(&res, "\">");
Csreparse(&res, T(srcp->text->text),
S(srcp->text->text), IS_LABEL);
Csprintf(&res, " ");
first = 0;
}
}
}
}
while ( last_hnumber > 0 ) {
--last_hnumber;
Csprintf(&res, " \n%*s \n%*s",
last_hnumber, "", last_hnumber, "");
}
if ( (size = S(res)) > 0 ) {
/* null-terminate & strdup into a free()able memory chunk
*/
EXPAND(res) = 0;
*doc = strdup(T(res));
}
DELETE(res);
return size;
}
/* write an header index
*/
int
mkd_generatetoc(Document *p, FILE *out)
{
char *buf = 0;
int sz = mkd_toc(p, &buf);
int ret = EOF;
if ( sz > 0 )
ret = fwrite(buf, 1, sz, out);
if ( buf ) free(buf);
return (ret == sz) ? ret : EOF;
}
rdiscount-2.2.7.3/ext/generate.c 0000644 0000041 0000041 00000124772 14571373162 016511 0 ustar www-data www-data /* markdown: a C implementation of John Gruber's Markdown markup language.
*
* Copyright (C) 2007 David L Parsons.
* The redistribution terms are provided in the COPYRIGHT file that must
* be distributed with this source code.
*/
#include
#include
#include
#include
#include
#include
#include "config.h"
#include "cstring.h"
#include "markdown.h"
#include "amalloc.h"
typedef int (*stfu)(const void*,const void*);
typedef void (*spanhandler)(MMIOT*,int);
/* forward declarations */
static void text(MMIOT *f);
static Paragraph *display(Paragraph*, MMIOT*);
/* externals from markdown.c */
int __mkd_footsort(Footnote *, Footnote *);
/*
* push text into the generator input buffer
*/
static void
push(char *bfr, int size, MMIOT *f)
{
while ( size-- > 0 )
EXPAND(f->in) = *bfr++;
}
/*
* push a character into the generator input buffer
*/
static void
pushc(char c, MMIOT *f)
{
EXPAND(f->in) = c;
}
/* look characters ahead of the cursor.
*/
static inline int
peek(MMIOT *f, int i)
{
i += (f->isp-1);
return (i >= 0) && (i < S(f->in)) ? (unsigned char)T(f->in)[i] : EOF;
}
/* pull a byte from the input buffer
*/
static inline unsigned int
pull(MMIOT *f)
{
return ( f->isp < S(f->in) ) ? (unsigned char)T(f->in)[f->isp++] : EOF;
}
/* return a pointer to the current position in the input buffer.
*/
static inline char*
cursor(MMIOT *f)
{
return T(f->in) + f->isp;
}
static inline int
isthisspace(MMIOT *f, int i)
{
int c = peek(f, i);
if ( c == EOF )
return 1;
if ( c & 0x80 )
return 0;
return isspace(c) || (c < ' ');
}
static inline int
isthisalnum(MMIOT *f, int i)
{
int c = peek(f, i);
return (c != EOF) && isalnum(c);
}
static inline int
isthisnonword(MMIOT *f, int i)
{
return isthisspace(f, i) || ispunct(peek(f,i));
}
/* return/set the current cursor position
* (when setting the current cursor position we also need to flush the
* last character written cache)
*/
#define mmiotseek(f,x) ((f->isp = x), (f->last = 0))
#define mmiottell(f) (f->isp)
/* move n characters forward ( or -n characters backward) in the input buffer.
*/
static void
shift(MMIOT *f, int i)
{
if (f->isp + i >= 0 )
f->isp += i;
}
/* Qchar()
*/
static void
Qchar(int c, MMIOT *f)
{
block *cur;
if ( S(f->Q) == 0 ) {
cur = &EXPAND(f->Q);
memset(cur, 0, sizeof *cur);
cur->b_type = bTEXT;
}
else
cur = &T(f->Q)[S(f->Q)-1];
EXPAND(cur->b_text) = c;
}
/* Qstring()
*/
static void
Qstring(char *s, MMIOT *f)
{
while (*s)
Qchar(*s++, f);
}
/* Qwrite()
*/
static void
Qwrite(char *s, int size, MMIOT *f)
{
while (size-- > 0)
Qchar(*s++, f);
}
/* Qprintf()
*/
static void
Qprintf(MMIOT *f, char *fmt, ...)
{
char bfr[80];
va_list ptr;
va_start(ptr,fmt);
vsnprintf(bfr, sizeof bfr, fmt, ptr);
va_end(ptr);
Qstring(bfr, f);
}
static int Qchar_mkd_sta_function_t(const int n, const void* iot) {
Qchar(n, iot);
}
/* Qanchor() prints out a suitable-for-id-tag version of a string
*/
static void
Qanchor(struct line *p, MMIOT *f)
{
mkd_string_to_anchor(T(p->text), S(p->text),
Qchar_mkd_sta_function_t, f, 1, f);
}
/* Qem()
*/
static void
Qem(MMIOT *f, char c, int count)
{
block *p = &EXPAND(f->Q);
memset(p, 0, sizeof *p);
p->b_type = (c == '*') ? bSTAR : bUNDER;
p->b_char = c;
p->b_count = count;
memset(&EXPAND(f->Q), 0, sizeof(block));
}
/* generate html from a markup fragment
*/
void
___mkd_reparse(char *bfr, int size, mkd_flag_t flags, MMIOT *f, char *esc)
{
MMIOT sub;
struct escaped e;
___mkd_initmmiot(&sub, f->footnotes);
sub.flags = f->flags | flags;
sub.cb = f->cb;
sub.ref_prefix = f->ref_prefix;
if ( esc ) {
sub.esc = &e;
e.up = f->esc;
e.text = esc;
}
else
sub.esc = f->esc;
push(bfr, size, &sub);
pushc(0, &sub);
S(sub.in)--;
text(&sub);
___mkd_emblock(&sub);
Qwrite(T(sub.out), S(sub.out), f);
/* inherit the last character printed from the reparsed
* text; this way superscripts can work when they're
* applied to something embedded in a link
*/
f->last = sub.last;
___mkd_freemmiot(&sub, f->footnotes);
}
/*
* check the escape list for special cases
*/
static int
escaped(MMIOT *f, char c)
{
struct escaped *thing = f->esc;
while ( thing ) {
if ( strchr(thing->text, c) )
return 1;
thing = thing->up;
}
return 0;
}
/*
* write out a url, escaping problematic characters
*/
static void
puturl(char *s, int size, MMIOT *f, int display)
{
unsigned char c;
while ( size-- > 0 ) {
c = *s++;
if ( c == '\\' && size-- > 0 ) {
c = *s++;
if ( !( ispunct(c) || isspace(c) ) )
Qchar('\\', f);
}
if ( c == '&' )
Qstring("&", f);
else if ( c == '<' )
Qstring("<", f);
else if ( c == '"' )
Qstring("%22", f);
else if ( isalnum(c) || ispunct(c) || (display && isspace(c)) )
Qchar(c, f);
else if ( c == MKD_EOLN ) /* untokenize hard return */
Qstring(" ", f);
else
Qprintf(f, "%%%02X", c);
}
}
/* advance forward until the next character is not whitespace
*/
static int
eatspace(MMIOT *f)
{
int c;
for ( ; ((c=peek(f, 1)) != EOF) && isspace(c); pull(f) )
;
return c;
}
/* (match (a (nested (parenthetical (string.)))))
*/
static int
parenthetical(int in, int out, MMIOT *f)
{
int size, indent, c;
for ( indent=1,size=0; indent; size++ ) {
if ( (c = pull(f)) == EOF )
return EOF;
else if ( (c == '\\') && (peek(f,1) == out || peek(f,1) == in) ) {
++size;
pull(f);
}
else if ( c == in )
++indent;
else if ( c == out )
--indent;
}
return size ? (size-1) : 0;
}
/* extract a []-delimited label from the input stream.
*/
static int
linkylabel(MMIOT *f, Cstring *res)
{
char *ptr = cursor(f);
int size;
if ( (size = parenthetical('[',']',f)) != EOF ) {
T(*res) = ptr;
S(*res) = size;
return 1;
}
return 0;
}
/* see if the quote-prefixed linky segment is actually a title.
*/
static int
linkytitle(MMIOT *f, char quote, Footnote *ref)
{
int whence = mmiottell(f);
char *title = cursor(f);
char *e;
register int c;
while ( (c = pull(f)) != EOF ) {
e = cursor(f);
if ( c == quote ) {
if ( (c = eatspace(f)) == ')' ) {
T(ref->title) = 1+title;
S(ref->title) = (e-title)-2;
return 1;
}
}
}
mmiotseek(f, whence);
return 0;
}
/* extract a =HHHxWWW size from the input stream
*/
static int
linkysize(MMIOT *f, Footnote *ref)
{
int height=0, width=0;
int whence = mmiottell(f);
int c;
if ( isspace(peek(f,0)) ) {
pull(f); /* eat '=' */
for ( c = pull(f); isdigit(c); c = pull(f))
width = (width * 10) + (c - '0');
if ( c == 'x' ) {
for ( c = pull(f); isdigit(c); c = pull(f))
height = (height*10) + (c - '0');
if ( isspace(c) )
c = eatspace(f);
if ( (c == ')') || ((c == '\'' || c == '"') && linkytitle(f, c, ref)) ) {
ref->height = height;
ref->width = width;
return 1;
}
}
}
mmiotseek(f, whence);
return 0;
}
/* extract a <...>-encased url from the input stream.
* (markdown 1.0.2b8 compatibility; older versions
* of markdown treated the < and > as syntactic
* sugar that didn't have to be there. 1.0.2b8
* requires a closing >, and then falls into the
* title or closing )
*/
static int
linkybroket(MMIOT *f, int image, Footnote *p)
{
int c;
int good = 0;
T(p->link) = cursor(f);
for ( S(p->link)=0; (c = pull(f)) != '>'; ++S(p->link) ) {
/* pull in all input until a '>' is found, or die trying.
*/
if ( c == EOF )
return 0;
else if ( (c == '\\') && ispunct(peek(f,2)) ) {
++S(p->link);
pull(f);
}
}
c = eatspace(f);
/* next nonspace needs to be a title, a size, or )
*/
if ( ( c == '\'' || c == '"' ) && linkytitle(f,c,p) )
good=1;
else if ( image && (c == '=') && linkysize(f,p) )
good=1;
else
good=( c == ')' );
if ( good ) {
if ( peek(f, 1) == ')' )
pull(f);
___mkd_tidy(&p->link);
}
return good;
} /* linkybroket */
/* extract a (-prefixed url from the input stream.
* the label is either of the format ` `, where I
* extract until I find a >, or it is of the format
* `text`, where I extract until I reach a ')', a quote,
* or (if image) a '='
*/
static int
linkyurl(MMIOT *f, int image, Footnote *p)
{
int c;
int mayneedtotrim=0;
if ( (c = eatspace(f)) == EOF )
return 0;
if ( c == '<' ) {
pull(f);
if ( !is_flag_set(f->flags, MKD_1_COMPAT) )
return linkybroket(f,image,p);
mayneedtotrim=1;
}
T(p->link) = cursor(f);
for ( S(p->link)=0; (c = peek(f,1)) != ')'; ++S(p->link) ) {
if ( c == EOF )
return 0;
else if ( (c == '"' || c == '\'') && linkytitle(f, c, p) )
break;
else if ( image && (c == '=') && linkysize(f, p) )
break;
else if ( (c == '\\') && ispunct(peek(f,2)) ) {
++S(p->link);
pull(f);
}
pull(f);
}
if ( peek(f, 1) == ')' )
pull(f);
___mkd_tidy(&p->link);
if ( mayneedtotrim && (T(p->link)[S(p->link)-1] == '>') )
--S(p->link);
return 1;
}
/* prefixes for
*/
static struct _protocol {
char *name;
int nlen;
} protocol[] = {
#define _aprotocol(x) { x, (sizeof x)-1 }
_aprotocol( "https:" ),
_aprotocol( "http:" ),
_aprotocol( "news:" ),
_aprotocol( "ftp:" ),
#undef _aprotocol
};
#define NRPROTOCOLS (sizeof protocol / sizeof protocol[0])
static int
isautoprefix(char *text, int size)
{
int i;
struct _protocol *p;
for (i=0, p=protocol; i < NRPROTOCOLS; i++, p++)
if ( (size >= p->nlen) && strncasecmp(text, p->name, p->nlen) == 0 )
return 1;
return 0;
}
/*
* all the tag types that linkylinky can produce are
* defined by this structure.
*/
typedef struct linkytype {
char *pat;
int szpat;
char *link_pfx; /* tag prefix and link pointer (eg: "" */
char *text_sfx; /* text suffix (eg: " " */
int flags; /* reparse flags */
int kind; /* tag is url or something else? */
#define IS_URL 0x01
} linkytype;
static linkytype imaget = { 0, 0, " ", MKD_NOIMAGE|MKD_TAGTEXT, IS_URL };
static linkytype linkt = { 0, 0, "", " ", MKD_NOLINKS, IS_URL };
/*
* pseudo-protocols for [][];
*
* id: generates tag
* class: generates tag
* raw: just dump the link without any processing
*/
static linkytype specials[] = {
{ "id:", 3, "", " ", 0, 0 },
{ "raw:", 4, 0, 0, 0, 0, 0, MKD_NOHTML, 0 },
{ "lang:", 5, "", " ", 0, 0 },
{ "abbr:", 5, "", " ", 0, 0 },
{ "class:", 6, "", " ", 0, 0 },
} ;
#define NR(x) (sizeof x / sizeof x[0])
/* see if t contains one of our pseudo-protocols.
*/
static linkytype *
pseudo(Cstring t)
{
int i;
linkytype *r;
for ( i=0, r=specials; i < NR(specials); i++,r++ ) {
if ( (S(t) > r->szpat) && (strncasecmp(T(t), r->pat, r->szpat) == 0) )
return r;
}
return 0;
}
/* print out the start of an `img' or `a' tag, applying callbacks as needed.
*/
static void
printlinkyref(MMIOT *f, linkytype *tag, char *link, int size)
{
char *edit;
if ( is_flag_set(f->flags, IS_LABEL) )
return;
Qstring(tag->link_pfx, f);
if ( tag->kind & IS_URL ) {
if ( f->cb && f->cb->e_url && (edit = (*f->cb->e_url)(link, size, f->cb->e_data)) ) {
puturl(edit, strlen(edit), f, 0);
if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data);
}
else
puturl(link + tag->szpat, size - tag->szpat, f, 0);
}
else
___mkd_reparse(link + tag->szpat, size - tag->szpat, MKD_TAGTEXT, f, 0);
Qstring(tag->link_sfx, f);
if ( f->cb && f->cb->e_flags && (edit = (*f->cb->e_flags)(link, size, f->cb->e_data)) ) {
Qchar(' ', f);
Qstring(edit, f);
if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data);
}
} /* printlinkyref */
/* helper function for php markdown extra footnotes; allow the user to
* define a prefix tag instead of just `fn`
*/
static char *
p_or_nothing(p)
MMIOT *p;
{
return p->ref_prefix ? p->ref_prefix : "fn";
}
/* php markdown extra/daring fireball style print footnotes
*/
static int
extra_linky(MMIOT *f, Cstring text, Footnote *ref)
{
if ( ref->flags & REFERENCED )
return 0;
if ( f->flags & IS_LABEL )
___mkd_reparse(T(text), S(text), linkt.flags, f, 0);
else {
ref->flags |= REFERENCED;
ref->refnumber = ++ f->footnotes->reference;
Qprintf(f, "%d ",
p_or_nothing(f), ref->refnumber,
p_or_nothing(f), ref->refnumber, ref->refnumber);
}
return 1;
} /* extra_linky */
/* check a url (or url fragment to see that it begins with a known good
* protocol (or no protocol at all)
*/
static int
safelink(Cstring link)
{
char *p, *colon;
if ( T(link) == 0 ) /* no link; safe */
return 1;
p = T(link);
if ( (colon = memchr(p, ':', S(link))) == 0 )
return 1; /* no protocol specified: safe */
if ( !isalpha(*p) ) /* protocol/method is [alpha][alnum or '+.-'] */
return 1;
while ( ++p < colon )
if ( !(isalnum(*p) || *p == '.' || *p == '+' || *p == '-') )
return 1;
return isautoprefix(T(link), S(link));
}
/* print out a linky (or fail if it's Not Allowed)
*/
static int
linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
{
linkytype *tag;
if ( image )
tag = &imaget;
else if ( tag = pseudo(ref->link) ) {
if ( is_flag_set(f->flags, MKD_NO_EXT) || is_flag_set(f->flags, MKD_SAFELINK) )
return 0;
}
else if ( is_flag_set(f->flags, MKD_SAFELINK) && !safelink(ref->link) )
/* if MKD_SAFELINK, only accept links that are local or
* a well-known protocol
*/
return 0;
else
tag = &linkt;
if ( f->flags & tag->flags )
return 0;
if ( is_flag_set(f->flags, IS_LABEL) )
___mkd_reparse(T(text), S(text), tag->flags, f, 0);
else if ( tag->link_pfx ) {
printlinkyref(f, tag, T(ref->link), S(ref->link));
if ( tag->WxH ) {
if ( ref->height ) Qprintf(f," height=\"%d\"", ref->height);
if ( ref->width ) Qprintf(f, " width=\"%d\"", ref->width);
}
if ( S(ref->title) ) {
Qstring(" title=\"", f);
___mkd_reparse(T(ref->title), S(ref->title), MKD_TAGTEXT, f, 0);
Qchar('"', f);
}
Qstring(tag->text_pfx, f);
___mkd_reparse(T(text), S(text), tag->flags, f, 0);
Qstring(tag->text_sfx, f);
}
else
Qwrite(T(ref->link) + tag->szpat, S(ref->link) - tag->szpat, f);
return 1;
} /* linkyformat */
/*
* process embedded links and images
*/
static int
linkylinky(int image, MMIOT *f)
{
int start = mmiottell(f);
Cstring name;
Footnote key, *ref;
int status = 0;
int extra_footnote = 0;
CREATE(name);
memset(&key, 0, sizeof key);
if ( linkylabel(f, &name) ) {
if ( peek(f,1) == '(' ) {
pull(f);
if ( linkyurl(f, image, &key) )
status = linkyformat(f, name, image, &key);
}
else {
int goodlink, implicit_mark = mmiottell(f);
if ( is_flag_set(f->flags, MKD_EXTRA_FOOTNOTE)
&& !is_flag_set(f->flags, MKD_STRICT)
&& (!image)
&& S(name)
&& T(name)[0] == '^' ) {
extra_footnote = 1;
goodlink = 1;
}
else {
if ( isspace(peek(f,1)) )
pull(f);
if ( peek(f,1) == '[' ) {
pull(f); /* consume leading '[' */
goodlink = linkylabel(f, &key.tag);
}
else {
/* new markdown implicit name syntax doesn't
* require a second []
*/
mmiotseek(f, implicit_mark);
goodlink = !is_flag_set(f->flags, MKD_1_COMPAT);
}
}
if ( goodlink ) {
if ( !S(key.tag) ) {
DELETE(key.tag);
T(key.tag) = T(name);
S(key.tag) = S(name);
}
if ( ref = bsearch(&key, T(f->footnotes->note),
S(f->footnotes->note),
sizeof key, (stfu)__mkd_footsort) ) {
if ( extra_footnote )
status = extra_linky(f,name,ref);
else
status = linkyformat(f, name, image, ref);
}
}
}
}
DELETE(name);
___mkd_freefootnote(&key);
if ( status == 0 )
mmiotseek(f, start);
return status;
}
/* write a character to output, doing text escapes ( & -> &,
* > -> > < -> < )
*/
static void
cputc(int c, MMIOT *f)
{
switch (c) {
case '&': Qstring("&", f); break;
case '>': Qstring(">", f); break;
case '<': Qstring("<", f); break;
default : Qchar(c, f); break;
}
}
/*
* convert an email address to a string of nonsense
*/
static void
mangle(char *s, int len, MMIOT *f)
{
while ( len-- > 0 ) {
#if DEBIAN_GLITCH
Qprintf(f, "%02d;", *((unsigned char*)(s++)) );
#else
Qstring("", f);
Qprintf(f, COINTOSS() ? "x%02x;" : "%02d;", *((unsigned char*)(s++)) );
#endif
}
}
/* nrticks() -- count up a row of tick marks
*/
static int
nrticks(int offset, int tickchar, MMIOT *f)
{
int tick = 0;
while ( peek(f, offset+tick) == tickchar ) tick++;
return tick;
} /* nrticks */
/* matchticks() -- match a certain # of ticks, and if that fails
* match the largest subset of those ticks.
*
* if a subset was matched, return the # of ticks
* that were matched.
*/
static int
matchticks(MMIOT *f, int tickchar, int ticks, int *endticks)
{
int size, count, c;
int subsize=0, subtick=0;
*endticks = ticks;
for (size = 0; (c=peek(f,size+ticks)) != EOF; size ++) {
if ( (c == tickchar) && ( count = nrticks(size+ticks,tickchar,f)) ) {
if ( count == ticks )
return size;
else if ( count ) {
if ( (count > subtick) && (count < ticks) ) {
subsize = size;
subtick = count;
}
size += count;
}
}
}
if ( subsize ) {
*endticks = subtick;
return subsize;
}
return 0;
} /* matchticks */
/* code() -- write a string out as code. The only characters that have
* special meaning in a code block are * `<' and `&' , which
* are /always/ expanded to < and &
*/
static void
code(MMIOT *f, char *s, int length)
{
int i,c;
for ( i=0; i < length; i++ )
if ( (c = s[i]) == MKD_EOLN) /* expand back to 2 spaces */
Qstring(" ", f);
else if ( c == '\\' && (i < length-1) && escaped(f, s[i+1]) )
cputc(s[++i], f);
else
cputc(c, f);
} /* code */
/* delspan() -- write out a chunk of text, blocking with ...
*/
static void
delspan(MMIOT *f, int size)
{
Qstring("", f);
___mkd_reparse(cursor(f)-1, size, 0, f, 0);
Qstring("", f);
}
#ifdef TYPORA
/* subspan() -- write out a chunk of text, blocking with ...
*/
static void
subspan(MMIOT *f, int size)
{
Qstring("", f);
___mkd_reparse(cursor(f)-1, size, 0, f, 0);
Qstring(" ", f);
}
/* supspan() -- write out a chunk of text, blocking with ...
*/
static void
supspan(MMIOT *f, int size)
{
Qstring("", f);
___mkd_reparse(cursor(f)-1, size, 0, f, 0);
Qstring(" ", f);
}
/* highlightspan() -- write out a chunk of text, blocking with ...
*/
static void
highlightspan(MMIOT *f, int size)
{
Qstring("", f);
___mkd_reparse(cursor(f)-1, size, 0, f, 0);
Qstring(" ", f);
}
#endif
/* codespan() -- write out a chunk of text as code, trimming one
* space off the front and/or back as appropriate.
*/
static void
codespan(MMIOT *f, int size)
{
int i=0;
if ( size > 1 && peek(f, size-1) == ' ' ) --size;
if ( peek(f,i) == ' ' ) ++i, --size;
Qstring("", f);
code(f, cursor(f)+(i-1), size);
Qstring("
", f);
} /* codespan */
/* before letting a tag through, validate against
* MKD_NOLINKS and MKD_NOIMAGE
*/
static int
forbidden_tag(MMIOT *f)
{
int c = toupper(peek(f, 1));
if ( is_flag_set(f->flags, MKD_NOHTML) )
return 1;
if ( c == 'A' && is_flag_set(f->flags, MKD_NOLINKS) && !isthisalnum(f,2) )
return 1;
if ( c == 'I' && is_flag_set(f->flags, MKD_NOIMAGE)
&& strncasecmp(cursor(f)+1, "MG", 2) == 0
&& !isthisalnum(f,4) )
return 1;
return 0;
}
/* Check a string to see if it looks like a mail address
* "looks like a mail address" means alphanumeric + some
* specials, then a `@`, then alphanumeric + some specials,
* but with a `.`
*/
static int
maybe_address(char *p, int size)
{
int ok = 0;
for ( ;size && (isalnum(*p) || strchr("._-+*", *p)); ++p, --size)
;
if ( ! (size && *p == '@') )
return 0;
--size, ++p;
if ( size && *p == '.' ) return 0;
for ( ;size && (isalnum(*p) || strchr("._-+", *p)); ++p, --size )
if ( *p == '.' && size > 1 ) ok = 1;
return size ? 0 : ok;
}
/* The size-length token at cursor(f) is either a mailto:, an
* implicit mailto:, one of the approved url protocols, or just
* plain old text. If it's a mailto: or an approved protocol,
* linkify it, otherwise say "no"
*/
static int
process_possible_link(MMIOT *f, int size)
{
int address= 0;
int mailto = 0;
char *text = cursor(f);
if ( is_flag_set(f->flags, MKD_NOLINKS) ) return 0;
if ( (size > 7) && strncasecmp(text, "mailto:", 7) == 0 ) {
/* if it says it's a mailto, it's a mailto -- who am
* I to second-guess the user?
*/
address = 1;
mailto = 7; /* 7 is the length of "mailto:"; we need this */
}
else
address = maybe_address(text, size);
if ( address ) {
Qstring("", f);
mangle(text+mailto, size-mailto, f);
Qstring(" ", f);
return 1;
}
else if ( isautoprefix(text, size) ) {
printlinkyref(f, &linkt, text, size);
Qchar('>', f);
puturl(text,size,f, 1);
Qstring("", f);
return 1;
}
return 0;
} /* process_possible_link */
/*
* check if a character is one of the things the reference implementation considers valid for starting
* a html(ish) tag
*/
static inline int
is_a_strict_tag_prefix(int c)
{
return isalpha(c) || (c == '/') || (c == '!') || (c == '$') || (c == '?');
}
/* a < may be just a regular character, the start of an embedded html
* tag, or the start of an . If it's an automatic
* link, we also need to know if it's an email address because if it
* is we need to mangle it in our futile attempt to cut down on the
* spaminess of the rendered page.
*/
static int
maybe_tag_or_link(MMIOT *f)
{
int c, size=0;
if ( is_flag_set(f->flags, MKD_TAGTEXT) )
return 0;
c = peek(f, 1);
if ( is_a_strict_tag_prefix(c) ) {
/* By decree of Markdown.pl *this is a tag* and we want to absorb everything up
* to the next '>', unless interrupted by another '<' OR a '`', at which point
* we kick it back to the caller as plain old text.
*/
size=1;
while ( (c=peek(f,size+1)) != '>' ) {
if ( c == EOF || c == '<' )
return 0;
if ( is_flag_set(f->flags, MKD_STRICT) ) {
if ( c == '`' )
return 0;
}
size++;
}
}
if ( size > 0 ) {
if ( process_possible_link(f, size) ) {
shift(f, size+1);
return 1;
}
else {
int i;
if ( forbidden_tag(f) )
return 0;
for ( i=0; i <= size+1; i++ ) {
c = peek(f,i);
if ( (c == '&') && (i > 0) )
Qstring("&", f);
else
Qchar(c, f);
}
shift(f, size+1);
return 1;
}
}
return 0;
}
/* autolinking means that all inline html is . A
* autolink url is alphanumerics, slashes, periods, underscores,
* the at sign, colon, and the % character.
*/
static int
maybe_autolink(MMIOT *f)
{
register int c;
int size;
/* greedily scan forward for the end of a legitimate link.
*/
for ( size=0; (c=peek(f, size+1)) != EOF; size++ ) {
if ( c == '\\' ) {
if ( peek(f, size+2) != EOF )
++size;
}
else if ( c & 0x80 ) /* HACK: ignore utf-8 extended characters */
continue;
else if ( isspace(c) || strchr("'\"()[]{}<>`", c) || c == MKD_EOLN )
break;
}
if ( (size > 1) && process_possible_link(f, size) ) {
shift(f, size);
return 1;
}
return 0;
}
/* smartyquote code that's common for single and double quotes
*/
static int
smartyquote(int *flags, char typeofquote, MMIOT *f)
{
int bit = (typeofquote == 's') ? 0x01 : 0x02;
if ( bit & (*flags) ) {
if ( isthisnonword(f,1) ) {
Qprintf(f, "&r%cquo;", typeofquote);
(*flags) &= ~bit;
return 1;
}
}
else if ( isthisnonword(f,-1) && peek(f,1) != EOF ) {
Qprintf(f, "&l%cquo;", typeofquote);
(*flags) |= bit;
return 1;
}
return 0;
}
static int
islike(MMIOT *f, char *s)
{
int len;
int i;
if ( s[0] == '|' ) {
if ( !isthisnonword(f, -1) )
return 0;
++s;
}
if ( !(len = strlen(s)) )
return 0;
if ( s[len-1] == '|' ) {
if ( !isthisnonword(f,len-1) )
return 0;
len--;
}
for (i=1; i < len; i++)
if (tolower(peek(f,i)) != s[i])
return 0;
return 1;
}
static struct smarties {
char c0;
char *pat;
char *entity;
int shift;
} smarties[] = {
{ '\'', "'s|", "rsquo", 0 },
{ '\'', "'t|", "rsquo", 0 },
{ '\'', "'re|", "rsquo", 0 },
{ '\'', "'ll|", "rsquo", 0 },
{ '\'', "'ve|", "rsquo", 0 },
{ '\'', "'m|", "rsquo", 0 },
{ '\'', "'d|", "rsquo", 0 },
{ '-', "---", "mdash", 2 },
{ '-', "--", "ndash", 1 },
{ '.', "...", "hellip", 2 },
{ '.', ". . .", "hellip", 4 },
{ '(', "(c)", "copy", 2 },
{ '(', "(r)", "reg", 2 },
{ '(', "(tm)", "trade", 3 },
{ '3', "|3/4|", "frac34", 2 },
{ '3', "|3/4ths|", "frac34", 2 },
{ '1', "|1/2|", "frac12", 2 },
{ '1', "|1/4|", "frac14", 2 },
{ '1', "|1/4th|", "frac14", 2 },
{ '&', "", 0, 3 },
} ;
#define NRSMART ( sizeof smarties / sizeof smarties[0] )
/* Smarty-pants-style chrome for quotes, -, ellipses, and (r)(c)(tm)
*/
static int
smartypants(int c, int *flags, MMIOT *f)
{
int i;
if ( is_flag_set(f->flags, MKD_NOPANTS)
|| is_flag_set(f->flags, MKD_TAGTEXT)
|| is_flag_set(f->flags, IS_LABEL) )
return 0;
for ( i=0; i < NRSMART; i++)
if ( (c == smarties[i].c0) && islike(f, smarties[i].pat) ) {
if ( smarties[i].entity )
Qprintf(f, "&%s;", smarties[i].entity);
shift(f, smarties[i].shift);
return 1;
}
switch (c) {
case '<' : return 0;
case '\'': if ( smartyquote(flags, 's', f) ) return 1;
break;
case '"': if ( smartyquote(flags, 'd', f) ) return 1;
break;
case '`': if ( peek(f, 1) == '`' ) {
int j = 2;
while ( (c=peek(f,j)) != EOF ) {
if ( c == '\\' )
j += 2;
else if ( c == '`' )
break;
else if ( c == '\'' && peek(f, j+1) == '\'' ) {
Qstring("“", f);
___mkd_reparse(cursor(f)+1, j-2, 0, f, 0);
Qstring("”", f);
shift(f,j+1);
return 1;
}
else ++j;
}
}
break;
}
return 0;
} /* smartypants */
/* process latex with arbitrary 2-character ( $$ .. $$, \[ .. \], \( .. \)
* delimiters
*/
static int
mathhandler(MMIOT *f, int e1, int e2)
{
int i = 0;
while(peek(f, ++i) != EOF) {
if (peek(f, i) == e1 && peek(f, i+1) == e2) {
cputc(peek(f,-1), f);
cputc(peek(f, 0), f);
while ( i-- > -1 )
cputc(pull(f), f);
return 1;
}
}
return 0;
}
/* process a body of text encased in some sort of tick marks. If it
* works, generate the output and return 1, otherwise just return 0 and
* let the caller figure it out.
*/
static int
tickhandler(MMIOT *f, int tickchar, int minticks, int allow_space, spanhandler spanner)
{
int endticks, size;
int tick = nrticks(0, tickchar, f);
if ( !allow_space && isspace(peek(f,tick)) )
return 0;
if ( (tick >= minticks) && (size = matchticks(f,tickchar,tick,&endticks)) ) {
if ( endticks < tick ) {
size += (tick - endticks);
tick = endticks;
}
shift(f, tick);
(*spanner)(f,size);
shift(f, size+tick-1);
return 1;
}
return 0;
}
#define tag_text(f) is_flag_set(f->flags, MKD_TAGTEXT)
static void
text(MMIOT *f)
{
int c, j;
int rep;
int smartyflags = 0;
while (1) {
if ( is_flag_set(f->flags, MKD_AUTOLINK) && isalpha(peek(f,1)) && !tag_text(f) )
maybe_autolink(f);
c = pull(f);
if (c == EOF)
break;
if ( smartypants(c, &smartyflags, f) )
continue;
switch (c) {
case 0: break;
case MKD_EOLN:
Qstring(tag_text(f) ? " " : " ", f);
break;
case '>': if ( tag_text(f) )
Qstring(">", f);
else
Qchar(c, f);
break;
case '"': if ( tag_text(f) )
Qstring(""", f);
else
Qchar(c, f);
break;
case '!': if ( peek(f,1) == '[' ) {
pull(f);
if ( tag_text(f) || !linkylinky(1, f) )
Qstring("![", f);
}
else
Qchar(c, f);
break;
case '[': if ( tag_text(f) || !linkylinky(0, f) )
Qchar(c, f);
break;
#ifdef TYPORA
case '=': if ( is_flag_set(f->flags, MKD_NOSUPERSCRIPT)
|| is_flag_set(f->flags, MKD_STRICT)
|| is_flag_set(f->flags, MKD_TAGTEXT)
|| ! tickhandler(f,c,2,0, highlightspan))
Qchar(c, f);
break;
/* A^B^ -> AB */
case '^': if ( is_flag_set(f->flags, MKD_NOSUPERSCRIPT)
|| is_flag_set(f->flags, MKD_STRICT)
|| is_flag_set(f->flags, MKD_TAGTEXT)
|| ! tickhandler(f,c,1,0, supspan))
Qchar(c, f);
break;
#else /* !TYPORA */
/* A^B -> AB */
case '^': if ( is_flag_set(f->flags, MKD_NOSUPERSCRIPT)
|| is_flag_set(f->flags, MKD_STRICT)
|| is_flag_set(f->flags, MKD_TAGTEXT)
|| (f->last == 0)
|| ((ispunct(f->last) || isspace(f->last))
&& f->last != ')')
|| isthisspace(f,1) )
Qchar(c,f);
else {
char *sup = cursor(f);
int len = 0;
if ( peek(f,1) == '(' ) {
int here = mmiottell(f);
pull(f);
if ( (len = parenthetical('(',')',f)) <= 0 ) {
mmiotseek(f,here);
Qchar(c, f);
break;
}
sup++;
}
else {
while ( isthisalnum(f,1+len) )
++len;
if ( !len ) {
Qchar(c,f);
break;
}
shift(f,len);
}
Qstring("",f);
___mkd_reparse(sup, len, 0, f, "()");
Qstring(" ", f);
}
break;
#endif /* TYPORA */
case '_':
/* Underscores don't count if they're in the middle of a word */
if ( !(is_flag_set(f->flags, MKD_NORELAXED) || is_flag_set(f->flags, MKD_STRICT))
&& isthisalnum(f,-1) && isthisalnum(f,1) ) {
Qchar(c, f);
break;
}
case '*':
/* Underscores & stars don't count if they're out in the middle
* of whitespace */
if ( isthisspace(f,-1) && isthisspace(f,1) ) {
Qchar(c, f);
break;
}
/* else fall into the regular old emphasis case */
if ( tag_text(f) )
Qchar(c, f);
else {
for (rep = 1; peek(f,1) == c; pull(f) )
++rep;
Qem(f,c,rep);
}
break;
#ifdef TYPORA
#define ticktick(f,c) (tickhandler(f,c,2,0,delspan) || tickhandler(f,c,1,0,subspan))
#else
#define ticktick(f,c) tickhandler(f,c,2,0,delspan)
#endif
case '~': if ( is_flag_set(f->flags, MKD_NOSTRIKETHROUGH)
|| is_flag_set(f->flags, MKD_STRICT)
|| is_flag_set(f->flags, MKD_TAGTEXT)
|| !ticktick(f,c) )
Qchar(c, f);
break;
case '`': if ( tag_text(f) || !tickhandler(f,c,1,1,codespan) )
Qchar(c, f);
break;
case '\\': switch ( c = pull(f) ) {
case '&': Qstring("&", f);
break;
case '<': c = peek(f,1);
if ( (c == EOF) || isspace(c) )
Qstring("<", f);
else {
/* Markdown.pl does not escape <[nonwhite]
* sequences */
Qchar('\\', f);
shift(f, -1);
}
break;
case '^': if ( is_flag_set(f->flags, MKD_STRICT)
|| is_flag_set(f->flags, MKD_NOSUPERSCRIPT) ) {
Qchar('\\', f);
shift(f,-1);
break;
}
Qchar(c, f);
break;
case ':': case '|':
if ( is_flag_set(f->flags, MKD_NOTABLES) ) {
Qchar('\\', f);
shift(f,-1);
break;
}
Qchar(c, f);
break;
case EOF: Qchar('\\', f);
break;
case '[':
case '(': if ( is_flag_set(f->flags, MKD_LATEX)
&& mathhandler(f, '\\', (c =='(')?')':']') )
break;
/* else fall through to default */
default: if ( escaped(f,c) ||
strchr(">#.-+{}]![*_\\()`", c) )
Qchar(c, f);
else {
Qchar('\\', f);
shift(f, -1);
}
break;
}
break;
case '<': if ( !maybe_tag_or_link(f) ) {
if ( is_flag_set(f->flags, MKD_STRICT) && is_a_strict_tag_prefix(peek(f,1)) )
Qchar(c, f);
else
Qstring("<", f);
}
break;
case '&': j = (peek(f,1) == '#' ) ? 2 : 1;
while ( isthisalnum(f,j) )
++j;
if ( peek(f,j) != ';' )
Qstring("&", f);
else
Qchar(c, f);
break;
case '$': if ( is_flag_set(f->flags, MKD_LATEX) && (peek(f, 1) == '$') ) {
pull(f);
if ( mathhandler(f, '$', '$') )
break;
Qchar('$', f);
}
/* fall through to default */
default: f->last = c;
Qchar(c, f);
break;
}
}
/* truncate the input string after we've finished processing it */
S(f->in) = f->isp = 0;
} /* text */
/* print a header block
*/
static void
printheader(Paragraph *pp, MMIOT *f)
{
if ( is_flag_set(f->flags, MKD_IDANCHOR) ) {
Qprintf(f, "hnumber);
if ( is_flag_set(f->flags, MKD_TOC) ) {
Qstring(" id=\"", f);
Qanchor(pp->text, f);
Qchar('"', f);
}
Qchar('>', f);
} else {
if ( is_flag_set(f->flags, MKD_TOC) ) {
Qstring("text, f);
Qstring("\"> \n", f);
}
Qprintf(f, "", pp->hnumber);
}
push(T(pp->text->text), S(pp->text->text), f);
text(f);
Qprintf(f, " ", pp->hnumber);
}
enum e_alignments { a_NONE, a_CENTER, a_LEFT, a_RIGHT };
static char* alignments[] = { "", " style=\"text-align:center;\"",
" style=\"text-align:left;\"",
" style=\"text-align:right;\"" };
typedef STRING(int) Istring;
static int
splat(Line *p, char *block, Istring align, int force, MMIOT *f)
{
int first,
idx = p->dle,
colno = 0;
___mkd_tidy(&p->text);
if ( T(p->text)[S(p->text)-1] == '|' )
--S(p->text);
Qstring("\n", f);
while ( idx < S(p->text) ) {
first = idx;
if ( force && (colno >= S(align)-1) )
idx = S(p->text);
else
while ( (idx < S(p->text)) && (T(p->text)[idx] != '|') ) {
if ( T(p->text)[idx] == '\\' )
++idx;
++idx;
}
Qprintf(f, "<%s%s>",
block,
alignments[ (colno < S(align)) ? T(align)[colno] : a_NONE ]);
___mkd_reparse(T(p->text)+first, idx-first, 0, f, "|");
Qprintf(f, "%s>\n", block);
idx++;
colno++;
}
if ( force )
while (colno < S(align) ) {
Qprintf(f, "<%s>%s>\n", block, block);
++colno;
}
Qstring(" \n", f);
return colno;
}
static int
printtable(Paragraph *pp, MMIOT *f)
{
/* header, dashes, then lines of content */
Line *hdr, *dash, *body;
Istring align;
int hcols,start;
char *p;
enum e_alignments it;
hdr = pp->text;
dash= hdr->next;
body= dash->next;
if ( T(hdr->text)[hdr->dle] == '|' ) {
/* trim leading pipe off all lines
*/
Line *r;
for ( r = pp->text; r; r = r->next )
r->dle ++;
}
/* figure out cell alignments */
CREATE(align);
for (p=T(dash->text), start=dash->dle; start < S(dash->text); ) {
char first, last;
int end;
last=first=0;
for (end=start ; (end < S(dash->text)) && p[end] != '|'; ++ end ) {
if ( p[end] == '\\' )
++ end;
else if ( !isspace(p[end]) ) {
if ( !first) first = p[end];
last = p[end];
}
}
it = ( first == ':' ) ? (( last == ':') ? a_CENTER : a_LEFT)
: (( last == ':') ? a_RIGHT : a_NONE );
EXPAND(align) = it;
start = 1+end;
}
Qstring("\n", f);
Qstring("\n", f);
hcols = splat(hdr, "th", align, 0, f);
Qstring(" \n", f);
if ( hcols < S(align) )
S(align) = hcols;
else
while ( hcols > S(align) )
EXPAND(align) = a_NONE;
Qstring("\n", f);
for ( ; body; body = body->next)
splat(body, "td", align, 1, f);
Qstring(" \n", f);
Qstring("
\n", f);
DELETE(align);
return 1;
}
static int
printblock(Paragraph *pp, MMIOT *f)
{
static char *Begin[] = { "", "", "
" };
static char *End[] = { "", "
","" };
Line *t = pp->text;
int align = pp->align;
while (t) {
if ( S(t->text) ) {
if ( t->next && S(t->text) > 2
&& T(t->text)[S(t->text)-2] == ' '
&& T(t->text)[S(t->text)-1] == ' ' ) {
push(T(t->text), S(t->text)-2, f);
pushc(MKD_EOLN, f);
pushc('\n', f);
}
else {
___mkd_tidy(&t->text);
push(T(t->text), S(t->text), f);
if ( t->next )
pushc('\n', f);
}
}
t = t->next;
}
Qstring(Begin[align], f);
text(f);
Qstring(End[align], f);
return 1;
}
static void
printcode(Line *t, char *lang, MMIOT *f)
{
int blanks;
if ( f->cb->e_codefmt ) {
/* external code block formatter; copy the text into a buffer,
* call the formatter to style it, then dump that styled text
* directly to the queue
*/
char *text;
char *fmt;
int size, copy_p;
Line *p;
for (size=0, p = t; p; p = p->next )
size += 1+S(p->text);
text = malloc(1+size);
for ( copy_p = 0; t ; t = t->next ) {
memcpy(text+copy_p, T(t->text), S(t->text));
copy_p += S(t->text);
text[copy_p++] = '\n';
}
text[copy_p] = 0;
fmt = (*(f->cb->e_codefmt))(text, copy_p, (lang && lang[0]) ? lang : 0);
free(text);
if ( fmt ) {
Qwrite(fmt, strlen(fmt), f);
if ( f->cb->e_free )
(*(f->cb->e_free))(fmt, f->cb->e_data);
return;
}
/* otherwise the external formatter failed and we need to
* fall back to the traditional codeblock format
*/
}
Qstring("", f);
for ( blanks = 0; t ; t = t->next ) {
if ( S(t->text) > t->dle ) {
while ( blanks ) {
Qchar('\n', f);
--blanks;
}
code(f, T(t->text), S(t->text));
Qchar('\n', f);
}
else blanks++;
}
Qstring("
", f);
}
static void
printhtml(Line *t, MMIOT *f)
{
int blanks;
for ( blanks=0; t ; t = t->next )
if ( S(t->text) ) {
for ( ; blanks; --blanks )
Qchar('\n', f);
Qwrite(T(t->text), S(t->text), f);
Qchar('\n', f);
}
else
blanks++;
}
static void
htmlify_paragraphs(Paragraph *p, MMIOT *f)
{
___mkd_emblock(f);
while (( p = display(p, f) )) {
___mkd_emblock(f);
Qstring("\n\n", f);
}
}
#ifdef GITHUB_CHECKBOX
static void
li_htmlify(Paragraph *p, char *arguments, mkd_flag_t flags, MMIOT *f)
{
___mkd_emblock(f);
Qprintf(f, "");
#if CHECKBOX_AS_INPUT
if ( flags & GITHUB_CHECK ) {
Qprintf(f, " ");
}
#else
if ( flags & GITHUB_CHECK )
Qprintf(f, flags & IS_CHECKED ? "☑" : "☐");
#endif
htmlify_paragraphs(p, f);
Qprintf(f, " ");
___mkd_emblock(f);
}
#endif
static void
htmlify(Paragraph *p, char *block, char *arguments, MMIOT *f)
{
___mkd_emblock(f);
if ( block )
Qprintf(f, arguments ? "<%s %s>" : "<%s>", block, arguments);
htmlify_paragraphs(p, f);
if ( block )
Qprintf(f, "%s>", block);
___mkd_emblock(f);
}
static void
definitionlist(Paragraph *p, MMIOT *f)
{
Line *tag;
if ( p ) {
Qstring("\n", f);
for ( ; p ; p = p->next) {
for ( tag = p->text; tag; tag = tag->next ) {
Qstring("", f);
___mkd_reparse(T(tag->text), S(tag->text), 0, f, 0);
Qstring(" \n", f);
}
htmlify(p->down, "dd", p->ident, f);
Qchar('\n', f);
}
Qstring(" ", f);
}
}
static void
listdisplay(int typ, Paragraph *p, MMIOT* f)
{
if ( p ) {
Qprintf(f, "<%cl", (typ==UL)?'u':'o');
if ( typ == AL )
Qprintf(f, " type=\"a\"");
Qprintf(f, ">\n");
for ( ; p ; p = p->next ) {
#ifdef GITHUB_CHECKBOX
li_htmlify(p->down, p->ident, p->flags, f);
#else
htmlify(p->down, "li", p->ident, f);
#endif
Qchar('\n', f);
}
Qprintf(f, "%cl>\n", (typ==UL)?'u':'o');
}
}
/* dump out a Paragraph in the desired manner
*/
static Paragraph*
display(Paragraph *p, MMIOT *f)
{
if ( !p ) return 0;
switch ( p->typ ) {
case STYLE:
case WHITESPACE:
break;
case HTML:
printhtml(p->text, f);
break;
case CODE:
printcode(p->text, p->lang, f);
break;
case QUOTE:
htmlify(p->down, p->ident ? "div" : "blockquote", p->ident, f);
break;
case UL:
case OL:
case AL:
listdisplay(p->typ, p->down, f);
break;
case DL:
definitionlist(p->down, f);
break;
case HR:
Qstring(" ", f);
break;
case HDR:
printheader(p, f);
break;
case TABLE:
printtable(p, f);
break;
case SOURCE:
htmlify(p->down, 0, 0, f);
break;
default:
printblock(p, f);
break;
}
return p->next;
}
/* dump out a list of footnotes
*/
static void
mkd_extra_footnotes(MMIOT *m)
{
int j, i;
Footnote *t;
if ( m->footnotes->reference == 0 )
return;
Csprintf(&m->out, "\n\n");
}
/* return a pointer to the compiled markdown
* document.
*/
int
mkd_document(Document *p, char **res)
{
int size;
if ( p && p->compiled ) {
if ( ! p->html ) {
htmlify(p->code, 0, 0, p->ctx);
if ( is_flag_set(p->ctx->flags, MKD_EXTRA_FOOTNOTE) )
mkd_extra_footnotes(p->ctx);
p->html = 1;
size = S(p->ctx->out);
if ( (size == 0) || T(p->ctx->out)[size-1] ) {
/* Add a null byte at the end of the generated html,
* but pretend it doesn't exist.
*/
EXPAND(p->ctx->out) = 0;
--S(p->ctx->out);
}
}
*res = T(p->ctx->out);
return S(p->ctx->out);
}
return EOF;
}
rdiscount-2.2.7.3/ext/Csio.c 0000644 0000041 0000041 00000001773 14571373162 015607 0 ustar www-data www-data #include
#include
#include
#include "cstring.h"
#include "markdown.h"
#include "amalloc.h"
/* putc() into a cstring
*/
void
Csputc(int c, Cstring *iot)
{
EXPAND(*iot) = c;
}
/* printf() into a cstring
*/
int
Csprintf(Cstring *iot, char *fmt, ...)
{
va_list ptr;
int siz=100;
do {
RESERVE(*iot, siz);
va_start(ptr, fmt);
siz = vsnprintf(T(*iot)+S(*iot), ALLOCATED(*iot)-S(*iot), fmt, ptr);
va_end(ptr);
} while ( siz > (ALLOCATED(*iot)-S(*iot)) );
S(*iot) += siz;
return siz;
}
/* write() into a cstring
*/
int
Cswrite(Cstring *iot, char *bfr, int size)
{
RESERVE(*iot, size);
memcpy(T(*iot)+S(*iot), bfr, size);
S(*iot) += size;
return size;
}
/* reparse() into a cstring
*/
void
Csreparse(Cstring *iot, char *buf, int size, mkd_flag_t flags)
{
MMIOT f;
___mkd_initmmiot(&f, 0);
___mkd_reparse(buf, size, flags, &f, 0);
___mkd_emblock(&f);
SUFFIX(*iot, T(f.out), S(f.out));
___mkd_freemmiot(&f, 0);
}
rdiscount-2.2.7.3/ext/css.c 0000644 0000041 0000041 00000002726 14571373162 015501 0 ustar www-data www-data /* markdown: a C implementation of John Gruber's Markdown markup language.
*
* Copyright (C) 2009 David L Parsons.
* The redistribution terms are provided in the COPYRIGHT file that must
* be distributed with this source code.
*/
#include
#include
#include
#include
#include
#include
#include "config.h"
#include "cstring.h"
#include "markdown.h"
#include "amalloc.h"
/*
* dump out stylesheet sections.
*/
static void
stylesheets(Paragraph *p, Cstring *f)
{
Line* q;
for ( ; p ; p = p->next ) {
if ( p->typ == STYLE ) {
for ( q = p->text; q ; q = q->next ) {
Cswrite(f, T(q->text), S(q->text));
Csputc('\n', f);
}
}
if ( p->down )
stylesheets(p->down, f);
}
}
/* dump any embedded styles to a string
*/
int
mkd_css(Document *d, char **res)
{
Cstring f;
int size;
if ( res && d && d->compiled ) {
*res = 0;
CREATE(f);
RESERVE(f, 100);
stylesheets(d->code, &f);
if ( (size = S(f)) > 0 ) {
/* null-terminate, then strdup() into a free()able memory
* chunk
*/
EXPAND(f) = 0;
*res = strdup(T(f));
}
DELETE(f);
return size;
}
return EOF;
}
/* dump any embedded styles to a file
*/
int
mkd_generatecss(Document *d, FILE *f)
{
char *res;
int written;
int size = mkd_css(d, &res);
written = (size > 0) ? fwrite(res,1,size,f) : 0;
if ( res )
free(res);
return (written == size) ? size : EOF;
}
rdiscount-2.2.7.3/ext/xmlpage.c 0000644 0000041 0000041 00000002211 14571373162 016333 0 ustar www-data www-data /*
* xmlpage -- write a skeletal xhtml page
*
* Copyright (C) 2007 David L Parsons.
* The redistribution terms are provided in the COPYRIGHT file that must
* be distributed with this source code.
*/
#include
#include
#include
int
mkd_xhtmlpage(Document *p, mkd_flag_t flags, FILE *out)
{
char *title;
extern char *mkd_doc_title(Document *);
if ( mkd_compile(p, flags) ) {
DO_OR_DIE( fprintf(out, "\n"
"\n"
"\n") );
DO_OR_DIE( fprintf(out, "\n") );
DO_OR_DIE( fprintf(out, "") );
if ( title = mkd_doc_title(p) ) {
DO_OR_DIE( fprintf(out, "%s", title) );
}
DO_OR_DIE( fprintf(out, " \n") );
DO_OR_DIE( mkd_generatecss(p, out) );
DO_OR_DIE( fprintf(out, "\n"
"\n") );
DO_OR_DIE( mkd_generatehtml(p, out) );
DO_OR_DIE( fprintf(out, "\n"
"\n") );
return 0;
}
return EOF;
}
rdiscount-2.2.7.3/ext/mkdio.c 0000644 0000041 0000041 00000022146 14571373162 016012 0 ustar www-data www-data /*
* mkdio -- markdown front end input functions
*
* Copyright (C) 2007 David L Parsons.
* The redistribution terms are provided in the COPYRIGHT file that must
* be distributed with this source code.
*/
#include "config.h"
#include
#include
#include
#include "cstring.h"
#include "markdown.h"
#include "amalloc.h"
typedef ANCHOR(Line) LineAnchor;
/* create a new blank Document
*/
Document*
__mkd_new_Document()
{
Document *ret = calloc(sizeof(Document), 1);
if ( ret ) {
if ( ret->ctx = calloc(sizeof(MMIOT), 1) ) {
ret->magic = VALID_DOCUMENT;
return ret;
}
free(ret);
}
return 0;
}
/* add a line to the markdown input chain, expanding tabs and
* noting the presence of special characters as we go.
*/
void
__mkd_enqueue(Document* a, Cstring *line)
{
Line *p = calloc(sizeof *p, 1);
unsigned char c;
int xp = 0;
int size = S(*line);
unsigned char *str = (unsigned char*)T(*line);
CREATE(p->text);
ATTACH(a->content, p);
while ( size-- ) {
if ( (c = *str++) == '\t' ) {
/* expand tabs into ->tabstop spaces. We use ->tabstop
* because the ENTIRE FREAKING COMPUTER WORLD uses editors
* that don't do ^T/^D, but instead use tabs for indentation,
* and, of course, set their tabs down to 4 spaces
*/
do {
EXPAND(p->text) = ' ';
} while ( ++xp % a->tabstop );
}
else if ( c >= ' ' ) {
if ( c == '|' )
p->flags |= PIPECHAR;
EXPAND(p->text) = c;
++xp;
}
}
EXPAND(p->text) = 0;
S(p->text)--;
p->dle = mkd_firstnonblank(p);
}
/* trim leading characters from a line, then adjust the dle.
*/
void
__mkd_trim_line(Line *p, int clip)
{
if ( clip >= S(p->text) ) {
S(p->text) = p->dle = 0;
T(p->text)[0] = 0;
}
else if ( clip > 0 ) {
CLIP(p->text, 0, clip);
p->dle = mkd_firstnonblank(p);
}
}
/* build a Document from any old input.
*/
typedef int (*getc_func)(void*);
Document *
populate(getc_func getc, void* ctx, mkd_flag_t flags)
{
Cstring line;
Document *a = __mkd_new_Document();
int c;
int pandoc = 0;
if ( !a ) return 0;
a->tabstop = is_flag_set(flags, MKD_TABSTOP) ? 4 : TABSTOP;
CREATE(line);
while ( (c = (*getc)(ctx)) != EOF ) {
if ( c == '\n' ) {
if ( pandoc != EOF && pandoc < 3 ) {
if ( S(line) && (T(line)[0] == '%') )
pandoc++;
else
pandoc = EOF;
}
__mkd_enqueue(a, &line);
S(line) = 0;
}
else if ( isprint(c) || isspace(c) || (c & 0x80) )
EXPAND(line) = c;
}
if ( S(line) )
__mkd_enqueue(a, &line);
DELETE(line);
if ( (pandoc == 3) && !(is_flag_set(flags, MKD_NOHEADER) || is_flag_set(flags, MKD_STRICT)) ) {
/* the first three lines started with %, so we have a header.
* clip the first three lines out of content and hang them
* off header.
*/
Line *headers = T(a->content);
a->title = headers; __mkd_trim_line(a->title, 1);
a->author= headers->next; __mkd_trim_line(a->author, 1);
a->date = headers->next->next; __mkd_trim_line(a->date, 1);
T(a->content) = headers->next->next->next;
}
return a;
}
/* convert a file into a linked list
*/
Document *
mkd_in(FILE *f, mkd_flag_t flags)
{
return populate((getc_func)fgetc, f, flags & INPUT_MASK);
}
/* return a single character out of a buffer
*/
int
__mkd_io_strget(struct string_stream *in)
{
if ( !in->size ) return EOF;
--(in->size);
return *(in->data)++;
}
/* convert a block of text into a linked list
*/
Document *
mkd_string(const char *buf, int len, mkd_flag_t flags)
{
struct string_stream about;
about.data = buf;
about.size = len;
return populate((getc_func)__mkd_io_strget, &about, flags & INPUT_MASK);
}
/* write the html to a file (xmlified if necessary)
*/
int
mkd_generatehtml(Document *p, FILE *output)
{
char *doc;
int szdoc;
DO_OR_DIE( szdoc = mkd_document(p,&doc) );
if ( is_flag_set(p->ctx->flags, MKD_CDATA) )
DO_OR_DIE( mkd_generatexml(doc, szdoc, output) );
else if ( fwrite(doc, szdoc, 1, output) != 1 )
return EOF;
DO_OR_DIE( putc('\n', output) );
return 0;
}
/* convert some markdown text to html
*/
int
markdown(Document *document, FILE *out, mkd_flag_t flags)
{
if ( mkd_compile(document, flags) ) {
mkd_generatehtml(document, out);
mkd_cleanup(document);
return 0;
}
return -1;
}
/* anchor_format a string, returning the formatted string in malloc()ed space
* MKD_URLENCODEDANCHOR is now perverted to being a html5 anchor
*
* !labelformat: print all characters
* labelformat && h4anchor: prefix nonalpha label with L,
* expand all nonalnum, _, ':', '.' to hex
* except space which maps to -
* labelformat && !h4anchor:expand space to -, other isspace() & '%' to hex
*/
static char *
mkd_anchor_format(char *s, int len, int labelformat, mkd_flag_t flags)
{
char *res;
unsigned char c;
int i, needed, out = 0;
int h4anchor = !is_flag_set(flags, MKD_URLENCODEDANCHOR);
static const unsigned char hexchars[] = "0123456789abcdef";
needed = (labelformat ? (4*len) : len) + 2 /* 'L', trailing null */;
if ( (res = malloc(needed)) == NULL )
return NULL;
if ( h4anchor && labelformat && !isalpha(s[0]) )
res[out++] = 'L';
for ( i=0; i < len ; i++ ) {
c = s[i];
if ( labelformat ) {
if ( h4anchor
? (isalnum(c) || (c == '_') || (c == ':') || (c == '.' ) )
: !(isspace(c) || c == '%') )
res[out++] = c;
else if ( c == ' ' )
res[out++] = '-';
else {
res[out++] = h4anchor ? '-' : '%';
res[out++] = hexchars[c >> 4 & 0xf];
res[out++] = hexchars[c & 0xf];
if ( h4anchor )
res[out++] = '-';
}
}
else
res[out++] = c;
}
res[out++] = 0;
return res;
} /* mkd_anchor_format */
/* write out a Cstring, mangled into a form suitable for `cb->e_anchor )
res = (*(f->cb->e_anchor))(line, size, f->cb->e_data);
else
res = mkd_anchor_format(line, size, labelformat, f->flags);
free(line);
if ( !res )
return;
for ( i=0; res[i]; i++ )
(*outchar)(res[i], out);
if ( f->cb->e_anchor ) {
if ( f->cb->e_free )
(*(f->cb->e_free))(res, f->cb->e_data);
}
else
free(res);
}
/* ___mkd_reparse() a line
*/
static void
mkd_parse_line(char *bfr, int size, MMIOT *f, mkd_flag_t flags)
{
___mkd_initmmiot(f, 0);
f->flags = flags & USER_FLAGS;
___mkd_reparse(bfr, size, 0, f, 0);
___mkd_emblock(f);
}
/* ___mkd_reparse() a line, returning it in malloc()ed memory
*/
int
mkd_line(char *bfr, int size, char **res, mkd_flag_t flags)
{
MMIOT f;
int len;
mkd_parse_line(bfr, size, &f, flags);
if ( len = S(f.out) ) {
EXPAND(f.out) = 0;
/* strdup() doesn't use amalloc(), so in an amalloc()ed
* build this copies the string safely out of our memory
* paranoia arena. In a non-amalloc world, it's a spurious
* memory allocation, but it avoids unintentional hilarity
* with amalloc()
*/
*res = strdup(T(f.out));
}
else {
*res = 0;
len = EOF;
}
___mkd_freemmiot(&f, 0);
return len;
}
/* ___mkd_reparse() a line, writing it to a FILE
*/
int
mkd_generateline(char *bfr, int size, FILE *output, mkd_flag_t flags)
{
MMIOT f;
int status;
mkd_parse_line(bfr, size, &f, flags);
if ( is_flag_set(flags, MKD_CDATA) )
status = mkd_generatexml(T(f.out), S(f.out), output) != EOF;
else
status = fwrite(T(f.out), S(f.out), 1, output) == S(f.out);
___mkd_freemmiot(&f, 0);
return status ? 0 : EOF;
}
/* set the url display callback
*/
void
mkd_e_url(Document *f, mkd_callback_t edit)
{
if ( f ) {
if ( f->cb.e_url != edit )
f->dirty = 1;
f->cb.e_url = edit;
}
}
/* set the url options callback
*/
void
mkd_e_flags(Document *f, mkd_callback_t edit)
{
if ( f ) {
if ( f->cb.e_flags != edit )
f->dirty = 1;
f->cb.e_flags = edit;
}
}
/* set the anchor formatter
*/
void
mkd_e_anchor(Document *f, mkd_callback_t format)
{
if ( f ) {
if ( f->cb.e_anchor != format )
f->dirty = 1;
f->cb.e_anchor = format;
}
}
/* set the url display/options deallocator
*/
void
mkd_e_free(Document *f, mkd_free_t dealloc)
{
if ( f ) {
if ( f->cb.e_free != dealloc )
f->dirty = 1;
f->cb.e_free = dealloc;
}
}
/* set the url display/options context data field
*/
void
mkd_e_data(Document *f, void *data)
{
if ( f ) {
if ( f->cb.e_data != data )
f->dirty = 1;
f->cb.e_data = data;
}
}
/* set the code block display callback
*/
void
mkd_e_code_format(Document *f, mkd_callback_t codefmt)
{
if ( f && (f->cb.e_codefmt != codefmt) ) {
f->dirty = 1;
f->cb.e_codefmt = codefmt;
}
}
/* set the href prefix for markdown extra style footnotes
*/
void
mkd_ref_prefix(Document *f, char *data)
{
if ( f ) {
if ( f->ref_prefix != data )
f->dirty = 1;
f->ref_prefix = data;
}
}
rdiscount-2.2.7.3/ext/docheader.c 0000644 0000041 0000041 00000001556 14571373162 016627 0 ustar www-data www-data /*
* docheader -- get values from the document header
*
* Copyright (C) 2007 David L Parsons.
* The redistribution terms are provided in the COPYRIGHT file that must
* be distributed with this source code.
*/
#include "config.h"
#include
#include
#include
#include "cstring.h"
#include "markdown.h"
#include "amalloc.h"
static char *
onlyifset(Line *l)
{
char *ret;
if ( l->dle < 0 || l->dle >= S(l->text) )
return 0;
ret = T(l->text) + l->dle;
return ret[0] ? ret : 0;
}
char *
mkd_doc_title(Document *doc)
{
if ( doc && doc->title )
return onlyifset(doc->title);
return 0;
}
char *
mkd_doc_author(Document *doc)
{
if ( doc && doc->author )
return onlyifset(doc->author);
return 0;
}
char *
mkd_doc_date(Document *doc)
{
if ( doc && doc->date )
return onlyifset(doc->date);
return 0;
}
rdiscount-2.2.7.3/ext/emmatch.c 0000644 0000041 0000041 00000010120 14571373162 016312 0 ustar www-data www-data /* markdown: a C implementation of John Gruber's Markdown markup language.
*
* Copyright (C) 2010 David L Parsons.
* The redistribution terms are provided in the COPYRIGHT file that must
* be distributed with this source code.
*/
#include
#include
#include
#include
#include
#include
#include "config.h"
#include "cstring.h"
#include "markdown.h"
#include "amalloc.h"
/* emmatch: the emphasis mangler that's run after a block
* of html has been generated.
*
* It should create MarkdownTest_1.0 (and _1.0.3)
* compatible emphasis for non-pathological cases
* and it should fail in a standards-compliant way
* when someone attempts to feed it junk.
*
* Emmatching is done after the input has been
* processed into a STRING (f->Q) of text and
* emphasis blocks. After ___mkd_emblock() finishes,
* it truncates f->Q and leaves the rendered paragraph
* if f->out.
*/
/* empair() -- find the NEAREST matching emphasis token (or
* subtoken of a 3+ long emphasis token.
*/
static int
empair(MMIOT *f, int first, int last, int match)
{
int i;
block *begin, *p;
begin = &T(f->Q)[first];
for (i=first+1; i <= last; i++) {
p = &T(f->Q)[i];
if ( (p->b_type != bTEXT) && (p->b_count <= 0) )
continue; /* break? */
if ( p->b_type == begin->b_type ) {
if ( p->b_count == match ) /* exact match */
return i;
if ( p->b_count > 2 ) /* fuzzy match */
return i;
}
}
return 0;
} /* empair */
/* emfill() -- if an emphasis token has leftover stars or underscores,
* convert them back into character and append them to b_text.
*/
static void
emfill(block *p)
{
int j;
if ( p->b_type == bTEXT )
return;
for (j=0; j < p->b_count; j++)
EXPAND(p->b_text) = p->b_char;
p->b_count = 0;
} /* emfill */
static void
emclose(MMIOT *f, int first, int last)
{
int j;
for (j=first+1; jQ)[j]);
}
static struct emtags {
char open[10];
char close[10];
int size;
} emtags[] = { { "" , " ", 5 }, { "", " ", 9 } };
static void emblock(MMIOT*,int,int);
/* emmatch() -- match emphasis for a single emphasis token.
*/
static void
emmatch(MMIOT *f, int first, int last)
{
block *start = &T(f->Q)[first];
int e, e2, match;
switch (start->b_count) {
case 2: if ( e = empair(f,first,last,match=2) )
break;
case 1: e = empair(f,first,last,match=1);
break;
case 0: return;
default:
e = empair(f,first,last,1);
e2= empair(f,first,last,2);
if ( e2 >= e ) {
e = e2;
match = 2;
}
else
match = 1;
break;
}
if ( e ) {
/* if we found emphasis to match, match it, recursively call
* emblock to match emphasis inside the new html block, add
* the emphasis markers for the block, then (tail) recursively
* call ourself to match any remaining emphasis on this token.
*/
block *end = &T(f->Q)[e];
end->b_count -= match;
start->b_count -= match;
emblock(f, first, e);
PREFIX(start->b_text, emtags[match-1].open, emtags[match-1].size-1);
SUFFIX(end->b_post, emtags[match-1].close, emtags[match-1].size);
emmatch(f, first, last);
}
} /* emmatch */
/* emblock() -- walk a blocklist, attempting to match emphasis
*/
static void
emblock(MMIOT *f, int first, int last)
{
int i;
for ( i = first; i <= last; i++ )
if ( T(f->Q)[i].b_type != bTEXT )
emmatch(f, i, last);
emclose(f, first, last);
} /* emblock */
/* ___mkd_emblock() -- emblock a string of blocks, then concatenate the
* resulting text onto f->out.
*/
void
___mkd_emblock(MMIOT *f)
{
int i;
block *p;
emblock(f, 0, S(f->Q)-1);
for (i=0; i < S(f->Q); i++) {
p = &T(f->Q)[i];
emfill(p);
if ( S(p->b_post) ) { SUFFIX(f->out, T(p->b_post), S(p->b_post));
DELETE(p->b_post); }
if ( S(p->b_text) ) { SUFFIX(f->out, T(p->b_text), S(p->b_text));
DELETE(p->b_text); }
}
S(f->Q) = 0;
} /* ___mkd_emblock */
rdiscount-2.2.7.3/ext/VERSION 0000644 0000041 0000041 00000000007 14571373162 015603 0 ustar www-data www-data 2.2.7d
rdiscount-2.2.7.3/ext/gethopt.c 0000644 0000041 0000041 00000013262 14571373162 016360 0 ustar www-data www-data /*
* gehopt; options processing with both single-character and whole-word
* options both introduced with -
*/
#include
#include
#include "gethopt.h"
void
hoptset(ctx, argc, argv)
struct h_context *ctx;
int argc;
char **argv;
{
memset(ctx, 0, sizeof *ctx);
ctx->argc = argc;
ctx->argv = argv;
ctx->optind = 1;
}
char *
hoptarg(ctx)
struct h_context *ctx;
{
return ctx->optarg;
}
int
hoptind(ctx)
struct h_context *ctx;
{
return ctx->optind;
}
char
hoptopt(ctx)
struct h_context *ctx;
{
return ctx->optopt;
}
int
hopterr(struct h_context *ctx, int val)
{
int old = ctx->opterr;
ctx->opterr = !!val;
return old;
}
struct h_opt *
gethopt(ctx, opts, nropts)
struct h_context *ctx;
struct h_opt *opts;
int nropts;
{
int i;
int dashes;
if ( (ctx == 0) || ctx->optend || (ctx->optind >= ctx->argc) )
return 0;
ctx->optarg = 0;
ctx->optopt = 0;
if ( ctx->optchar == 0) {
/* check for leading -
*/
if ( ctx->argv[ctx->optind][0] != '-' ) {
/* out of arguments */
ctx->optend = 1;
return 0;
}
if ( ctx->argv[ctx->optind][1] == 0
|| strcmp(ctx->argv[ctx->optind], "--") == 0 ) {
/* option list finishes with - or -- token
*/
ctx->optend = 1;
ctx->optind++;
return 0;
}
dashes = 1;
if ( ctx->argv[ctx->optind][dashes] == '-' ) {
/* support GNU-style long option double-dash prefix
* (if gethopt is passed an unknown option with a double-dash
* prefix, it won't match a word and then the second dash
* will be scanned as if it was a regular old single-character
* option.)
*/
dashes = 2;
}
for ( i=0; i < nropts; i++ ) {
if ( ! opts[i].optword )
continue;
if (strcmp(opts[i].optword, dashes+(ctx->argv[ctx->optind]) ) == 0 ) {
if ( opts[i].opthasarg ) {
if ( ctx->argc > ctx->optind ) {
ctx->optarg = ctx->argv[ctx->optind+1];
ctx->optind += 2;
}
else {
/* word argument with required arg at end of
*command line
*/
if ( ctx->opterr )
fprintf(stderr,
"%s: option requires an argument -- %s\n",
ctx->argv[0], opts[i].optword);
ctx->optind ++;
return HOPTERR;
}
}
else {
ctx->optind ++;
}
return &opts[i];
}
}
ctx->optchar = 1;
}
ctx->optopt = ctx->argv[ctx->optind][ctx->optchar++];
if ( !ctx->optopt ) {
/* fell off the end of this argument */
ctx->optind ++;
ctx->optchar = 0;
return gethopt(ctx, opts, nropts);
}
for ( i=0; ioptopt ) {
/* found a single-char option!
*/
if ( opts[i].opthasarg ) {
if ( ctx->argv[ctx->optind][ctx->optchar] ) {
/* argument immediately follows this options (-Oc)
*/
ctx->optarg = &ctx->argv[ctx->optind][ctx->optchar];
ctx->optind ++;
ctx->optchar = 0;
}
else if ( ctx->optind < ctx->argc-1 ) {
/* argument is next arg (-O c)
*/
ctx->optarg = &ctx->argv[ctx->optind+1][0];
ctx->optind += 2;
ctx->optchar = 0;
}
else {
/* end of arg string (-O); set optarg to null, return
* (should it opterr on me?)
*/
ctx->optarg = 0;
ctx->optind ++;
ctx->optchar = 0;
if ( ctx->opterr )
fprintf(stderr,
"%s: option requires an argument -- %c\n",
ctx->argv[0], opts[i].optchar);
return HOPTERR;
}
}
else {
if ( !ctx->argv[ctx->optind][ctx->optchar] ) {
ctx->optind ++;
ctx->optchar = 0;
}
}
return &opts[i];
}
}
if ( ctx->opterr )
fprintf(stderr, "%s: illegal option -- %c\n", ctx->argv[0], ctx->optopt);
return HOPTERR;
}
void
hoptusage(char *pgm, struct h_opt opts[], int nropts, char *arguments)
{
int i;
int optcount;
fprintf(stderr, "usage: %s", pgm);
/* print out the options that don't have flags first */
for ( optcount=i=0; i < nropts; i++ ) {
if ( opts[i].optchar && !opts[i].opthasarg) {
if (optcount == 0 )
fputs(" [-", stderr);
fputc(opts[i].optchar, stderr);
optcount++;
}
}
if ( optcount )
fputc(']', stderr);
/* print out the options WITH flags */
for ( i = 0; i < nropts; i++ )
if ( opts[i].optchar && opts[i].opthasarg)
fprintf(stderr, " [-%c %s]", opts[i].optchar, opts[i].opthasarg);
/* print out the long options */
for ( i = 0; i < nropts; i++ )
if ( opts[i].optword ) {
fprintf(stderr, " [-%s", opts[i].optword);
if ( opts[i].opthasarg )
fprintf(stderr, " %s", opts[i].opthasarg);
fputc(']', stderr);
}
/* print out the arguments string, if any */
if ( arguments )
fprintf(stderr, " %s", arguments);
/* and we're done */
fputc('\n', stderr);
}
#if DEBUG
struct h_opt opts[] = {
{ 0, "css", 0, 1, "css file" },
{ 1, "header", 0, 1, "header file" },
{ 2, 0, 'a', 0, "option a (no arg)" },
{ 3, 0, 'b', 1, "option B (with arg)" },
{ 4, "help", '?', 0, "help message" },
} ;
#define NROPT (sizeof opts/sizeof opts[0])
int
main(argc, argv)
char **argv;
{
struct h_opt *ret;
struct h_context ctx;
int i;
hoptset(&ctx, argc, argv);
hopterr(&ctx, 1);
while (( ret = gethopt(&ctx, opts, NROPT) )) {
if ( ret != HOPTERR ) {
if ( ret->optword )
printf("%s", ret->optword);
else
printf("%c", ret->optchar);
if ( ret->opthasarg ) {
if ( hoptarg(&ctx) )
printf(" with argument \"%s\"", hoptarg(&ctx));
else
printf(" with no argument?");
}
printf(" (%s)\n", ret->optdesc);
}
}
argc -= hoptind(&ctx);
argv += hoptind(&ctx);
for ( i=0; i < argc; i++ )
printf("%d: %s\n", i, argv[i]);
return 0;
}
#endif /*DEBUG*/
rdiscount-2.2.7.3/ext/config.h 0000644 0000041 0000041 00000001002 14571373162 016145 0 ustar www-data www-data /*
* rdiscount extension discount configuration
*/
#ifndef __MARKDOWN_D
#define __MARKDOWN_D 1
/* tabs are four spaces */
#define TABSTOP 4
#define DESTRUCTOR __attribute__((__destructor__))
/* these are setup by extconf.rb */
#if HAVE_RANDOM
#define COINTOSS() (random()&1)
#elif HAVE_RAND
#define COINTOSS() (rand()&1)
#endif
#if HAVE_SRANDOM
#define INITRNG(x) srandom((unsigned int)x)
#elif HAVE_SRAND
#define INITRNG(x) srand((unsigned int)x)
#endif
#include "ruby-config.h"
#endif/* __MARKDOWN_D */
rdiscount-2.2.7.3/ext/setup.c 0000644 0000041 0000041 00000001235 14571373162 016043 0 ustar www-data www-data /* markdown: a C implementation of John Gruber's Markdown markup language.
*
* Copyright (C) 2007 David L Parsons.
* The redistribution terms are provided in the COPYRIGHT file that must
* be distributed with this source code.
*/
#include "config.h"
#include
#include
#include
#include
#include
#include
#include "cstring.h"
#include "markdown.h"
#include "amalloc.h"
#include "tags.h"
static int need_to_initrng = 1;
void
mkd_initialize()
{
if ( need_to_initrng ) {
need_to_initrng = 0;
INITRNG(time(0));
}
}
void DESTRUCTOR
mkd_shlib_destructor()
{
mkd_deallocate_tags();
}
rdiscount-2.2.7.3/ext/h1title.c 0000644 0000041 0000041 00000001261 14571373162 016254 0 ustar www-data www-data #include
#include "markdown.h"
static Paragraph *
mkd_h1(Paragraph *p)
{
Paragraph *found;
while ( p ) {
if ( p->typ == HDR && p->hnumber == 1 )
return p;
if ( p->down && (found = mkd_h1(p->down)) )
return found;
p = p->next;
}
return 0;
}
char *
mkd_h1_title(Document *doc, int flags)
{
Paragraph *title;
if (doc && (title = mkd_h1(doc->code)) ) {
char *generated;
int size;
/* assert that a H1 header is one line long, so that's
* the only thing needed
*/
size = mkd_line(T(title->text->text),
S(title->text->text), &generated, flags|MKD_TAGTEXT);
if ( size ) return generated;
}
return 0;
}
rdiscount-2.2.7.3/ext/amalloc.c 0000644 0000041 0000041 00000005163 14571373162 016317 0 ustar www-data www-data /*
* debugging malloc()/realloc()/calloc()/free() that attempts
* to keep track of just what's been allocated today.
*/
#include
#include
#include "config.h"
#define MAGIC 0x1f2e3d4c
struct alist { int magic, size, index; int *end; struct alist *next, *last; };
static struct alist list = { 0, 0, 0, 0 };
static int mallocs=0;
static int reallocs=0;
static int frees=0;
static int index = 0;
static void
die(char *msg, int index)
{
fprintf(stderr, msg, index);
abort();
}
void *
acalloc(int count, int size)
{
struct alist *ret;
if ( size > 1 ) {
count *= size;
size = 1;
}
if ( ret = calloc(count + sizeof(struct alist) + sizeof(int), size) ) {
ret->magic = MAGIC;
ret->size = size * count;
ret->index = index ++;
ret->end = (int*)(count + (char*) (ret + 1));
*(ret->end) = ~MAGIC;
if ( list.next ) {
ret->next = list.next;
ret->last = &list;
ret->next->last = ret;
list.next = ret;
}
else {
ret->last = ret->next = &list;
list.next = list.last = ret;
}
++mallocs;
return ret+1;
}
return 0;
}
void*
amalloc(int size)
{
return acalloc(size,1);
}
void
afree(void *ptr)
{
struct alist *p2 = ((struct alist*)ptr)-1;
if ( p2->magic == MAGIC ) {
if ( ! (p2->end && *(p2->end) == ~MAGIC) )
die("goddam: corrupted memory block %d in free()!\n", p2->index);
p2->last->next = p2->next;
p2->next->last = p2->last;
++frees;
free(p2);
}
else
free(ptr);
}
void *
arealloc(void *ptr, int size)
{
struct alist *p2 = ((struct alist*)ptr)-1;
struct alist save;
if ( p2->magic == MAGIC ) {
if ( ! (p2->end && *(p2->end) == ~MAGIC) )
die("goddam: corrupted memory block %d in realloc()!\n", p2->index);
save.next = p2->next;
save.last = p2->last;
p2 = realloc(p2, sizeof(int) + sizeof(*p2) + size);
if ( p2 ) {
p2->size = size;
p2->end = (int*)(size + (char*) (p2 + 1));
*(p2->end) = ~MAGIC;
p2->next->last = p2;
p2->last->next = p2;
++reallocs;
return p2+1;
}
else {
save.next->last = save.last;
save.last->next = save.next;
return 0;
}
}
return realloc(ptr, size);
}
void
adump()
{
struct alist *p;
for ( p = list.next; p && (p != &list); p = p->next ) {
fprintf(stderr, "allocated: %d byte%s\n", p->size, (p->size==1) ? "" : "s");
fprintf(stderr, " [%.*s]\n", p->size, (char*)(p+1));
}
if ( getenv("AMALLOC_STATISTICS") ) {
fprintf(stderr, "%d malloc%s\n", mallocs, (mallocs==1)?"":"s");
fprintf(stderr, "%d realloc%s\n", reallocs, (reallocs==1)?"":"s");
fprintf(stderr, "%d free%s\n", frees, (frees==1)?"":"s");
}
}
rdiscount-2.2.7.3/ext/tags.c 0000644 0000041 0000041 00000003720 14571373162 015642 0 ustar www-data www-data /* block-level tags for passing html blocks through the blender
*/
#include "config.h"
#define __WITHOUT_AMALLOC 1
#include "cstring.h"
#include "tags.h"
STRING(struct kw) extratags;
/* the standard collection of tags are built and sorted when
* discount is configured, so all we need to do is pull them
* in and use them.
*
* Additional tags still need to be allocated, sorted, and deallocated.
*/
#include "blocktags"
/* define an additional html block tag
*/
void
mkd_define_tag(char *id, int selfclose)
{
struct kw *p;
/* only add the new tag if it doesn't exist in
* either the standard or extra tag tables.
*/
if ( !(p = mkd_search_tags(id, strlen(id))) ) {
/* extratags could be deallocated */
if ( S(extratags) == 0 )
CREATE(extratags);
p = &EXPAND(extratags);
p->id = id;
p->size = strlen(id);
p->selfclose = selfclose;
}
}
/* case insensitive string sort (for qsort() and bsearch() of block tags)
*/
static int
casort(struct kw *a, struct kw *b)
{
if ( a->size != b->size )
return a->size - b->size;
return strncasecmp(a->id, b->id, b->size);
}
/* stupid cast to make gcc shut up about the function types being
* passed into qsort() and bsearch()
*/
typedef int (*stfu)(const void*,const void*);
/* sort the list of extra html block tags for later searching
*/
void
mkd_sort_tags()
{
qsort(T(extratags), S(extratags), sizeof(struct kw), (stfu)casort);
}
/* look for a token in the html block tag list
*/
struct kw*
mkd_search_tags(char *pat, int len)
{
struct kw key;
struct kw *ret;
key.id = pat;
key.size = len;
if ( (ret=bsearch(&key,blocktags,NR_blocktags,sizeof key,(stfu)casort)) )
return ret;
if ( S(extratags) )
return bsearch(&key,T(extratags),S(extratags),sizeof key,(stfu)casort);
return 0;
}
/* destroy the extratags list (for shared libraries)
*/
void
mkd_deallocate_tags()
{
if ( S(extratags) > 0 )
DELETE(extratags);
} /* mkd_deallocate_tags */
rdiscount-2.2.7.3/ext/mkdio.h 0000644 0000041 0000041 00000010725 14571373162 016017 0 ustar www-data www-data #ifndef _MKDIO_D
#define _MKDIO_D
#include
#include
typedef void MMIOT;
typedef uint32_t mkd_flag_t;
/* line builder for markdown()
*/
MMIOT *mkd_in(FILE*,mkd_flag_t); /* assemble input from a file */
MMIOT *mkd_string(const char*,int,mkd_flag_t); /* assemble input from a buffer */
/* line builder for github flavoured markdown
*/
MMIOT *gfm_in(FILE*,mkd_flag_t); /* assemble input from a file */
MMIOT *gfm_string(const char*,int,mkd_flag_t); /* assemble input from a buffer */
void mkd_basename(MMIOT*,char*);
void mkd_initialize();
void mkd_with_html5_tags();
void mkd_shlib_destructor();
/* compilation, debugging, cleanup
*/
int mkd_compile(MMIOT*, mkd_flag_t);
void mkd_cleanup(MMIOT*);
/* markup functions
*/
int mkd_dump(MMIOT*, FILE*, mkd_flag_t, char*);
int markdown(MMIOT*, FILE*, mkd_flag_t);
int mkd_line(char *, int, char **, mkd_flag_t);
int mkd_xhtmlpage(MMIOT*,mkd_flag_t,FILE*);
/* header block access
*/
char* mkd_doc_title(MMIOT*);
char* mkd_doc_author(MMIOT*);
char* mkd_doc_date(MMIOT*);
/* compiled data access
*/
int mkd_document(MMIOT*, char**);
int mkd_toc(MMIOT*, char**);
int mkd_css(MMIOT*, char **);
int mkd_xml(char *, int, char **);
/* write-to-file functions
*/
int mkd_generatehtml(MMIOT*,FILE*);
int mkd_generatetoc(MMIOT*,FILE*);
int mkd_generatexml(char *, int,FILE*);
int mkd_generatecss(MMIOT*,FILE*);
#define mkd_style mkd_generatecss
int mkd_generateline(char *, int, FILE*, mkd_flag_t);
#define mkd_text mkd_generateline
/* url generator callbacks
*/
typedef char * (*mkd_callback_t)(const char*, const int, void*);
typedef void (*mkd_free_t)(char*, void*);
void mkd_e_url(void *, mkd_callback_t);
void mkd_e_flags(void *, mkd_callback_t);
void mkd_e_anchor(void *, mkd_callback_t);
void mkd_e_code_format(void*, mkd_callback_t);
void mkd_e_free(void *, mkd_free_t );
void mkd_e_data(void *, void *);
/* version#.
*/
extern char markdown_version[];
void mkd_mmiot_flags(FILE *, MMIOT *, int);
void mkd_flags_are(FILE*, mkd_flag_t, int);
void mkd_ref_prefix(MMIOT*, char*);
/* special flags for markdown() and mkd_text()
*/
#define MKD_NOLINKS 0x00000001 /* don't do link processing, block tags */
#define MKD_NOIMAGE 0x00000002 /* don't do image processing, block */
#define MKD_NOPANTS 0x00000004 /* don't run smartypants() */
#define MKD_NOHTML 0x00000008 /* don't allow raw html through AT ALL */
#define MKD_STRICT 0x00000010 /* disable SUPERSCRIPT, RELAXED_EMPHASIS */
#define MKD_TAGTEXT 0x00000020 /* process text inside an html tag; no
* , no , no html or [] expansion */
#define MKD_NO_EXT 0x00000040 /* don't allow pseudo-protocols */
#define MKD_NOEXT MKD_NO_EXT /* ^^^ (aliased for user convenience) */
#define MKD_CDATA 0x00000080 /* generate code for xml ![CDATA[...]] */
#define MKD_NOSUPERSCRIPT 0x00000100 /* no A^B */
#define MKD_NORELAXED 0x00000200 /* emphasis happens /everywhere/ */
#define MKD_NOTABLES 0x00000400 /* disallow tables */
#define MKD_NOSTRIKETHROUGH 0x00000800 /* forbid ~~strikethrough~~ */
#define MKD_TOC 0x00001000 /* do table-of-contents processing */
#define MKD_1_COMPAT 0x00002000 /* compatibility with MarkdownTest_1.0 */
#define MKD_AUTOLINK 0x00004000 /* make http://foo.com link even without <>s */
#define MKD_SAFELINK 0x00008000 /* paranoid check for link protocol */
#define MKD_NOHEADER 0x00010000 /* don't process header blocks */
#define MKD_TABSTOP 0x00020000 /* expand tabs to 4 spaces */
#define MKD_NODIVQUOTE 0x00040000 /* forbid >%class% blocks */
#define MKD_NOALPHALIST 0x00080000 /* forbid alphabetic lists */
#define MKD_NODLIST 0x00100000 /* forbid definition lists */
#define MKD_EXTRA_FOOTNOTE 0x00200000 /* enable markdown extra-style footnotes */
#define MKD_NOSTYLE 0x00400000 /* don't extract