]> granicus.if.org Git - multimarkdown/commitdiff
CHANGED: Initial public commit
authorFletcher T. Penney <fletcher@fletcherpenney.net>
Thu, 19 Jan 2017 03:43:15 +0000 (22:43 -0500)
committerFletcher T. Penney <fletcher@fletcherpenney.net>
Thu, 19 Jan 2017 03:43:15 +0000 (22:43 -0500)
154 files changed:
.gitignore
CMakeLists.txt
LICENSE.txt
Makefile
README.md
lemon/CMakeLists.txt [new file with mode: 0644]
lemon/lemon.c [new file with mode: 0644]
lemon/lempar.c [new file with mode: 0644]
src/argtable3.c [new file with mode: 0755]
src/argtable3.h [new file with mode: 0755]
src/char.c [new file with mode: 0644]
src/char.h [new file with mode: 0644]
src/char_lookup.c [new file with mode: 0644]
src/d_string.c
src/d_string.h
src/html.c [new file with mode: 0644]
src/html.h [new file with mode: 0644]
src/lexer.c [new file with mode: 0644]
src/lexer.h [new file with mode: 0644]
src/lexer.re [new file with mode: 0644]
src/libMultiMarkdown.h [new file with mode: 0644]
src/main.c
src/mmd.c [new file with mode: 0644]
src/mmd.h [new file with mode: 0644]
src/object_pool.c [new file with mode: 0644]
src/object_pool.h [new file with mode: 0644]
src/parser.c [new file with mode: 0644]
src/parser.h [new file with mode: 0644]
src/parser.out [new file with mode: 0644]
src/parser.y [new file with mode: 0644]
src/rng.c [new file with mode: 0644]
src/scanners.c [new file with mode: 0644]
src/scanners.h [new file with mode: 0644]
src/scanners.re [new file with mode: 0644]
src/stack.c [new file with mode: 0644]
src/stack.h [new file with mode: 0644]
src/token.c [new file with mode: 0644]
src/token.h [new file with mode: 0644]
src/token_pairs.c [new file with mode: 0644]
src/token_pairs.h [new file with mode: 0644]
src/uthash.h [new file with mode: 0644]
src/writer.c [new file with mode: 0644]
src/writer.h [new file with mode: 0644]
templates/README.md.in
templates/template.c.in
templates/template.h.in
test/speed-full.sh [new file with mode: 0755]
test/speed.sh [new file with mode: 0755]
tests/Disabled/Advanced Footnotes.text [new file with mode: 0644]
tests/Disabled/Advanced.html [new file with mode: 0644]
tests/Disabled/Advanced.text [new file with mode: 0644]
tests/Disabled/zEmph and Strong Complex.html [new file with mode: 0644]
tests/Disabled/zEmph and Strong Complex.text [new file with mode: 0644]
tests/MMD6Tests/Advanced Emph and Strong.html [new file with mode: 0644]
tests/MMD6Tests/Advanced Emph and Strong.htmlc [new file with mode: 0644]
tests/MMD6Tests/Advanced Emph and Strong.text [new file with mode: 0644]
tests/MMD6Tests/Amps and Angles.html [new file with mode: 0644]
tests/MMD6Tests/Amps and Angles.htmlc [new file with mode: 0644]
tests/MMD6Tests/Amps and Angles.text [new file with mode: 0644]
tests/MMD6Tests/Automatic Links.html [new file with mode: 0644]
tests/MMD6Tests/Automatic Links.htmlc [new file with mode: 0644]
tests/MMD6Tests/Automatic Links.text [new file with mode: 0644]
tests/MMD6Tests/Basic Blocks.html [new file with mode: 0644]
tests/MMD6Tests/Basic Blocks.htmlc [new file with mode: 0644]
tests/MMD6Tests/Basic Blocks.text [new file with mode: 0644]
tests/MMD6Tests/Basic Lists.html [new file with mode: 0644]
tests/MMD6Tests/Basic Lists.htmlc [new file with mode: 0644]
tests/MMD6Tests/Basic Lists.text [new file with mode: 0644]
tests/MMD6Tests/Blockquotes.html [new file with mode: 0644]
tests/MMD6Tests/Blockquotes.htmlc [new file with mode: 0644]
tests/MMD6Tests/Blockquotes.text [new file with mode: 0644]
tests/MMD6Tests/Citations.html [new file with mode: 0644]
tests/MMD6Tests/Citations.htmlc [new file with mode: 0644]
tests/MMD6Tests/Citations.text [new file with mode: 0644]
tests/MMD6Tests/Code Spans.html [new file with mode: 0644]
tests/MMD6Tests/Code Spans.htmlc [new file with mode: 0644]
tests/MMD6Tests/Code Spans.text [new file with mode: 0644]
tests/MMD6Tests/CriticMarkup.html [new file with mode: 0644]
tests/MMD6Tests/CriticMarkup.htmlc [new file with mode: 0644]
tests/MMD6Tests/CriticMarkup.text [new file with mode: 0644]
tests/MMD6Tests/Cross-References.html [new file with mode: 0644]
tests/MMD6Tests/Cross-References.htmlc [new file with mode: 0644]
tests/MMD6Tests/Cross-References.text [new file with mode: 0644]
tests/MMD6Tests/Edge Cases 2.html [new file with mode: 0644]
tests/MMD6Tests/Edge Cases 2.htmlc [new file with mode: 0644]
tests/MMD6Tests/Edge Cases 2.text [new file with mode: 0644]
tests/MMD6Tests/Edge Cases.html [new file with mode: 0644]
tests/MMD6Tests/Edge Cases.htmlc [new file with mode: 0644]
tests/MMD6Tests/Edge Cases.text [new file with mode: 0644]
tests/MMD6Tests/Emph and Strong Star.html [new file with mode: 0644]
tests/MMD6Tests/Emph and Strong Star.htmlc [new file with mode: 0644]
tests/MMD6Tests/Emph and Strong Star.text [new file with mode: 0644]
tests/MMD6Tests/Emph and Strong UL.html [new file with mode: 0644]
tests/MMD6Tests/Emph and Strong UL.htmlc [new file with mode: 0644]
tests/MMD6Tests/Emph and Strong UL.text [new file with mode: 0644]
tests/MMD6Tests/Escapes.html [new file with mode: 0644]
tests/MMD6Tests/Escapes.htmlc [new file with mode: 0644]
tests/MMD6Tests/Escapes.text [new file with mode: 0644]
tests/MMD6Tests/Fenced Code Blocks.html [new file with mode: 0644]
tests/MMD6Tests/Fenced Code Blocks.htmlc [new file with mode: 0644]
tests/MMD6Tests/Fenced Code Blocks.text [new file with mode: 0644]
tests/MMD6Tests/HTML Blocks.html [new file with mode: 0644]
tests/MMD6Tests/HTML Blocks.htmlc [new file with mode: 0644]
tests/MMD6Tests/HTML Blocks.text [new file with mode: 0644]
tests/MMD6Tests/HTML Inline.html [new file with mode: 0644]
tests/MMD6Tests/HTML Inline.htmlc [new file with mode: 0644]
tests/MMD6Tests/HTML Inline.text [new file with mode: 0644]
tests/MMD6Tests/Headers.html [new file with mode: 0644]
tests/MMD6Tests/Headers.htmlc [new file with mode: 0644]
tests/MMD6Tests/Headers.text [new file with mode: 0644]
tests/MMD6Tests/Horizontal Rules.html [new file with mode: 0644]
tests/MMD6Tests/Horizontal Rules.htmlc [new file with mode: 0644]
tests/MMD6Tests/Horizontal Rules.text [new file with mode: 0644]
tests/MMD6Tests/Indented Code Blocks.html [new file with mode: 0644]
tests/MMD6Tests/Indented Code Blocks.htmlc [new file with mode: 0644]
tests/MMD6Tests/Indented Code Blocks.text [new file with mode: 0644]
tests/MMD6Tests/Inline Footnotes.html [new file with mode: 0644]
tests/MMD6Tests/Inline Footnotes.htmlc [new file with mode: 0644]
tests/MMD6Tests/Inline Footnotes.text [new file with mode: 0644]
tests/MMD6Tests/Inline Images.html [new file with mode: 0644]
tests/MMD6Tests/Inline Images.htmlc [new file with mode: 0644]
tests/MMD6Tests/Inline Images.text [new file with mode: 0644]
tests/MMD6Tests/Inline Links.html [new file with mode: 0644]
tests/MMD6Tests/Inline Links.htmlc [new file with mode: 0644]
tests/MMD6Tests/Inline Links.text [new file with mode: 0644]
tests/MMD6Tests/Link Attributes.html [new file with mode: 0644]
tests/MMD6Tests/Link Attributes.htmlc [new file with mode: 0644]
tests/MMD6Tests/Link Attributes.text [new file with mode: 0644]
tests/MMD6Tests/Lists.html [new file with mode: 0644]
tests/MMD6Tests/Markdown Syntax.html [new file with mode: 0644]
tests/MMD6Tests/Markdown Syntax.htmlc [new file with mode: 0644]
tests/MMD6Tests/Markdown Syntax.text [new file with mode: 0644]
tests/MMD6Tests/Math.html [new file with mode: 0644]
tests/MMD6Tests/Math.htmlc [new file with mode: 0644]
tests/MMD6Tests/Math.text [new file with mode: 0644]
tests/MMD6Tests/Nested Lists.html [new file with mode: 0644]
tests/MMD6Tests/Nested Lists.htmlc [new file with mode: 0644]
tests/MMD6Tests/Nested Lists.text [new file with mode: 0644]
tests/MMD6Tests/Reference Footnotes.html [new file with mode: 0644]
tests/MMD6Tests/Reference Footnotes.htmlc [new file with mode: 0644]
tests/MMD6Tests/Reference Footnotes.text [new file with mode: 0644]
tests/MMD6Tests/Reference Images.html [new file with mode: 0644]
tests/MMD6Tests/Reference Images.htmlc [new file with mode: 0644]
tests/MMD6Tests/Reference Images.text [new file with mode: 0644]
tests/MMD6Tests/Reference Links.html [new file with mode: 0644]
tests/MMD6Tests/Reference Links.htmlc [new file with mode: 0644]
tests/MMD6Tests/Reference Links.text [new file with mode: 0644]
tests/MMD6Tests/Smart Quotes.html [new file with mode: 0644]
tests/MMD6Tests/Smart Quotes.htmlc [new file with mode: 0644]
tests/MMD6Tests/Smart Quotes.text [new file with mode: 0644]
tests/MMD6Tests/Superscript.html [new file with mode: 0644]
tests/MMD6Tests/Superscript.htmlc [new file with mode: 0644]
tests/MMD6Tests/Superscript.text [new file with mode: 0644]
tests/MarkdownTest.pl [new file with mode: 0755]

index c06b87f2e40376618e6005fa46f66327f50ccd83..2ed54b1823c378898e3aad5a4262f1fc39c18b48 100644 (file)
@@ -19,5 +19,7 @@ profile
 DerivedData
 .idea/
 
+lemon/build
+
 build-xcode
 build-xcode-debug
index ddf769ad24fe18bb500fb169aacd01c38e62cb6d..19d6bcb95270b960af3d1c7d2d562fde7531fefd 100644 (file)
@@ -5,17 +5,17 @@ cmake_minimum_required (VERSION 2.6)
 # Define Our Project
 # ==================
 
-set (My_Project_Title "C-Template")
-set (My_Project_Description "Boilerplate c project with cmake support, CuTest unit testing, and more.")
+set (My_Project_Title "MultiMarkdown 6")
+set (My_Project_Description "Lightweight markup processor to produce HTML, LaTeX, and more.")
 set (My_Project_Author "Fletcher T. Penney")
-set (My_Project_Revised_Date "2017-01-16")
-set (My_Project_Version_Major 1)
-set (My_Project_Version_Minor 0)
-set (My_Project_Version_Patch 5)
+set (My_Project_Revised_Date "2017-01-18")
+set (My_Project_Version_Major 0)
+set (My_Project_Version_Minor 1)
+set (My_Project_Version_Patch 0a)
 
 set (My_Project_Version "${My_Project_Version_Major}.${My_Project_Version_Minor}.${My_Project_Version_Patch}")
 
-set (My_Project_Copyright_Date "2015-2017")
+set (My_Project_Copyright_Date "2016 - 2017")
 set (My_Project_Copyright "Copyright © ${My_Project_Copyright_Date} ${My_Project_Author}.")
 
 string(TOUPPER ${My_Project_Title} My_Project_Title_Caps  )
@@ -24,6 +24,10 @@ string(REGEX REPLACE " " "_" My_Project_Title_Caps ${My_Project_Title_Caps} )
 project (${My_Project_Title})
 
 
+# Enable this if you want to be warned about struct alignment
+# add_definitions ("-Wpadded")
+
+
 # =========================
 # Build Submodules (if any)
 # =========================
@@ -125,9 +129,9 @@ ENDMACRO(ADD_LINKED_FRAMEWORK)
 
 file(READ ${PROJECT_SOURCE_DIR}/LICENSE.txt My_Project_License)
 
-string(REGEX REPLACE "\n" "\n\t" My_Project_License_Indent ${My_Project_License})
+string(REGEX REPLACE "\n" "\n\t" My_Project_License_Indented ${My_Project_License})
 
-string(REGEX REPLACE "\"" "\\\\\"" My_Project_License_Escaped ${My_Project_License_Indent})
+string(REGEX REPLACE "\"" "\\\\\"" My_Project_License_Escaped ${My_Project_License_Indented})
 
 string(REGEX REPLACE "\n" "\\\\n\"\\\\\n\"" My_Project_License_Literal ${My_Project_License_Escaped})
 
@@ -160,11 +164,38 @@ configure_file (
 
 # src_files are the primary files, and will be included in doxygen documentation
 set(src_files
-#      src/foo.c
+       src/argtable3.c
+       src/char.c
+       src/d_string.c
+       src/html.c
+       src/lexer.c
+       src/mmd.c
+       src/object_pool.c
+       src/parser.c
+       src/rng.c
+       src/scanners.c
+       src/stack.c
+       src/token.c
+       src/token_pairs.c
+       src/writer.c
 )
 
 # Primary header files, also for doxygen documentation
 set(header_files
+       src/argtable3.h
+       src/d_string.h
+       src/char.h
+       src/html.h
+       src/lexer.h
+       src/libMultiMarkdown.h
+       src/mmd.h
+       src/object_pool.h
+       src/scanners.h
+       src/stack.h
+       src/token.h
+       src/token_pairs.h
+       src/uthash.h
+       src/writer.h
 )
 
 # Public headers, will be installed in 'include'
@@ -174,11 +205,9 @@ set(public_header_files
 
 # Utility source files will not be included in doxygen
 set(src_utility_files
-#      src/d_string.c
 )
 
 set(header_utility_files
-#      src/d_string.h
        ${PROJECT_BINARY_DIR}/version.h
 )
 
@@ -230,10 +259,10 @@ else()
                add_test( test ${PROJECT_BINARY_DIR}/run_tests)
 
                # valgrind memory testing
-               find_program (MEMORYCHECK_COMMAND valgrind)
-               SET (MEMORYCHECK_COMMAND_OPTIONS --leak-check=full --error-exitcode=1)
-
-               add_test( memory_test ${MEMORYCHECK_COMMAND} ${MEMORYCHECK_COMMAND_OPTIONS} ${PROJECT_BINARY_DIR}/run_tests)
+       #       find_program (MEMORYCHECK_COMMAND valgrind)
+       #       SET (MEMORYCHECK_COMMAND_OPTIONS --leak-check=full --error-exitcode=1)
+       #
+       #       add_test( memory_test ${MEMORYCHECK_COMMAND} ${MEMORYCHECK_COMMAND_OPTIONS} ${PROJECT_BINARY_DIR}/run_tests)
 
        endif()
 endif()
@@ -302,32 +331,33 @@ endif (WIN32)
 # ==============
 
 # Create a library?
-# add_library(libFOO STATIC
-#      ${src_files}
-#      ${src_utility_files}
-#      ${header_files}
-#      ${header_utility_files}
-# )
+add_library(libMultiMarkdown STATIC
+       ${src_files}
+       ${src_utility_files}
+       ${header_files}
+       ${header_utility_files}
+)
+
+ADD_PUBLIC_HEADER(libMultiMarkdown src/libMultiMarkdown.h)
+ADD_PUBLIC_HEADER(libMultiMarkdown src/d_string.h)
 
 # remove the extra "lib" from "liblibFOO"
-# SET_TARGET_PROPERTIES(libFOO PROPERTIES PREFIX "")
+SET_TARGET_PROPERTIES(libMultiMarkdown PROPERTIES PREFIX "")
 
 # Create a command-line app?
 # if (NOT DEFINED TEST)
-#      add_executable(main
-#              src/main.c
-#              src/d_string.c
-#              src/d_string.h
-#              ${header_files}
-#      )
+       add_executable(multimarkdown
+               src/d_string.c
+               src/main.c
+       )
 # 
 #      Link the library to the app?
-#      target_link_libraries(main libFOO)
+       target_link_libraries(multimarkdown libMultiMarkdown)
 # endif()
 
 # Xcode settings for fat binaries
-# set_target_properties(libFOO PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "NO")
-# set_target_properties(main PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "NO")
+set_target_properties(libMultiMarkdown PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "NO")
+set_target_properties(multimarkdown PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "NO")
 
 
 # ==========================
@@ -371,3 +401,27 @@ endif (WIN32)
 set (CPACK_PACKAGE_INSTALL_DIRECTORY ${PROJECT})
 
 include (CPack)
+
+
+# ======================
+# Integration Test Suite
+# ======================
+
+enable_testing()
+
+function(ADD_MMD_TEST NAME FLAGS FOLDER EXTENSION)
+       add_test ( ${NAME}
+               ${PROJECT_SOURCE_DIR}/tests/MarkdownTest.pl
+               --Script=${CMAKE_CURRENT_BINARY_DIR}/multimarkdown
+               --testdir=${PROJECT_SOURCE_DIR}/tests/${FOLDER}
+               "--Flags=${FLAGS}"
+               --ext=${EXTENSION}
+       )
+
+endfunction(ADD_MMD_TEST)
+
+
+# MMD 6
+ADD_MMD_TEST(mmd-6 "" MMD6Tests html)
+
+ADD_MMD_TEST(mmd-6-compat "-c" MMD6Tests htmlc)
index 0f416df1a7deeb223f07a4d2c41d53101b49b8e1..3a559ac12ed08cd9ab87d864922b359ac23c7e12 100644 (file)
@@ -1,4 +1,4 @@
-The `c-template` project is released under the MIT License.
+The `MultiMarkdown 6` project is released under the MIT License..
 
 GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
 
index 13802fc54077b8348b1690c8522fd8f821c05f7d..5be146ff36f1e17d220a65fd75db060234f46932 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,5 @@
 BUILD_DIR = build
+DOC_DIR = documentation
 XCODE_BUILD_DIR = build-xcode
 XCODE_DEBUG_BUILD_DIR = build-xcode-debug
 
@@ -18,7 +19,7 @@ zip: $(BUILD_DIR)
 .PHONY : debug
 debug: $(BUILD_DIR)
        cd $(BUILD_DIR); \
-       cmake -DTEST=1 ..
+       cmake -DTEST=1 DCMAKE_BUILD_TYPE=DEBUG ..
 
 # analyze target enables use of clang's scan-build (if installed)
 # will then need to run 'scan-build make' to compile and analyze
@@ -27,15 +28,20 @@ debug: $(BUILD_DIR)
 .PHONY : analyze
 analyze: $(BUILD_DIR)
        cd $(BUILD_DIR); \
-       scan-build cmake -DTEST=1 ..
+       scan-build cmake -DTEST=1 DCMAKE_BUILD_TYPE=DEBUG ..
+
+.PHONY : map
+map:
+       cd $(BUILD_DIR); \
+       ../tools/enumsToPerl.pl ../src/libMultiMarkdown.h enumMap.txt;
 
 # Create xcode project
 # You can then build within XCode, or using the commands:
 #      xcodebuild -configuration Debug
 #      xcodebuild -configuration Release
 .PHONY : xcode
-xcode: $(XCOD_BUILD_DIR)
-       cd $(XCOD_BUILD_DIR); \
+xcode: $(XCODE_BUILD_DIR)
+       cd $(XCODE_BUILD_DIR); \
        cmake -G Xcode ..
 
 .PHONY : xcode-debug
@@ -69,10 +75,11 @@ windows-zip-32: $(BUILD_DIR)
 
 # Build the documentation using doxygen
 .PHONY : documentation
-documentation: $(BUILD_DIR)
-       cd $(BUILD_DIR); \
+documentation:
+       -mkdir $(DOC_DIR) 2>/dev/null; \
+       cd $(DOC_DIR); \
        cmake -DDOCUMENTATION=1 ..; cd ..; \
-       doxygen build/doxygen.conf
+       doxygen $(DOC_DIR)/doxygen.conf
 
 .PHONY : gh-pages
 gh-pages: documentation
index a3fa6a274b363e0ac19e1486acd7be2262ee5463..5ef2339db6fed5943351b33f0e353f175fe403d9 100644 (file)
--- a/README.md
+++ b/README.md
 
 |            |                           |  
 | ---------- | ------------------------- |  
-| Title:     | C-Template        |  
+| Title:     | MultiMarkdown 6        |  
 | Author:    | Fletcher T. Penney       |  
 | Date:      | 2017-01-16 |  
-| Copyright: | Copyright © 2015-2017 Fletcher T. Penney.    |  
-| Version:   | 1.0.5      |  
+| Copyright: | Copyright © 2016 - 2017 Fletcher T. Penney.    |  
+| Version:   | 0.1.0a      |  
 
 
-## Introduction ##
+## An Announcement! ##
 
-This template was created out of a desire to simplify some of the setup and
-configuration that I was doing over and over each time I started a new project.
-Additionally, I wanted to try to start encouraging some "better practices"
-(though not necessarily "best practices"):
+I would like to officially announce that MultiMarkdown version 6 is in public
+alpha.  It's finally at a point where it is usable, but there are quite a few
+caveats.
 
-1. [Test-driven development][tdd] -- My development of MultiMarkdown
-       focused on integration testing, but really had no unit testing to
-       speak of.  Some newer projects I began working on were a bit math-
-       heavy, and ensuring that each piece works properly became even more
-       important.  It was also nice to be able to actually develop code that
-       could do *something* (via the test suite), even though the project as
-       a whole was nowhere near complete.)  To accomplish this, I include the
-       [CuTest] project to support writing tests for your code.
+This post is a way for me to organize some of my thoughts, provide some
+history for those who are interested, and to provide some tips and tricks from
+my experiences for those who are working on their own products.
 
-2.  Use of the [cmake] build system.  `cmake` is not perfect by any
-       means, but it does offer some very useful features and a means for
-       better integrating the compilation and packaging/installation aspects
-       of development.  Rather than reinventing the wheel each time, this
-       setup incorporates basic `cmake` functionality to make it easy to 
-       control how your project is compiled, and includes automated generation
-       of the test command.
+But first, some background...
 
-3.     Templates -- `cmake` has a reasonable templating system, so that you
-       can define basic variables (e.g. author, project name, etc.) and allow
-       `cmake` to combine those elements to ensure consistency across source
-       code and README files.
 
-4.     Documentation -- some default setup to allow for [Doxygen]-generated
-       documentation.  The generated `README.md` file is used as the main 
-       page, and the source c/header files are included.  Naturally, Doxygen
-       is a complex system, so you're responsible for figuring out how to 
-       properly document your code.
+### Why a New Version? ###
 
-5.     Simplify `git` a touch -- In my larger projects, I make heavy use of
-       git modules.  One project may make use of 20-30 modules, which are
-       designed to be re-usable across other projects.  I found that I was
-       spending too much time making sure that I had the latest version
-       of a module checked out, so I created two scripts to help me keep
-       my modules in line: `link_git_modules` and `update_git_modules`.
-       You run the `link` script once to ensure that your modules are properly
-       set up, and can then run the `update` script at any time to be sure
-       you've pulled the latest version.  One advantage of this is that your
-       modules are set to a branch, rather than just a detached commit. It
-       may or may not work for your needs, but it saves me a bunch of time
-       and headache.
+MultiMarkdown version 5 was released in November of 2015, but the codebase was
+essentially the same as that of v4 -- and that was released in beta in April
+of 2013.  A few key things prompted work on a new version:
 
+* Accuracy -- MMD v4 and v5 were the most accurate versions yet, and a lot of
+effort went into finding and resolving various edge cases.  However, it began
+to feel like a game of whack-a-mole where new bugs would creep in every time I
+fixed an old one.  The PEG began to feel rather convoluted in spots, even
+though it did allow for a precise (if not always accurate) specification of
+the grammar.
 
-[tdd]: https://en.wikipedia.org/wiki/Test-driven_development
-[cmake]:       http://www.cmake.org/
-[CuTest]:      http://cutest.sourceforge.net
-[Doxygen]:     http://www.stack.nl/~dimitri/doxygen/
+* Performance -- "Back in the day" [peg-markdown] was one of the fastest
+Markdown parsers around.  MMD v3 was based on peg-markdown, and would leap-
+frog with it in terms of performance.  Then [CommonMark] was released, which
+was a bit faster. Then a couple of years went by and CommonMark became *much*
+faster -- in one of my test suites, MMD v 5.4.0 takes about 25 times longer to
+process  a long document than CommonMark 0.27.0.
 
+[peg-markdown]:        https://github.com/jgm/peg-markdown
+[CommonMark]:  http://commonmark.org/
 
-## How do I use it? ##
+Last spring, I decided I wanted to rewrite MultiMarkdown from scratch,
+building the parser myself rather than relying on a pre-rolled solution.  (I
+had been using [greg](https://github.com/ooc-lang/greg) to compile the PEG
+into parser code.  It worked well overall, but lacked some features I needed,
+requiring a lot of workarounds.)
 
-You can download the source from [github] and get to work. The file "IMPORTANT"
-contains instructions on the various build commands you can use.
 
+## First Attempt ##
 
-I recommend using the following script to automatically create a new git repo,
-pull in the default project template, and configure git-flow.  You simply have
-to rename your project directory from `new-project` to whatever you desire:
+My first attempt  started by hand-crafting a parser that scanned through the
+document a line at a time, deciding what to do with each line as it found
+them.  I used regex parsers made with [re2c](http://re2c.org/index.html) to
+help classify each line, and then a separate parser layer to process groups of
+lines into blocks.  Initially this approach worked well, and was really
+efficient.  But I quickly began to code my way into a dead-end -- the strategy
+was not elegant enough to handle things like nested lists, etc.
 
+One thing that did turn out well from the first attempt, however, was an
+approach for handling `<emph>` and `<strong>` parsing.  I've learned over the
+years that this can be one of the hardest parts of coding accurately for
+Markdown.  There are many examples that are obvious to a person, but difficult
+to properly "explain" how to parse to a computer.
 
-       #!/bin/sh
+No solution is perfect, but I developed an approach that seems to accurately
+handle a wide range of situations without a great deal of complexity:
 
-       git init new-project
+1.  Scan the documents for asterisks (`*`).  Each one will be handled one at a
+time.
 
-       cd new-project
+2.  Unlike brackets (`[` and `]`), an asterisk is "ambidextrous", in that it
+may be able to open a matched pair of asterisks, close a pair, or both.  For
+example, in `foo *bar* foo`:
 
-       git remote add "template" https://github.com/fletcher/c-template.git
+       1.      The first asterisk can open a pair, but not close one.
 
-       git pull template master
+       2.      The second asterisk can close a pair, but not open one.
 
-       git flow init -d
+3.  So, once the asterisks have been identified, each has to be examined to
+determine whether it can open/close/both.  The algorithm is not that complex,
+but I'll describe it in general terms.  Check the code for more specifics.
+This approach seems to work, but might still need some slight tweaking.  In
+the future, I'll codify this better in language rather than just in code.
 
-       git checkout develop
+       1.      If there is whitespace to the left of an asterisk, it can't close.
 
+       2.      If there is whitespace or punctuation to the right it can't open.
 
-Using this approach, you can define your own `origin` remote if you like, but
-the `template` remote can be used to update the core project files should any
-improvements come about:
+       3.      "Runs" of asterisks, e.g. `**bar` are treated as a unit in terms of
+       looking left/right.
 
-       git checkout develop
-       git merge template master
+       4.      Asterisks inside a word are a bit trickier -- we look at the number of
+       asterisks before the word, the number in the current run, and the number
+       of asterisks after the word to determine which combinations, if any, are
+       permitted.
 
-**NOTE**: `cmake` is a complex suite of utilities, and if you have trouble you
-will need to get support elsewhere.  If you find errors in this template, by
-all means I want to hear about them and fix them, but this is just a basic 
-framework to get you started.  In all likelihood, all but the most basic
-projects will need some customization.
+4.  Once all asterisks have been tagged as able to open/close/both, we proceed
+through them in order:
 
+       1.      When we encounter a tag that can close, we look to see if there is a
+       previous opener that has not been paired off.  If so, pair the two and
+       remove the opener from the list of available asterisks.
 
-[github]:      https://github.com/fletcher/c-template
+       2.      When we encounter an opener, add it to the stack of available openers.
+
+       3.      When encounter an asterisk that can do both, see if it can close an
+       existing opener.  If not, then add it to the stack.
+
+5.  After all tokens in the block have been paired, then we look for nesting
+pairs of asterisks in order to create `<emph>` and `<strong>` sets.  For
+example, assume we have six asterisks wrapped around a word, three in front,
+and three after.  The asterisks are indicated with numbers: `123foo456`. We
+proceed in the following manner:
 
+       1.      Based on the pairing algorithm above, these asterisks would be paired as
+       follows, with matching asterisks sharing numbers -- `123foo321`.
+
+       2.      Moving forwards, we come to asterisk "1".  It is followed by an
+       asterisk, so we check to see if they should be grouped as a `<strong>`.
+       Since the "1" asterisks are wrapped immediately outside the "2" asterisks,
+       they are joined together.  More than two pairs can't be joined, so we now
+       get the following -- `112foo211`, where the "11" represents the opening
+       and closing of a `<strong>`, and the "2" represents a `<emph>`.
+
+6.  When matching a pair, any unclosed openers that are on the stack are
+removed, preventing pairs from "crossing" or "intersecting".  Pairs can wrap
+around each other, e.g. `[(foo)]`, but not intersect like `[(foo])`.  In the
+second case, the brackets would close, removing the `(` from the stack.
+
+7.  This same approach is used in all tokens that are matched in pairs--
+`[foo]`, `(foo)`, `_foo_`, etc.  There's slightly more to it, but once you
+figure out how to assign opening/closing ability, the rest is easy.  By using
+a stack to track available openers, it can be performed efficiently.
+
+In my testing, this approach has worked quite well.  It handles all the basic
+scenarios I've thrown at it, and all of the "basic" and "devious" edge cases I
+have thought of (some of these don't necessarily have a "right" answer -- but
+v6 gives consistency answers that seem as reasonable as any others to me).
+There are also three more edge cases I've come up can still stump it, and
+ironically they are handled correctly by most implementations.  They just
+don't follow the rules above.  I'll continue to work on this.
+
+In the end, I scrapped this effort, but kept the lessons learned in the token
+pairing algorithm.
 
-## Configuration ##
 
+## Second Attempt ##
+
+I tried again this past Fall.  This time, I approached the problem with lots
+of reading.  *Lots and lots* of reading -- tons of websites, computer science
+journal articles, PhD theses, etc.  Learned a lot about lexers, and a lot
+about parsers, including hand-crafting vs using parser generators.  In brief:
+
+1. I learned about the [Aho–Corasick algorithm], which is a great way to
+efficiently search a string for multiple target strings at once.  I used this
+to create a custom lexer to identify tokens in a MultiMarkdown text document
+(e.g. `*`, `[ `, `{++`, etc.).  I learned a lot, and had a good time working
+out the implementation.  This code efficiently allowed me to break a string of
+text into the tokens that mattered for Markdown parsing.
+
+2. However, in a few instances I really needed some features of regular
+expressions to simplify more complex structures. After a quick bit of testing,
+using re2c to create a tokenizer was just as efficient, and allowed me to
+incorporate some regex functionality that simplified later parsing.  I'll keep
+the Aho-Corasick stuff around, and will probably experiment more with it
+later.  But I didn't need it for MMD now.  `lexer.re` contains the source for
+the tokenizer.
 
-### CMakeLists.txt File ###
+[Aho–Corasick algorithm]: https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm
 
-First, you should update the project information under the "Define Our Project"
-section, including the title, description, etc.  This information will be used
-to update the README, as well as to create the `version.h` file so that the 
-project can have access to its own version number.
+I looked long and hard for a way to simplify the parsing algorithm to try and
+"touch" each token only once.  Ideally, the program could step through each
+token, and decide when to create a new block, when to pair things together,
+etc.  But I'm not convinced it's possible.  Since Markdown's grammar varies
+based on context, it seems to work best when handled in distinct phases:
+
+1. Tokenize the string to identify key sections of text.  This includes line
+breaks, allowing the text to be examined one line at time.
+
+2. Join series of lines together into blocks, such as paragraphs, code blocks,
+lists, etc.
+
+3. The tokens inside each block can then be paired together to create more
+complex syntax such as links, strong, emphasis, etc.
+
+To handle the block parsing, I started off using the [Aho-Corasick] code to
+handle my first attempt.  I had actually implemented some basic regex
+functionality, and used that to group lines together to create blocks.  But
+this quickly fell apart in the face of more complex structures such as
+recursive lists.   After a lot of searching, and *tons* more reading, I
+ultimately decided to use a parser generator to handle the task of group lines
+into blocks.  `parser.y` has the source for this, and it is processed by the
+[lemon](http://www.hwaci.com/sw/lemon/) parser generator to create the actual
+code.
+
+I chose to do this because hand-crafting the block parser would be complex.
+The end result would likely be difficult to read and understand, which would
+make it difficult to update later on.  Using the parser generator allows me to
+write things out in a way that can more easily be understood by a person.  In
+all likelihood, the performance is probably as good as anything I could do
+anyway, if not better.
+
+Because lemon is a LALR(1) parser, it does require a bit of thinking ahead
+about how to create the grammar used.  But so far, it has been able to handle
+everything I have thrown at it.
+
+
+## Optimization ##
+
+One of my goals for MMD 6 was performance.  So I've paid attention to speed
+along the way, and have tried to use a few tricks to keep things fast.  Here
+are some things I've learned along the way.  In no particular order:
+
+
+### Memory Allocation ###
+
+When parsing a long document, a *lot* of token structures are created.  Each
+one requires a small bit of memory to be allocated.  In aggregate, that time
+added up and slowed down performance.
+
+After reading for a bit, I ended up coming up with an approach that uses
+larger chunks of memory.  I allocate pools of of memory in large slabs for
+smaller "objects"".  For example, I allocate memory for 1024 tokens at a
+single time, and then dole that memory out as needed.  When the slab is empty,
+a new one is allocated.  This dramatically improved performance.
+
+When pairing tokens, I created a new stack for each block.  I realized that an
+empty stack didn't have any "leftover" cruft to interfere with re-use, so I
+just used one for the entire document.  Again a sizeable improvement in
+performance from only allocating one object instead of many.  When recursing
+to a deeper level, the stack just gets deeper, but earlier levels aren't
+modified.
 
-You will then need to update the various groups in the "Source Files" section
-so that Cmake will be able to determine which files are used to build your
-project.  For reasons that will become clear later, try to follow the
-suggestions for the different groups of files.
+Speaking of tokens, I realized that the average document contains a lot of
+single spaces (there's one between every two words I have written, for
+example.)  The vast majority of the time, these single spaces have no effect
+on the output of Markdown documents.  I changed my whitespace token search to
+only flag runs of 2 or more spaces, dramatically reducing the number of
+tokens.  This gives the benefit of needing fewer memory allocations, and also
+reduces the number of tokens that need to be processed later on.  The only
+downside is remember to check for a single space character in a few instances
+where it matters.
 
-You then need to define your targets, such as a library, or executable, etc.
-Obviously, this will depend on the needs of your project.  You can also add
-custom steps based on the Target OS (OS X, Windows, *nix, etc.).
 
-You can use CPack to generate installers for your software.  This can be
-complex, and you will need to modify this section heavily.
+### Proper input buffering ###
 
-CuTest is used by default to provide unit testing (see below), but you
-can also use CMake/CTest to provide integration testing.  Again, this will
-be up to you to configure.
+When I first began last spring, I was amazed to see how much time was being
+spent by MultiMarkdown simply reading the input file.  Then I discovered it
+was because I was reading it one character at a time.  I switched to using a
+buffered read approach and the time to read the file went to almost nothing. I
+experimented with different buffer sizes, but they did not seem to make a
+measurable difference.
 
 
-### CuTest ###
+### Output Buffering ###
+
+I experimented with different approaches to creating the output after parsing.
+I tried printing directly to `stdout`, and even played with different
+buffering settings.  None of those seemed to work well, and all were slower
+than using the `d_string` approach (formerly call `GString` in MMD 5).
 
-[CuTest] provides a means to integrate unit testing with your C source code.
-Once you get the hang of it, it's easy to use.
 
+### Fast Searches ###
 
-### Doxygen ###
+After getting basic Markdown functionality complete, I discovered during
+testing that the time required to parse a document grew exponentially as the
+document grew longer.  Performance was on par with CommonMark for shorter
+documents, but fell increasingly behind in larger tests.  Time profiling found
+that the culprit was searching for link definitions when they didn't exist.
+My first approach was to keep a stack of used link definitions, and to iterate
+through them when necessary.  In long documents, this performs very poorly.
+More research and I ended up using
+[uthash](http://troydhanson.github.io/uthash/).  This allows me to search for
+a link (or footnote, etc.) by "name" rather than searching through an array.
+This allowed me to get MMD's performance back to O(n), taking roughly twice as
+much time to process a document that is twice as long.
 
-[Doxygen] is used to generate documentation from the source code itself. 
-Properly configuring your source for this is up to you.  You can modify the
-`doxygen.conf.in` template with your desired settings as desired, but most
-of the basics are handled for you based on your CMake configuration.
 
+### Efficient Utility Functions ###
 
-### GitHub Pages Support ###
+It is frequently necessary when parsing Markdown to check what sort of
+character we are dealing with at a certain position -- a letter, whitespace,
+punctuation, etc.  I created a lookup table for this via `char_lookup.c` and
+hard-coded it in `char.c`.  These routines allow me to quickly, and
+consistently, classify any byte within a document. This saved a lot of
+programming time, and saved time tracking down bugs from handling things
+slightly differently under different circumstances.  I also suspect it
+improved performance, but don't have the data to back it up.
 
-The `configure-gh-pages` script sets up a `documentation` directory that is 
-linked to a `gh-pages` branch of the project.  You can then run `make gh-pages` 
-to update the documentation in this directory.  Commit and push to your origin,
-and your projects gh-page is updated.
 
+### Testing While Writing ###
 
-### Makefile ###
+I developed several chunks of code in parallel while creating MMD 6.  The vast
+majority of it was developed largely in a [test-driven development] approach.
+The other code was largely created with extensive unit testing to accomplish
+this.
 
-The overall build process is controlled by the master `Makefile`.  It provides
-the following commands:
+[test-driven development]: https://en.wikipedia.org/wiki/Test-driven_development
 
-       make
-       make release
+MMD isn't particularly amenable to this approach at the small level, but
+instead I relied more on integration testing with an ever-growing collection
+of text files and the corresponding HTML files in the MMD 6 test suite.  This
+allowed me to ensure new features work properly and that old features aren't
+broken.  At this time, there are 29 text files in the test suite, and many
+more to come.
 
-Generate the CMake build files for use or distribution.  Once complete you will
-need to change to the `build` directory and run `make`, `make test`, and
-`cpack` as desired.
 
-       make zip
+### Other Lessons ###
 
-Direct CPack to create a zip installer rather than a graphical installer.
+Some things that didn't do me any good....
 
-       make debug
+I considered differences between using `malloc` and `calloc` when initializing
+tokens.  The time saved  by using `malloc` was basically exactly offset by the
+initial time required to initialize the token to default null values as
+compared to using `calloc`.  When trying `calloc` failed to help me out
+(thinking that clearing a single slab in the object pool would be faster), I
+stuck with `malloc` as it makes more sense to me in my workflow.
 
-Generate build files for [CuTest] unit testing.  In the `build` directory, 
-run `make`, then `make test`.
+I read a bit about [struct padding] and reordered some of my structs.  It was
+until later that I discovered the `-Wpadded` option, and it's not clear
+whether my changes modified anything.  Since the structs were being padded
+automatically, there was no noticeable performance change, and I didn't have
+the tools to measure whether I could have improved memory usage at all.  Not
+sure this would be worth the effort -- much lower hanging fruit available.
 
-       make analyze
+[struct padding]: http://www.catb.org/esr/structure-packing/
 
-If you have `clang` installed, this will generate debug build files with the
-`scan-build` command.  In the `build` directory, run `scan-build -V make`
-to compile the software and view the static analysis results.
 
-       make xcode
+## Differences in MultiMarkdown Itself ##
 
-Build a project file for Xcode on OS X.
+MultiMarkdown v6 is mostly about making a better MMD parser, but it will
+likely involve a few changes to the MultiMarkdown language itself.
 
-       make windows
-       make windows-zip
-       make windows-32
-       make windows-zip-32
 
-Use the MinGW software to cross-compile for Windows on a *nix machine.  You can
-specify the 32 bit option, and also the zip option as indicated.
+1. I am thinking about removing Setext headers from the language.  I almost
+never use them, much preferring to use ATX style headers (`# foo #`).
+Additionally, I have never liked the fact that Setext headers allow the
+meaning of a line to be completely changed by the following line.  It makes
+the parsing slightly more difficult on a technical level (requiring some
+backtracking at times).  I'm not 100% certain on this, but right now I believe
+it's the only Markdown feature that doesn't exist in MMD 6 yet.
 
-       make documentation
+2. Whitespace is not allowed between the text brackets and label brackets in
+reference links, images, footnotes, etc.  For example `[foo] [bar]` will no
+longer be the same as `[foo][bar]`.
 
-Build the [Doxygen]-generated documentation.
+3. Link and image titles can be quoted with `'foo'`, `"foo"`, or `(foo)`.
 
-       make clean
+4. HTML elements are handled slightly differently.  There is no longer a
+`markdown="1"` feature.  Instead, HTML elements that are on a line by
+themselves will open an HTML block that will cause the rest of the "paragraph"
+to be treated as HTML such that Markdown will not be parsed in side of it.
+HTML block-level tags are even "stronger" at starting an HTML block.  It is
+not quite as complex as the approach used in CommonMark, but is similar under
+most circumstances.
 
-Clean out the `build` directory.  Be sure to run this before running another
-command.
+       For example, this would not be parsed:
 
+               <div>
+               *foo*
+               </div>
 
-## Git Submodules ##
+       But this would be:
 
-Apparently, submodules are a rather controversial feature in git.  For me,
-however, they have proven invaluable.  My most active projects depend on each
-other, and the submodule feature allows me to easily keep everything up to
-date.  That said, however, I quickly realized that submodules don't work very
-well using default commands.
+               <div>
 
-The problem is that I want to always use the latest version of my submodules.
-This is more easily accomplished when the submodule is set to the `master`
-branch of the original repository, rather than a detached commit as happens
-by default.  In order to easily keep all submodules updated, there are two 
-scripts:
+               *foo*
 
-1. `link_git_modules` -- this script is generally only run when the master
-repository is first cloned, but can also be run after a new submodule is 
-added.  It causes the submodules to automatically track the master branch.
-If you need to modify this, there are instructions in the script itself 
-explaining how to modify it on a per submodule basis.  Running this script 
-more than one time will not hurt anything.
+               </div>
 
-2. `update_git_modules` -- this script simply causes each submodule to be
-updated to the latest commit in the original repository.  Again, running it
-multiple times doesn't hurt anything.
+5. I haven't worked a lot yet on the MMD-specific features, so there may be
+more changes to come.  One thing I do anticipate is that if fenced code blocks
+stay, they will work slightly differently.  Currently, an opening fence
+doesn't mean anything unless there is a closing fence that follows it.  Again,
+this requires backtracking in the parser.  I suspect that an opening fence
+will definitely open a code block.  If there is no closing fence, then the
+rest of the document will remain inside the code block.  This is the approach
+used by CommonMark and it's a reasonable one, IMO.
 
 
-## Source File Templates ##
+## Where Does MultiMarkdown 6 Stand? ##
 
-In the `templates` directory are two files, `template.c.in` and
-`template.h.in`.  These are used to create default source files that include
-the project title, copyright, license, etc. They are also set up to include
-some example information for [Doxygen] and [CuTest].
 
+### Features ###
 
-## License ##
+I *think* that all basic Markdown features have been implemented, except for
+Setext headers, as mentioned above.  Additionally, the following MultiMarkdown
+features have been implemented:
+
+* Automatic cross-reference targets
+* Basic Citation support
+* CriticMarkup support
+* Inline and reference footnotes
+* Image and Link attributes (attributes can now be used with inline links as
+       well as reference links)
+* Math support
+* Smart quotes (support for languages other than english is not fully
+       implemented yet)
+* Superscripts/subscripts
+
+
+Things that are partially completed:
+
+* Citations -- still need:
+       * Syntax for "not cited" entries
+       * Output format
+       * HTML --> separate footnotes and citations?
+       * Locators required?
+* CriticMarkup -- need to decide:
+       * How to handle CM stretches that include blank lines
+* Fenced code blocks
+
+
+Things yet to be completed:
 
-The `c-template` project is released under the MIT License.
+* Multiple blocks inside of reference footnotes
+* Manually specified labels for headers
+* Definition lists
+* Abbreviations
+* Metadata
+* Glossaries
+* Tables
+* Table of Contents
+* File Transclusion
 
-GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
 
-       https://github.com/fletcher/MultiMarkdown-4/
+### Accuracy ###
 
-MMD 4 is released under both the MIT License and GPL.
+MultiMarkdown v6 successfully parses the Markdown [syntax page], except for
+the Setext header at the top.  It passes the 29 test files currently in place.
+There are a few ad
 
+[syntax page]: https://daringfireball.net/projects/markdown/syntax
 
-CuTest is released under the zlib/libpng license. See CuTest.c for the text
-of the license.
 
+### Performance ###
 
-## The MIT License ##
+Basic tests show that currently MMD 6 takes about 20-25% longer the CommonMark
+0.27.0 to process long files (e.g. 0.2 MB).  However, it is around 5% *faster*
+than CommonMark when parsing a shorter file (27 kB) (measured by parsing the
+same file 200 times over).  This test suite is performed by using the Markdown
+[syntax page], modified to avoid the use of the Setext header at the top.  The
+longer files tested are created by copying the same syntax page onto itself,
+thereby doubling the length of the file with each iteration.
 
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+The largest file I test is approximately 108 MB (4096 copies of the syntax
+page).  On my machine (2012 Mac mini with 2.3 GHz Intel Core i7, 16 GB RAM),
+it takes approximately 4.4 seconds to parse with MMD 6 and 3.7 seconds with
+CommonMark.  MMD 6 processes approximately 25 MB/s on this test file.
+CommonMark 0.27.0 gets about 29 MB/s on the same machine.
 
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
+There are some slight variations with the smaller test files (8-32 copies),
+but overall the performance of both programs (MMD 6 and CommonMark) are
+roughly linear as the test file gets bigger (double the file size and it takes
+twice as long to parse, aka O(n)).
+
+Out of curiosity, I ran the same tests on the original Markdown.pl by Gruber
+(v 1.0.2b8).  It took approximately 178 seconds to parse 128 copies of the
+file (3.4 MB) and was demonstrating quadratic performance characteristics
+(double the file size and it takes 2^2 or 4 times longer to process, aka
+O(n^2)). I didn't bother running it on larger versions of the test file.  For
+comparison, MMD 6 can process 128 copies in approximately 140 msec.
+
+Of note, the throughput speed drops when testing more complicated files
+containing more advanced MultiMarkdown features, though it still seems to
+maintain linear performance characteristics.  A second test file is created by
+concatenating all of the test suite files (including the Markdown syntax
+file).  In this case, MMD gets about 13 MB/s.  CommonMark doesn't support
+these additional features, so testing it with that file is not relevant.  I
+will work to see whether there are certain features in particular that are
+more challenging and see whether they can be reworked to improve performance.
+
+As above, I have done some high level optimization of the parse strategy, but
+I'm sure there's still a lot of room for further improvement to be made.
+Suggestions welcome!
+
+
+## License ##
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
diff --git a/lemon/CMakeLists.txt b/lemon/CMakeLists.txt
new file mode 100644 (file)
index 0000000..87b42fc
--- /dev/null
@@ -0,0 +1,11 @@
+cmake_minimum_required (VERSION 2.6)
+
+# Quick file to build lemon parser generator
+
+add_executable(lemon
+       lemon.c
+)
+
+configure_file(
+       lempar.c ${PROJECT_BINARY_DIR}/lempar.c COPYONLY
+)
diff --git a/lemon/lemon.c b/lemon/lemon.c
new file mode 100644 (file)
index 0000000..0fa3d63
--- /dev/null
@@ -0,0 +1,5437 @@
+/*
+** This file contains all sources (including headers) to the LEMON
+** LALR(1) parser generator.  The sources have been combined into a
+** single file to make it easy to include LEMON in the source tree
+** and Makefile of another program.
+**
+** The author of this program disclaims copyright.
+*/
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#define ISSPACE(X) isspace((unsigned char)(X))
+#define ISDIGIT(X) isdigit((unsigned char)(X))
+#define ISALNUM(X) isalnum((unsigned char)(X))
+#define ISALPHA(X) isalpha((unsigned char)(X))
+#define ISUPPER(X) isupper((unsigned char)(X))
+#define ISLOWER(X) islower((unsigned char)(X))
+
+
+#ifndef __WIN32__
+#   if defined(_WIN32) || defined(WIN32)
+#       define __WIN32__
+#   endif
+#endif
+
+#ifdef __WIN32__
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int access(const char *path, int mode);
+#ifdef __cplusplus
+}
+#endif
+#else
+#include <unistd.h>
+#endif
+
+/* #define PRIVATE static */
+#define PRIVATE
+
+#ifdef TEST
+#define MAXRHS 5       /* Set low to exercise exception code */
+#else
+#define MAXRHS 1000
+#endif
+
+static int showPrecedenceConflict = 0;
+static char *msort(char*,char**,int(*)(const char*,const char*));
+
+/*
+** Compilers are getting increasingly pedantic about type conversions
+** as C evolves ever closer to Ada....  To work around the latest problems
+** we have to define the following variant of strlen().
+*/
+#define lemonStrlen(X)   ((int)strlen(X))
+
+/*
+** Compilers are starting to complain about the use of sprintf() and strcpy(),
+** saying they are unsafe.  So we define our own versions of those routines too.
+**
+** There are three routines here:  lemon_sprintf(), lemon_vsprintf(), and
+** lemon_addtext(). The first two are replacements for sprintf() and vsprintf().
+** The third is a helper routine for vsnprintf() that adds texts to the end of a
+** buffer, making sure the buffer is always zero-terminated.
+**
+** The string formatter is a minimal subset of stdlib sprintf() supporting only
+** a few simply conversions:
+**
+**   %d
+**   %s
+**   %.*s
+**
+*/
+static void lemon_addtext(
+  char *zBuf,           /* The buffer to which text is added */
+  int *pnUsed,          /* Slots of the buffer used so far */
+  const char *zIn,      /* Text to add */
+  int nIn,              /* Bytes of text to add.  -1 to use strlen() */
+  int iWidth            /* Field width.  Negative to left justify */
+){
+  if( nIn<0 ) for(nIn=0; zIn[nIn]; nIn++){}
+  while( iWidth>nIn ){ zBuf[(*pnUsed)++] = ' '; iWidth--; }
+  if( nIn==0 ) return;
+  memcpy(&zBuf[*pnUsed], zIn, nIn);
+  *pnUsed += nIn;
+  while( (-iWidth)>nIn ){ zBuf[(*pnUsed)++] = ' '; iWidth++; }
+  zBuf[*pnUsed] = 0;
+}
+static int lemon_vsprintf(char *str, const char *zFormat, va_list ap){
+  int i, j, k, c;
+  int nUsed = 0;
+  const char *z;
+  char zTemp[50];
+  str[0] = 0;
+  for(i=j=0; (c = zFormat[i])!=0; i++){
+    if( c=='%' ){
+      int iWidth = 0;
+      lemon_addtext(str, &nUsed, &zFormat[j], i-j, 0);
+      c = zFormat[++i];
+      if( ISDIGIT(c) || (c=='-' && ISDIGIT(zFormat[i+1])) ){
+        if( c=='-' ) i++;
+        while( ISDIGIT(zFormat[i]) ) iWidth = iWidth*10 + zFormat[i++] - '0';
+        if( c=='-' ) iWidth = -iWidth;
+        c = zFormat[i];
+      }
+      if( c=='d' ){
+        int v = va_arg(ap, int);
+        if( v<0 ){
+          lemon_addtext(str, &nUsed, "-", 1, iWidth);
+          v = -v;
+        }else if( v==0 ){
+          lemon_addtext(str, &nUsed, "0", 1, iWidth);
+        }
+        k = 0;
+        while( v>0 ){
+          k++;
+          zTemp[sizeof(zTemp)-k] = (v%10) + '0';
+          v /= 10;
+        }
+        lemon_addtext(str, &nUsed, &zTemp[sizeof(zTemp)-k], k, iWidth);
+      }else if( c=='s' ){
+        z = va_arg(ap, const char*);
+        lemon_addtext(str, &nUsed, z, -1, iWidth);
+      }else if( c=='.' && memcmp(&zFormat[i], ".*s", 3)==0 ){
+        i += 2;
+        k = va_arg(ap, int);
+        z = va_arg(ap, const char*);
+        lemon_addtext(str, &nUsed, z, k, iWidth);
+      }else if( c=='%' ){
+        lemon_addtext(str, &nUsed, "%", 1, 0);
+      }else{
+        fprintf(stderr, "illegal format\n");
+        exit(1);
+      }
+      j = i+1;
+    }
+  }
+  lemon_addtext(str, &nUsed, &zFormat[j], i-j, 0);
+  return nUsed;
+}
+static int lemon_sprintf(char *str, const char *format, ...){
+  va_list ap;
+  int rc;
+  va_start(ap, format);
+  rc = lemon_vsprintf(str, format, ap);
+  va_end(ap);
+  return rc;
+}
+static void lemon_strcpy(char *dest, const char *src){
+  while( (*(dest++) = *(src++))!=0 ){}
+}
+static void lemon_strcat(char *dest, const char *src){
+  while( *dest ) dest++;
+  lemon_strcpy(dest, src);
+}
+
+
+/* a few forward declarations... */
+struct rule;
+struct lemon;
+struct action;
+
+static struct action *Action_new(void);
+static struct action *Action_sort(struct action *);
+
+/********** From the file "build.h" ************************************/
+void FindRulePrecedences();
+void FindFirstSets();
+void FindStates();
+void FindLinks();
+void FindFollowSets();
+void FindActions();
+
+/********* From the file "configlist.h" *********************************/
+void Configlist_init(void);
+struct config *Configlist_add(struct rule *, int);
+struct config *Configlist_addbasis(struct rule *, int);
+void Configlist_closure(struct lemon *);
+void Configlist_sort(void);
+void Configlist_sortbasis(void);
+struct config *Configlist_return(void);
+struct config *Configlist_basis(void);
+void Configlist_eat(struct config *);
+void Configlist_reset(void);
+
+/********* From the file "error.h" ***************************************/
+void ErrorMsg(const char *, int,const char *, ...);
+
+/****** From the file "option.h" ******************************************/
+enum option_type { OPT_FLAG=1,  OPT_INT,  OPT_DBL,  OPT_STR,
+         OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR};
+struct s_options {
+  enum option_type type;
+  const char *label;
+  char *arg;
+  const char *message;
+};
+int    OptInit(char**,struct s_options*,FILE*);
+int    OptNArgs(void);
+char  *OptArg(int);
+void   OptErr(int);
+void   OptPrint(void);
+
+/******** From the file "parse.h" *****************************************/
+void Parse(struct lemon *lemp);
+
+/********* From the file "plink.h" ***************************************/
+struct plink *Plink_new(void);
+void Plink_add(struct plink **, struct config *);
+void Plink_copy(struct plink **, struct plink *);
+void Plink_delete(struct plink *);
+
+/********** From the file "report.h" *************************************/
+void Reprint(struct lemon *);
+void ReportOutput(struct lemon *);
+void ReportTable(struct lemon *, int);
+void ReportHeader(struct lemon *);
+void CompressTables(struct lemon *);
+void ResortStates(struct lemon *);
+
+/********** From the file "set.h" ****************************************/
+void  SetSize(int);             /* All sets will be of size N */
+char *SetNew(void);               /* A new set for element 0..N */
+void  SetFree(char*);             /* Deallocate a set */
+int SetAdd(char*,int);            /* Add element to a set */
+int SetUnion(char *,char *);    /* A <- A U B, thru element N */
+#define SetFind(X,Y) (X[Y])       /* True if Y is in set X */
+
+/********** From the file "struct.h" *************************************/
+/*
+** Principal data structures for the LEMON parser generator.
+*/
+
+typedef enum {LEMON_FALSE=0, LEMON_TRUE} Boolean;
+
+/* Symbols (terminals and nonterminals) of the grammar are stored
+** in the following: */
+enum symbol_type {
+  TERMINAL,
+  NONTERMINAL,
+  MULTITERMINAL
+};
+enum e_assoc {
+    LEFT,
+    RIGHT,
+    NONE,
+    UNK
+};
+struct symbol {
+  const char *name;        /* Name of the symbol */
+  int index;               /* Index number for this symbol */
+  enum symbol_type type;   /* Symbols are all either TERMINALS or NTs */
+  struct rule *rule;       /* Linked list of rules of this (if an NT) */
+  struct symbol *fallback; /* fallback token in case this token doesn't parse */
+  int prec;                /* Precedence if defined (-1 otherwise) */
+  enum e_assoc assoc;      /* Associativity if precedence is defined */
+  char *firstset;          /* First-set for all rules of this symbol */
+  Boolean lambda;          /* True if NT and can generate an empty string */
+  int useCnt;              /* Number of times used */
+  char *destructor;        /* Code which executes whenever this symbol is
+                           ** popped from the stack during error processing */
+  int destLineno;          /* Line number for start of destructor.  Set to
+                           ** -1 for duplicate destructors. */
+  char *datatype;          /* The data type of information held by this
+                           ** object. Only used if type==NONTERMINAL */
+  int dtnum;               /* The data type number.  In the parser, the value
+                           ** stack is a union.  The .yy%d element of this
+                           ** union is the correct data type for this object */
+  /* The following fields are used by MULTITERMINALs only */
+  int nsubsym;             /* Number of constituent symbols in the MULTI */
+  struct symbol **subsym;  /* Array of constituent symbols */
+};
+
+/* Each production rule in the grammar is stored in the following
+** structure.  */
+struct rule {
+  struct symbol *lhs;      /* Left-hand side of the rule */
+  const char *lhsalias;    /* Alias for the LHS (NULL if none) */
+  int lhsStart;            /* True if left-hand side is the start symbol */
+  int ruleline;            /* Line number for the rule */
+  int nrhs;                /* Number of RHS symbols */
+  struct symbol **rhs;     /* The RHS symbols */
+  const char **rhsalias;   /* An alias for each RHS symbol (NULL if none) */
+  int line;                /* Line number at which code begins */
+  const char *code;        /* The code executed when this rule is reduced */
+  const char *codePrefix;  /* Setup code before code[] above */
+  const char *codeSuffix;  /* Breakdown code after code[] above */
+  int noCode;              /* True if this rule has no associated C code */
+  int codeEmitted;         /* True if the code has been emitted already */
+  struct symbol *precsym;  /* Precedence symbol for this rule */
+  int index;               /* An index number for this rule */
+  int iRule;               /* Rule number as used in the generated tables */
+  Boolean canReduce;       /* True if this rule is ever reduced */
+  Boolean doesReduce;      /* Reduce actions occur after optimization */
+  struct rule *nextlhs;    /* Next rule with the same LHS */
+  struct rule *next;       /* Next rule in the global list */
+};
+
+/* A configuration is a production rule of the grammar together with
+** a mark (dot) showing how much of that rule has been processed so far.
+** Configurations also contain a follow-set which is a list of terminal
+** symbols which are allowed to immediately follow the end of the rule.
+** Every configuration is recorded as an instance of the following: */
+enum cfgstatus {
+  COMPLETE,
+  INCOMPLETE
+};
+struct config {
+  struct rule *rp;         /* The rule upon which the configuration is based */
+  int dot;                 /* The parse point */
+  char *fws;               /* Follow-set for this configuration only */
+  struct plink *fplp;      /* Follow-set forward propagation links */
+  struct plink *bplp;      /* Follow-set backwards propagation links */
+  struct state *stp;       /* Pointer to state which contains this */
+  enum cfgstatus status;   /* used during followset and shift computations */
+  struct config *next;     /* Next configuration in the state */
+  struct config *bp;       /* The next basis configuration */
+};
+
+enum e_action {
+  SHIFT,
+  ACCEPT,
+  REDUCE,
+  ERROR,
+  SSCONFLICT,              /* A shift/shift conflict */
+  SRCONFLICT,              /* Was a reduce, but part of a conflict */
+  RRCONFLICT,              /* Was a reduce, but part of a conflict */
+  SH_RESOLVED,             /* Was a shift.  Precedence resolved conflict */
+  RD_RESOLVED,             /* Was reduce.  Precedence resolved conflict */
+  NOT_USED,                /* Deleted by compression */
+  SHIFTREDUCE              /* Shift first, then reduce */
+};
+
+/* Every shift or reduce operation is stored as one of the following */
+struct action {
+  struct symbol *sp;       /* The look-ahead symbol */
+  enum e_action type;
+  union {
+    struct state *stp;     /* The new state, if a shift */
+    struct rule *rp;       /* The rule, if a reduce */
+  } x;
+  struct symbol *spOpt;    /* SHIFTREDUCE optimization to this symbol */
+  struct action *next;     /* Next action for this state */
+  struct action *collide;  /* Next action with the same hash */
+};
+
+/* Each state of the generated parser's finite state machine
+** is encoded as an instance of the following structure. */
+struct state {
+  struct config *bp;       /* The basis configurations for this state */
+  struct config *cfp;      /* All configurations in this set */
+  int statenum;            /* Sequential number for this state */
+  struct action *ap;       /* List of actions for this state */
+  int nTknAct, nNtAct;     /* Number of actions on terminals and nonterminals */
+  int iTknOfst, iNtOfst;   /* yy_action[] offset for terminals and nonterms */
+  int iDfltReduce;         /* Default action is to REDUCE by this rule */
+  struct rule *pDfltReduce;/* The default REDUCE rule. */
+  int autoReduce;          /* True if this is an auto-reduce state */
+};
+#define NO_OFFSET (-2147483647)
+
+/* A followset propagation link indicates that the contents of one
+** configuration followset should be propagated to another whenever
+** the first changes. */
+struct plink {
+  struct config *cfp;      /* The configuration to which linked */
+  struct plink *next;      /* The next propagate link */
+};
+
+/* The state vector for the entire parser generator is recorded as
+** follows.  (LEMON uses no global variables and makes little use of
+** static variables.  Fields in the following structure can be thought
+** of as begin global variables in the program.) */
+struct lemon {
+  struct state **sorted;   /* Table of states sorted by state number */
+  struct rule *rule;       /* List of all rules */
+  struct rule *startRule;  /* First rule */
+  int nstate;              /* Number of states */
+  int nxstate;             /* nstate with tail degenerate states removed */
+  int nrule;               /* Number of rules */
+  int nsymbol;             /* Number of terminal and nonterminal symbols */
+  int nterminal;           /* Number of terminal symbols */
+  struct symbol **symbols; /* Sorted array of pointers to symbols */
+  int errorcnt;            /* Number of errors */
+  struct symbol *errsym;   /* The error symbol */
+  struct symbol *wildcard; /* Token that matches anything */
+  char *name;              /* Name of the generated parser */
+  char *arg;               /* Declaration of the 3th argument to parser */
+  char *tokentype;         /* Type of terminal symbols in the parser stack */
+  char *vartype;           /* The default type of non-terminal symbols */
+  char *start;             /* Name of the start symbol for the grammar */
+  char *stacksize;         /* Size of the parser stack */
+  char *include;           /* Code to put at the start of the C file */
+  char *error;             /* Code to execute when an error is seen */
+  char *overflow;          /* Code to execute on a stack overflow */
+  char *failure;           /* Code to execute on parser failure */
+  char *accept;            /* Code to execute when the parser excepts */
+  char *extracode;         /* Code appended to the generated file */
+  char *tokendest;         /* Code to execute to destroy token data */
+  char *vardest;           /* Code for the default non-terminal destructor */
+  char *filename;          /* Name of the input file */
+  char *outname;           /* Name of the current output file */
+  char *tokenprefix;       /* A prefix added to token names in the .h file */
+  int nconflict;           /* Number of parsing conflicts */
+  int nactiontab;          /* Number of entries in the yy_action[] table */
+  int tablesize;           /* Total table size of all tables in bytes */
+  int basisflag;           /* Print only basis configurations */
+  int has_fallback;        /* True if any %fallback is seen in the grammar */
+  int nolinenosflag;       /* True if #line statements should not be printed */
+  char *argv0;             /* Name of the program */
+};
+
+#define MemoryCheck(X) if((X)==0){ \
+  extern void memory_error(); \
+  memory_error(); \
+}
+
+/**************** From the file "table.h" *********************************/
+/*
+** All code in this file has been automatically generated
+** from a specification in the file
+**              "table.q"
+** by the associative array code building program "aagen".
+** Do not edit this file!  Instead, edit the specification
+** file, then rerun aagen.
+*/
+/*
+** Code for processing tables in the LEMON parser generator.
+*/
+/* Routines for handling a strings */
+
+const char *Strsafe(const char *);
+
+void Strsafe_init(void);
+int Strsafe_insert(const char *);
+const char *Strsafe_find(const char *);
+
+/* Routines for handling symbols of the grammar */
+
+struct symbol *Symbol_new(const char *);
+int Symbolcmpp(const void *, const void *);
+void Symbol_init(void);
+int Symbol_insert(struct symbol *, const char *);
+struct symbol *Symbol_find(const char *);
+struct symbol *Symbol_Nth(int);
+int Symbol_count(void);
+struct symbol **Symbol_arrayof(void);
+
+/* Routines to manage the state table */
+
+int Configcmp(const char *, const char *);
+struct state *State_new(void);
+void State_init(void);
+int State_insert(struct state *, struct config *);
+struct state *State_find(struct config *);
+struct state **State_arrayof(/*  */);
+
+/* Routines used for efficiency in Configlist_add */
+
+void Configtable_init(void);
+int Configtable_insert(struct config *);
+struct config *Configtable_find(struct config *);
+void Configtable_clear(int(*)(struct config *));
+
+/****************** From the file "action.c" *******************************/
+/*
+** Routines processing parser actions in the LEMON parser generator.
+*/
+
+/* Allocate a new parser action */
+static struct action *Action_new(void){
+  static struct action *freelist = 0;
+  struct action *newaction;
+
+  if( freelist==0 ){
+    int i;
+    int amt = 100;
+    freelist = (struct action *)calloc(amt, sizeof(struct action));
+    if( freelist==0 ){
+      fprintf(stderr,"Unable to allocate memory for a new parser action.");
+      exit(1);
+    }
+    for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1];
+    freelist[amt-1].next = 0;
+  }
+  newaction = freelist;
+  freelist = freelist->next;
+  return newaction;
+}
+
+/* Compare two actions for sorting purposes.  Return negative, zero, or
+** positive if the first action is less than, equal to, or greater than
+** the first
+*/
+static int actioncmp(
+  struct action *ap1,
+  struct action *ap2
+){
+  int rc;
+  rc = ap1->sp->index - ap2->sp->index;
+  if( rc==0 ){
+    rc = (int)ap1->type - (int)ap2->type;
+  }
+  if( rc==0 && (ap1->type==REDUCE || ap1->type==SHIFTREDUCE) ){
+    rc = ap1->x.rp->index - ap2->x.rp->index;
+  }
+  if( rc==0 ){
+    rc = (int) (ap2 - ap1);
+  }
+  return rc;
+}
+
+/* Sort parser actions */
+static struct action *Action_sort(
+  struct action *ap
+){
+  ap = (struct action *)msort((char *)ap,(char **)&ap->next,
+                              (int(*)(const char*,const char*))actioncmp);
+  return ap;
+}
+
+void Action_add(
+  struct action **app,
+  enum e_action type,
+  struct symbol *sp,
+  char *arg
+){
+  struct action *newaction;
+  newaction = Action_new();
+  newaction->next = *app;
+  *app = newaction;
+  newaction->type = type;
+  newaction->sp = sp;
+  newaction->spOpt = 0;
+  if( type==SHIFT ){
+    newaction->x.stp = (struct state *)arg;
+  }else{
+    newaction->x.rp = (struct rule *)arg;
+  }
+}
+/********************** New code to implement the "acttab" module ***********/
+/*
+** This module implements routines use to construct the yy_action[] table.
+*/
+
+/*
+** The state of the yy_action table under construction is an instance of
+** the following structure.
+**
+** The yy_action table maps the pair (state_number, lookahead) into an
+** action_number.  The table is an array of integers pairs.  The state_number
+** determines an initial offset into the yy_action array.  The lookahead
+** value is then added to this initial offset to get an index X into the
+** yy_action array. If the aAction[X].lookahead equals the value of the
+** of the lookahead input, then the value of the action_number output is
+** aAction[X].action.  If the lookaheads do not match then the
+** default action for the state_number is returned.
+**
+** All actions associated with a single state_number are first entered
+** into aLookahead[] using multiple calls to acttab_action().  Then the 
+** actions for that single state_number are placed into the aAction[] 
+** array with a single call to acttab_insert().  The acttab_insert() call
+** also resets the aLookahead[] array in preparation for the next
+** state number.
+*/
+struct lookahead_action {
+  int lookahead;             /* Value of the lookahead token */
+  int action;                /* Action to take on the given lookahead */
+};
+typedef struct acttab acttab;
+struct acttab {
+  int nAction;                 /* Number of used slots in aAction[] */
+  int nActionAlloc;            /* Slots allocated for aAction[] */
+  struct lookahead_action
+    *aAction,                  /* The yy_action[] table under construction */
+    *aLookahead;               /* A single new transaction set */
+  int mnLookahead;             /* Minimum aLookahead[].lookahead */
+  int mnAction;                /* Action associated with mnLookahead */
+  int mxLookahead;             /* Maximum aLookahead[].lookahead */
+  int nLookahead;              /* Used slots in aLookahead[] */
+  int nLookaheadAlloc;         /* Slots allocated in aLookahead[] */
+};
+
+/* Return the number of entries in the yy_action table */
+#define acttab_size(X) ((X)->nAction)
+
+/* The value for the N-th entry in yy_action */
+#define acttab_yyaction(X,N)  ((X)->aAction[N].action)
+
+/* The value for the N-th entry in yy_lookahead */
+#define acttab_yylookahead(X,N)  ((X)->aAction[N].lookahead)
+
+/* Free all memory associated with the given acttab */
+void acttab_free(acttab *p){
+  free( p->aAction );
+  free( p->aLookahead );
+  free( p );
+}
+
+/* Allocate a new acttab structure */
+acttab *acttab_alloc(void){
+  acttab *p = (acttab *) calloc( 1, sizeof(*p) );
+  if( p==0 ){
+    fprintf(stderr,"Unable to allocate memory for a new acttab.");
+    exit(1);
+  }
+  memset(p, 0, sizeof(*p));
+  return p;
+}
+
+/* Add a new action to the current transaction set.  
+**
+** This routine is called once for each lookahead for a particular
+** state.
+*/
+void acttab_action(acttab *p, int lookahead, int action){
+  if( p->nLookahead>=p->nLookaheadAlloc ){
+    p->nLookaheadAlloc += 25;
+    p->aLookahead = (struct lookahead_action *) realloc( p->aLookahead,
+                             sizeof(p->aLookahead[0])*p->nLookaheadAlloc );
+    if( p->aLookahead==0 ){
+      fprintf(stderr,"malloc failed\n");
+      exit(1);
+    }
+  }
+  if( p->nLookahead==0 ){
+    p->mxLookahead = lookahead;
+    p->mnLookahead = lookahead;
+    p->mnAction = action;
+  }else{
+    if( p->mxLookahead<lookahead ) p->mxLookahead = lookahead;
+    if( p->mnLookahead>lookahead ){
+      p->mnLookahead = lookahead;
+      p->mnAction = action;
+    }
+  }
+  p->aLookahead[p->nLookahead].lookahead = lookahead;
+  p->aLookahead[p->nLookahead].action = action;
+  p->nLookahead++;
+}
+
+/*
+** Add the transaction set built up with prior calls to acttab_action()
+** into the current action table.  Then reset the transaction set back
+** to an empty set in preparation for a new round of acttab_action() calls.
+**
+** Return the offset into the action table of the new transaction.
+*/
+int acttab_insert(acttab *p){
+  int i, j, k, n;
+  assert( p->nLookahead>0 );
+
+  /* Make sure we have enough space to hold the expanded action table
+  ** in the worst case.  The worst case occurs if the transaction set
+  ** must be appended to the current action table
+  */
+  n = p->mxLookahead + 1;
+  if( p->nAction + n >= p->nActionAlloc ){
+    int oldAlloc = p->nActionAlloc;
+    p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20;
+    p->aAction = (struct lookahead_action *) realloc( p->aAction,
+                          sizeof(p->aAction[0])*p->nActionAlloc);
+    if( p->aAction==0 ){
+      fprintf(stderr,"malloc failed\n");
+      exit(1);
+    }
+    for(i=oldAlloc; i<p->nActionAlloc; i++){
+      p->aAction[i].lookahead = -1;
+      p->aAction[i].action = -1;
+    }
+  }
+
+  /* Scan the existing action table looking for an offset that is a 
+  ** duplicate of the current transaction set.  Fall out of the loop
+  ** if and when the duplicate is found.
+  **
+  ** i is the index in p->aAction[] where p->mnLookahead is inserted.
+  */
+  for(i=p->nAction-1; i>=0; i--){
+    if( p->aAction[i].lookahead==p->mnLookahead ){
+      /* All lookaheads and actions in the aLookahead[] transaction
+      ** must match against the candidate aAction[i] entry. */
+      if( p->aAction[i].action!=p->mnAction ) continue;
+      for(j=0; j<p->nLookahead; j++){
+        k = p->aLookahead[j].lookahead - p->mnLookahead + i;
+        if( k<0 || k>=p->nAction ) break;
+        if( p->aLookahead[j].lookahead!=p->aAction[k].lookahead ) break;
+        if( p->aLookahead[j].action!=p->aAction[k].action ) break;
+      }
+      if( j<p->nLookahead ) continue;
+
+      /* No possible lookahead value that is not in the aLookahead[]
+      ** transaction is allowed to match aAction[i] */
+      n = 0;
+      for(j=0; j<p->nAction; j++){
+        if( p->aAction[j].lookahead<0 ) continue;
+        if( p->aAction[j].lookahead==j+p->mnLookahead-i ) n++;
+      }
+      if( n==p->nLookahead ){
+        break;  /* An exact match is found at offset i */
+      }
+    }
+  }
+
+  /* If no existing offsets exactly match the current transaction, find an
+  ** an empty offset in the aAction[] table in which we can add the
+  ** aLookahead[] transaction.
+  */
+  if( i<0 ){
+    /* Look for holes in the aAction[] table that fit the current
+    ** aLookahead[] transaction.  Leave i set to the offset of the hole.
+    ** If no holes are found, i is left at p->nAction, which means the
+    ** transaction will be appended. */
+    for(i=0; i<p->nActionAlloc - p->mxLookahead; i++){
+      if( p->aAction[i].lookahead<0 ){
+        for(j=0; j<p->nLookahead; j++){
+          k = p->aLookahead[j].lookahead - p->mnLookahead + i;
+          if( k<0 ) break;
+          if( p->aAction[k].lookahead>=0 ) break;
+        }
+        if( j<p->nLookahead ) continue;
+        for(j=0; j<p->nAction; j++){
+          if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break;
+        }
+        if( j==p->nAction ){
+          break;  /* Fits in empty slots */
+        }
+      }
+    }
+  }
+  /* Insert transaction set at index i. */
+  for(j=0; j<p->nLookahead; j++){
+    k = p->aLookahead[j].lookahead - p->mnLookahead + i;
+    p->aAction[k] = p->aLookahead[j];
+    if( k>=p->nAction ) p->nAction = k+1;
+  }
+  p->nLookahead = 0;
+
+  /* Return the offset that is added to the lookahead in order to get the
+  ** index into yy_action of the action */
+  return i - p->mnLookahead;
+}
+
+/********************** From the file "build.c" *****************************/
+/*
+** Routines to construction the finite state machine for the LEMON
+** parser generator.
+*/
+
+/* Find a precedence symbol of every rule in the grammar.
+** 
+** Those rules which have a precedence symbol coded in the input
+** grammar using the "[symbol]" construct will already have the
+** rp->precsym field filled.  Other rules take as their precedence
+** symbol the first RHS symbol with a defined precedence.  If there
+** are not RHS symbols with a defined precedence, the precedence
+** symbol field is left blank.
+*/
+void FindRulePrecedences(struct lemon *xp)
+{
+  struct rule *rp;
+  for(rp=xp->rule; rp; rp=rp->next){
+    if( rp->precsym==0 ){
+      int i, j;
+      for(i=0; i<rp->nrhs && rp->precsym==0; i++){
+        struct symbol *sp = rp->rhs[i];
+        if( sp->type==MULTITERMINAL ){
+          for(j=0; j<sp->nsubsym; j++){
+            if( sp->subsym[j]->prec>=0 ){
+              rp->precsym = sp->subsym[j];
+              break;
+            }
+          }
+        }else if( sp->prec>=0 ){
+          rp->precsym = rp->rhs[i];
+        }
+      }
+    }
+  }
+  return;
+}
+
+/* Find all nonterminals which will generate the empty string.
+** Then go back and compute the first sets of every nonterminal.
+** The first set is the set of all terminal symbols which can begin
+** a string generated by that nonterminal.
+*/
+void FindFirstSets(struct lemon *lemp)
+{
+  int i, j;
+  struct rule *rp;
+  int progress;
+
+  for(i=0; i<lemp->nsymbol; i++){
+    lemp->symbols[i]->lambda = LEMON_FALSE;
+  }
+  for(i=lemp->nterminal; i<lemp->nsymbol; i++){
+    lemp->symbols[i]->firstset = SetNew();
+  }
+
+  /* First compute all lambdas */
+  do{
+    progress = 0;
+    for(rp=lemp->rule; rp; rp=rp->next){
+      if( rp->lhs->lambda ) continue;
+      for(i=0; i<rp->nrhs; i++){
+        struct symbol *sp = rp->rhs[i];
+        assert( sp->type==NONTERMINAL || sp->lambda==LEMON_FALSE );
+        if( sp->lambda==LEMON_FALSE ) break;
+      }
+      if( i==rp->nrhs ){
+        rp->lhs->lambda = LEMON_TRUE;
+        progress = 1;
+      }
+    }
+  }while( progress );
+
+  /* Now compute all first sets */
+  do{
+    struct symbol *s1, *s2;
+    progress = 0;
+    for(rp=lemp->rule; rp; rp=rp->next){
+      s1 = rp->lhs;
+      for(i=0; i<rp->nrhs; i++){
+        s2 = rp->rhs[i];
+        if( s2->type==TERMINAL ){
+          progress += SetAdd(s1->firstset,s2->index);
+          break;
+        }else if( s2->type==MULTITERMINAL ){
+          for(j=0; j<s2->nsubsym; j++){
+            progress += SetAdd(s1->firstset,s2->subsym[j]->index);
+          }
+          break;
+        }else if( s1==s2 ){
+          if( s1->lambda==LEMON_FALSE ) break;
+        }else{
+          progress += SetUnion(s1->firstset,s2->firstset);
+          if( s2->lambda==LEMON_FALSE ) break;
+        }
+      }
+    }
+  }while( progress );
+  return;
+}
+
+/* Compute all LR(0) states for the grammar.  Links
+** are added to between some states so that the LR(1) follow sets
+** can be computed later.
+*/
+PRIVATE struct state *getstate(struct lemon *);  /* forward reference */
+void FindStates(struct lemon *lemp)
+{
+  struct symbol *sp;
+  struct rule *rp;
+
+  Configlist_init();
+
+  /* Find the start symbol */
+  if( lemp->start ){
+    sp = Symbol_find(lemp->start);
+    if( sp==0 ){
+      ErrorMsg(lemp->filename,0,
+"The specified start symbol \"%s\" is not \
+in a nonterminal of the grammar.  \"%s\" will be used as the start \
+symbol instead.",lemp->start,lemp->startRule->lhs->name);
+      lemp->errorcnt++;
+      sp = lemp->startRule->lhs;
+    }
+  }else{
+    sp = lemp->startRule->lhs;
+  }
+
+  /* Make sure the start symbol doesn't occur on the right-hand side of
+  ** any rule.  Report an error if it does.  (YACC would generate a new
+  ** start symbol in this case.) */
+  for(rp=lemp->rule; rp; rp=rp->next){
+    int i;
+    for(i=0; i<rp->nrhs; i++){
+      if( rp->rhs[i]==sp ){   /* FIX ME:  Deal with multiterminals */
+        ErrorMsg(lemp->filename,0,
+"The start symbol \"%s\" occurs on the \
+right-hand side of a rule. This will result in a parser which \
+does not work properly.",sp->name);
+        lemp->errorcnt++;
+      }
+    }
+  }
+
+  /* The basis configuration set for the first state
+  ** is all rules which have the start symbol as their
+  ** left-hand side */
+  for(rp=sp->rule; rp; rp=rp->nextlhs){
+    struct config *newcfp;
+    rp->lhsStart = 1;
+    newcfp = Configlist_addbasis(rp,0);
+    SetAdd(newcfp->fws,0);
+  }
+
+  /* Compute the first state.  All other states will be
+  ** computed automatically during the computation of the first one.
+  ** The returned pointer to the first state is not used. */
+  (void)getstate(lemp);
+  return;
+}
+
+/* Return a pointer to a state which is described by the configuration
+** list which has been built from calls to Configlist_add.
+*/
+PRIVATE void buildshifts(struct lemon *, struct state *); /* Forwd ref */
+PRIVATE struct state *getstate(struct lemon *lemp)
+{
+  struct config *cfp, *bp;
+  struct state *stp;
+
+  /* Extract the sorted basis of the new state.  The basis was constructed
+  ** by prior calls to "Configlist_addbasis()". */
+  Configlist_sortbasis();
+  bp = Configlist_basis();
+
+  /* Get a state with the same basis */
+  stp = State_find(bp);
+  if( stp ){
+    /* A state with the same basis already exists!  Copy all the follow-set
+    ** propagation links from the state under construction into the
+    ** preexisting state, then return a pointer to the preexisting state */
+    struct config *x, *y;
+    for(x=bp, y=stp->bp; x && y; x=x->bp, y=y->bp){
+      Plink_copy(&y->bplp,x->bplp);
+      Plink_delete(x->fplp);
+      x->fplp = x->bplp = 0;
+    }
+    cfp = Configlist_return();
+    Configlist_eat(cfp);
+  }else{
+    /* This really is a new state.  Construct all the details */
+    Configlist_closure(lemp);    /* Compute the configuration closure */
+    Configlist_sort();           /* Sort the configuration closure */
+    cfp = Configlist_return();   /* Get a pointer to the config list */
+    stp = State_new();           /* A new state structure */
+    MemoryCheck(stp);
+    stp->bp = bp;                /* Remember the configuration basis */
+    stp->cfp = cfp;              /* Remember the configuration closure */
+    stp->statenum = lemp->nstate++; /* Every state gets a sequence number */
+    stp->ap = 0;                 /* No actions, yet. */
+    State_insert(stp,stp->bp);   /* Add to the state table */
+    buildshifts(lemp,stp);       /* Recursively compute successor states */
+  }
+  return stp;
+}
+
+/*
+** Return true if two symbols are the same.
+*/
+int same_symbol(struct symbol *a, struct symbol *b)
+{
+  int i;
+  if( a==b ) return 1;
+  if( a->type!=MULTITERMINAL ) return 0;
+  if( b->type!=MULTITERMINAL ) return 0;
+  if( a->nsubsym!=b->nsubsym ) return 0;
+  for(i=0; i<a->nsubsym; i++){
+    if( a->subsym[i]!=b->subsym[i] ) return 0;
+  }
+  return 1;
+}
+
+/* Construct all successor states to the given state.  A "successor"
+** state is any state which can be reached by a shift action.
+*/
+PRIVATE void buildshifts(struct lemon *lemp, struct state *stp)
+{
+  struct config *cfp;  /* For looping thru the config closure of "stp" */
+  struct config *bcfp; /* For the inner loop on config closure of "stp" */
+  struct config *newcfg;  /* */
+  struct symbol *sp;   /* Symbol following the dot in configuration "cfp" */
+  struct symbol *bsp;  /* Symbol following the dot in configuration "bcfp" */
+  struct state *newstp; /* A pointer to a successor state */
+
+  /* Each configuration becomes complete after it contibutes to a successor
+  ** state.  Initially, all configurations are incomplete */
+  for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE;
+
+  /* Loop through all configurations of the state "stp" */
+  for(cfp=stp->cfp; cfp; cfp=cfp->next){
+    if( cfp->status==COMPLETE ) continue;    /* Already used by inner loop */
+    if( cfp->dot>=cfp->rp->nrhs ) continue;  /* Can't shift this config */
+    Configlist_reset();                      /* Reset the new config set */
+    sp = cfp->rp->rhs[cfp->dot];             /* Symbol after the dot */
+
+    /* For every configuration in the state "stp" which has the symbol "sp"
+    ** following its dot, add the same configuration to the basis set under
+    ** construction but with the dot shifted one symbol to the right. */
+    for(bcfp=cfp; bcfp; bcfp=bcfp->next){
+      if( bcfp->status==COMPLETE ) continue;    /* Already used */
+      if( bcfp->dot>=bcfp->rp->nrhs ) continue; /* Can't shift this one */
+      bsp = bcfp->rp->rhs[bcfp->dot];           /* Get symbol after dot */
+      if( !same_symbol(bsp,sp) ) continue;      /* Must be same as for "cfp" */
+      bcfp->status = COMPLETE;                  /* Mark this config as used */
+      newcfg = Configlist_addbasis(bcfp->rp,bcfp->dot+1);
+      Plink_add(&newcfg->bplp,bcfp);
+    }
+
+    /* Get a pointer to the state described by the basis configuration set
+    ** constructed in the preceding loop */
+    newstp = getstate(lemp);
+
+    /* The state "newstp" is reached from the state "stp" by a shift action
+    ** on the symbol "sp" */
+    if( sp->type==MULTITERMINAL ){
+      int i;
+      for(i=0; i<sp->nsubsym; i++){
+        Action_add(&stp->ap,SHIFT,sp->subsym[i],(char*)newstp);
+      }
+    }else{
+      Action_add(&stp->ap,SHIFT,sp,(char *)newstp);
+    }
+  }
+}
+
+/*
+** Construct the propagation links
+*/
+void FindLinks(struct lemon *lemp)
+{
+  int i;
+  struct config *cfp, *other;
+  struct state *stp;
+  struct plink *plp;
+
+  /* Housekeeping detail:
+  ** Add to every propagate link a pointer back to the state to
+  ** which the link is attached. */
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+    for(cfp=stp->cfp; cfp; cfp=cfp->next){
+      cfp->stp = stp;
+    }
+  }
+
+  /* Convert all backlinks into forward links.  Only the forward
+  ** links are used in the follow-set computation. */
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+    for(cfp=stp->cfp; cfp; cfp=cfp->next){
+      for(plp=cfp->bplp; plp; plp=plp->next){
+        other = plp->cfp;
+        Plink_add(&other->fplp,cfp);
+      }
+    }
+  }
+}
+
+/* Compute all followsets.
+**
+** A followset is the set of all symbols which can come immediately
+** after a configuration.
+*/
+void FindFollowSets(struct lemon *lemp)
+{
+  int i;
+  struct config *cfp;
+  struct plink *plp;
+  int progress;
+  int change;
+
+  for(i=0; i<lemp->nstate; i++){
+    for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){
+      cfp->status = INCOMPLETE;
+    }
+  }
+  
+  do{
+    progress = 0;
+    for(i=0; i<lemp->nstate; i++){
+      for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){
+        if( cfp->status==COMPLETE ) continue;
+        for(plp=cfp->fplp; plp; plp=plp->next){
+          change = SetUnion(plp->cfp->fws,cfp->fws);
+          if( change ){
+            plp->cfp->status = INCOMPLETE;
+            progress = 1;
+          }
+        }
+        cfp->status = COMPLETE;
+      }
+    }
+  }while( progress );
+}
+
+static int resolve_conflict(struct action *,struct action *);
+
+/* Compute the reduce actions, and resolve conflicts.
+*/
+void FindActions(struct lemon *lemp)
+{
+  int i,j;
+  struct config *cfp;
+  struct state *stp;
+  struct symbol *sp;
+  struct rule *rp;
+
+  /* Add all of the reduce actions 
+  ** A reduce action is added for each element of the followset of
+  ** a configuration which has its dot at the extreme right.
+  */
+  for(i=0; i<lemp->nstate; i++){   /* Loop over all states */
+    stp = lemp->sorted[i];
+    for(cfp=stp->cfp; cfp; cfp=cfp->next){  /* Loop over all configurations */
+      if( cfp->rp->nrhs==cfp->dot ){        /* Is dot at extreme right? */
+        for(j=0; j<lemp->nterminal; j++){
+          if( SetFind(cfp->fws,j) ){
+            /* Add a reduce action to the state "stp" which will reduce by the
+            ** rule "cfp->rp" if the lookahead symbol is "lemp->symbols[j]" */
+            Action_add(&stp->ap,REDUCE,lemp->symbols[j],(char *)cfp->rp);
+          }
+        }
+      }
+    }
+  }
+
+  /* Add the accepting token */
+  if( lemp->start ){
+    sp = Symbol_find(lemp->start);
+    if( sp==0 ) sp = lemp->startRule->lhs;
+  }else{
+    sp = lemp->startRule->lhs;
+  }
+  /* Add to the first state (which is always the starting state of the
+  ** finite state machine) an action to ACCEPT if the lookahead is the
+  ** start nonterminal.  */
+  Action_add(&lemp->sorted[0]->ap,ACCEPT,sp,0);
+
+  /* Resolve conflicts */
+  for(i=0; i<lemp->nstate; i++){
+    struct action *ap, *nap;
+    stp = lemp->sorted[i];
+    /* assert( stp->ap ); */
+    stp->ap = Action_sort(stp->ap);
+    for(ap=stp->ap; ap && ap->next; ap=ap->next){
+      for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){
+         /* The two actions "ap" and "nap" have the same lookahead.
+         ** Figure out which one should be used */
+         lemp->nconflict += resolve_conflict(ap,nap);
+      }
+    }
+  }
+
+  /* Report an error for each rule that can never be reduced. */
+  for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = LEMON_FALSE;
+  for(i=0; i<lemp->nstate; i++){
+    struct action *ap;
+    for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){
+      if( ap->type==REDUCE ) ap->x.rp->canReduce = LEMON_TRUE;
+    }
+  }
+  for(rp=lemp->rule; rp; rp=rp->next){
+    if( rp->canReduce ) continue;
+    ErrorMsg(lemp->filename,rp->ruleline,"This rule can not be reduced.\n");
+    lemp->errorcnt++;
+  }
+}
+
+/* Resolve a conflict between the two given actions.  If the
+** conflict can't be resolved, return non-zero.
+**
+** NO LONGER TRUE:
+**   To resolve a conflict, first look to see if either action
+**   is on an error rule.  In that case, take the action which
+**   is not associated with the error rule.  If neither or both
+**   actions are associated with an error rule, then try to
+**   use precedence to resolve the conflict.
+**
+** If either action is a SHIFT, then it must be apx.  This
+** function won't work if apx->type==REDUCE and apy->type==SHIFT.
+*/
+static int resolve_conflict(
+  struct action *apx,
+  struct action *apy
+){
+  struct symbol *spx, *spy;
+  int errcnt = 0;
+  assert( apx->sp==apy->sp );  /* Otherwise there would be no conflict */
+  if( apx->type==SHIFT && apy->type==SHIFT ){
+    apy->type = SSCONFLICT;
+    errcnt++;
+  }
+  if( apx->type==SHIFT && apy->type==REDUCE ){
+    spx = apx->sp;
+    spy = apy->x.rp->precsym;
+    if( spy==0 || spx->prec<0 || spy->prec<0 ){
+      /* Not enough precedence information. */
+      apy->type = SRCONFLICT;
+      errcnt++;
+    }else if( spx->prec>spy->prec ){    /* higher precedence wins */
+      apy->type = RD_RESOLVED;
+    }else if( spx->prec<spy->prec ){
+      apx->type = SH_RESOLVED;
+    }else if( spx->prec==spy->prec && spx->assoc==RIGHT ){ /* Use operator */
+      apy->type = RD_RESOLVED;                             /* associativity */
+    }else if( spx->prec==spy->prec && spx->assoc==LEFT ){  /* to break tie */
+      apx->type = SH_RESOLVED;
+    }else{
+      assert( spx->prec==spy->prec && spx->assoc==NONE );
+      apx->type = ERROR;
+    }
+  }else if( apx->type==REDUCE && apy->type==REDUCE ){
+    spx = apx->x.rp->precsym;
+    spy = apy->x.rp->precsym;
+    if( spx==0 || spy==0 || spx->prec<0 ||
+    spy->prec<0 || spx->prec==spy->prec ){
+      apy->type = RRCONFLICT;
+      errcnt++;
+    }else if( spx->prec>spy->prec ){
+      apy->type = RD_RESOLVED;
+    }else if( spx->prec<spy->prec ){
+      apx->type = RD_RESOLVED;
+    }
+  }else{
+    assert( 
+      apx->type==SH_RESOLVED ||
+      apx->type==RD_RESOLVED ||
+      apx->type==SSCONFLICT ||
+      apx->type==SRCONFLICT ||
+      apx->type==RRCONFLICT ||
+      apy->type==SH_RESOLVED ||
+      apy->type==RD_RESOLVED ||
+      apy->type==SSCONFLICT ||
+      apy->type==SRCONFLICT ||
+      apy->type==RRCONFLICT
+    );
+    /* The REDUCE/SHIFT case cannot happen because SHIFTs come before
+    ** REDUCEs on the list.  If we reach this point it must be because
+    ** the parser conflict had already been resolved. */
+  }
+  return errcnt;
+}
+/********************* From the file "configlist.c" *************************/
+/*
+** Routines to processing a configuration list and building a state
+** in the LEMON parser generator.
+*/
+
+static struct config *freelist = 0;      /* List of free configurations */
+static struct config *current = 0;       /* Top of list of configurations */
+static struct config **currentend = 0;   /* Last on list of configs */
+static struct config *basis = 0;         /* Top of list of basis configs */
+static struct config **basisend = 0;     /* End of list of basis configs */
+
+/* Return a pointer to a new configuration */
+PRIVATE struct config *newconfig(){
+  struct config *newcfg;
+  if( freelist==0 ){
+    int i;
+    int amt = 3;
+    freelist = (struct config *)calloc( amt, sizeof(struct config) );
+    if( freelist==0 ){
+      fprintf(stderr,"Unable to allocate memory for a new configuration.");
+      exit(1);
+    }
+    for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1];
+    freelist[amt-1].next = 0;
+  }
+  newcfg = freelist;
+  freelist = freelist->next;
+  return newcfg;
+}
+
+/* The configuration "old" is no longer used */
+PRIVATE void deleteconfig(struct config *old)
+{
+  old->next = freelist;
+  freelist = old;
+}
+
+/* Initialized the configuration list builder */
+void Configlist_init(){
+  current = 0;
+  currentend = &current;
+  basis = 0;
+  basisend = &basis;
+  Configtable_init();
+  return;
+}
+
+/* Initialized the configuration list builder */
+void Configlist_reset(){
+  current = 0;
+  currentend = &current;
+  basis = 0;
+  basisend = &basis;
+  Configtable_clear(0);
+  return;
+}
+
+/* Add another configuration to the configuration list */
+struct config *Configlist_add(
+  struct rule *rp,    /* The rule */
+  int dot             /* Index into the RHS of the rule where the dot goes */
+){
+  struct config *cfp, model;
+
+  assert( currentend!=0 );
+  model.rp = rp;
+  model.dot = dot;
+  cfp = Configtable_find(&model);
+  if( cfp==0 ){
+    cfp = newconfig();
+    cfp->rp = rp;
+    cfp->dot = dot;
+    cfp->fws = SetNew();
+    cfp->stp = 0;
+    cfp->fplp = cfp->bplp = 0;
+    cfp->next = 0;
+    cfp->bp = 0;
+    *currentend = cfp;
+    currentend = &cfp->next;
+    Configtable_insert(cfp);
+  }
+  return cfp;
+}
+
+/* Add a basis configuration to the configuration list */
+struct config *Configlist_addbasis(struct rule *rp, int dot)
+{
+  struct config *cfp, model;
+
+  assert( basisend!=0 );
+  assert( currentend!=0 );
+  model.rp = rp;
+  model.dot = dot;
+  cfp = Configtable_find(&model);
+  if( cfp==0 ){
+    cfp = newconfig();
+    cfp->rp = rp;
+    cfp->dot = dot;
+    cfp->fws = SetNew();
+    cfp->stp = 0;
+    cfp->fplp = cfp->bplp = 0;
+    cfp->next = 0;
+    cfp->bp = 0;
+    *currentend = cfp;
+    currentend = &cfp->next;
+    *basisend = cfp;
+    basisend = &cfp->bp;
+    Configtable_insert(cfp);
+  }
+  return cfp;
+}
+
+/* Compute the closure of the configuration list */
+void Configlist_closure(struct lemon *lemp)
+{
+  struct config *cfp, *newcfp;
+  struct rule *rp, *newrp;
+  struct symbol *sp, *xsp;
+  int i, dot;
+
+  assert( currentend!=0 );
+  for(cfp=current; cfp; cfp=cfp->next){
+    rp = cfp->rp;
+    dot = cfp->dot;
+    if( dot>=rp->nrhs ) continue;
+    sp = rp->rhs[dot];
+    if( sp->type==NONTERMINAL ){
+      if( sp->rule==0 && sp!=lemp->errsym ){
+        ErrorMsg(lemp->filename,rp->line,"Nonterminal \"%s\" has no rules.",
+          sp->name);
+        lemp->errorcnt++;
+      }
+      for(newrp=sp->rule; newrp; newrp=newrp->nextlhs){
+        newcfp = Configlist_add(newrp,0);
+        for(i=dot+1; i<rp->nrhs; i++){
+          xsp = rp->rhs[i];
+          if( xsp->type==TERMINAL ){
+            SetAdd(newcfp->fws,xsp->index);
+            break;
+          }else if( xsp->type==MULTITERMINAL ){
+            int k;
+            for(k=0; k<xsp->nsubsym; k++){
+              SetAdd(newcfp->fws, xsp->subsym[k]->index);
+            }
+            break;
+          }else{
+            SetUnion(newcfp->fws,xsp->firstset);
+            if( xsp->lambda==LEMON_FALSE ) break;
+          }
+        }
+        if( i==rp->nrhs ) Plink_add(&cfp->fplp,newcfp);
+      }
+    }
+  }
+  return;
+}
+
+/* Sort the configuration list */
+void Configlist_sort(){
+  current = (struct config*)msort((char*)current,(char**)&(current->next),
+                                  Configcmp);
+  currentend = 0;
+  return;
+}
+
+/* Sort the basis configuration list */
+void Configlist_sortbasis(){
+  basis = (struct config*)msort((char*)current,(char**)&(current->bp),
+                                Configcmp);
+  basisend = 0;
+  return;
+}
+
+/* Return a pointer to the head of the configuration list and
+** reset the list */
+struct config *Configlist_return(){
+  struct config *old;
+  old = current;
+  current = 0;
+  currentend = 0;
+  return old;
+}
+
+/* Return a pointer to the head of the configuration list and
+** reset the list */
+struct config *Configlist_basis(){
+  struct config *old;
+  old = basis;
+  basis = 0;
+  basisend = 0;
+  return old;
+}
+
+/* Free all elements of the given configuration list */
+void Configlist_eat(struct config *cfp)
+{
+  struct config *nextcfp;
+  for(; cfp; cfp=nextcfp){
+    nextcfp = cfp->next;
+    assert( cfp->fplp==0 );
+    assert( cfp->bplp==0 );
+    if( cfp->fws ) SetFree(cfp->fws);
+    deleteconfig(cfp);
+  }
+  return;
+}
+/***************** From the file "error.c" *********************************/
+/*
+** Code for printing error message.
+*/
+
+void ErrorMsg(const char *filename, int lineno, const char *format, ...){
+  va_list ap;
+  fprintf(stderr, "%s:%d: ", filename, lineno);
+  va_start(ap, format);
+  vfprintf(stderr,format,ap);
+  va_end(ap);
+  fprintf(stderr, "\n");
+}
+/**************** From the file "main.c" ************************************/
+/*
+** Main program file for the LEMON parser generator.
+*/
+
+/* Report an out-of-memory condition and abort.  This function
+** is used mostly by the "MemoryCheck" macro in struct.h
+*/
+void memory_error(){
+  fprintf(stderr,"Out of memory.  Aborting...\n");
+  exit(1);
+}
+
+static int nDefine = 0;      /* Number of -D options on the command line */
+static char **azDefine = 0;  /* Name of the -D macros */
+
+/* This routine is called with the argument to each -D command-line option.
+** Add the macro defined to the azDefine array.
+*/
+static void handle_D_option(char *z){
+  char **paz;
+  nDefine++;
+  azDefine = (char **) realloc(azDefine, sizeof(azDefine[0])*nDefine);
+  if( azDefine==0 ){
+    fprintf(stderr,"out of memory\n");
+    exit(1);
+  }
+  paz = &azDefine[nDefine-1];
+  *paz = (char *) malloc( lemonStrlen(z)+1 );
+  if( *paz==0 ){
+    fprintf(stderr,"out of memory\n");
+    exit(1);
+  }
+  lemon_strcpy(*paz, z);
+  for(z=*paz; *z && *z!='='; z++){}
+  *z = 0;
+}
+
+static char *user_templatename = NULL;
+static void handle_T_option(char *z){
+  user_templatename = (char *) malloc( lemonStrlen(z)+1 );
+  if( user_templatename==0 ){
+    memory_error();
+  }
+  lemon_strcpy(user_templatename, z);
+}
+
+/* Merge together to lists of rules ordered by rule.iRule */
+static struct rule *Rule_merge(struct rule *pA, struct rule *pB){
+  struct rule *pFirst = 0;
+  struct rule **ppPrev = &pFirst;
+  while( pA && pB ){
+    if( pA->iRule<pB->iRule ){
+      *ppPrev = pA;
+      ppPrev = &pA->next;
+      pA = pA->next;
+    }else{
+      *ppPrev = pB;
+      ppPrev = &pB->next;
+      pB = pB->next;
+    }
+  }
+  if( pA ){
+    *ppPrev = pA;
+  }else{
+    *ppPrev = pB;
+  }
+  return pFirst;
+}
+
+/*
+** Sort a list of rules in order of increasing iRule value
+*/
+static struct rule *Rule_sort(struct rule *rp){
+  int i;
+  struct rule *pNext;
+  struct rule *x[32];
+  memset(x, 0, sizeof(x));
+  while( rp ){
+    pNext = rp->next;
+    rp->next = 0;
+    for(i=0; i<sizeof(x)/sizeof(x[0]) && x[i]; i++){
+      rp = Rule_merge(x[i], rp);
+      x[i] = 0;
+    }
+    x[i] = rp;
+    rp = pNext;
+  }
+  rp = 0;
+  for(i=0; i<sizeof(x)/sizeof(x[0]); i++){
+    rp = Rule_merge(x[i], rp);
+  }
+  return rp;
+}
+
+/* forward reference */
+static const char *minimum_size_type(int lwr, int upr, int *pnByte);
+
+/* Print a single line of the "Parser Stats" output
+*/
+static void stats_line(const char *zLabel, int iValue){
+  int nLabel = lemonStrlen(zLabel);
+  printf("  %s%.*s %5d\n", zLabel,
+         35-nLabel, "................................",
+         iValue);
+}
+
+/* The main program.  Parse the command line and do it... */
+int main(int argc, char **argv)
+{
+  static int version = 0;
+  static int rpflag = 0;
+  static int basisflag = 0;
+  static int compress = 0;
+  static int quiet = 0;
+  static int statistics = 0;
+  static int mhflag = 0;
+  static int nolinenosflag = 0;
+  static int noResort = 0;
+  static struct s_options options[] = {
+    {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."},
+    {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."},
+    {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."},
+    {OPT_FSTR, "f", 0, "Ignored.  (Placeholder for -f compiler options.)"},
+    {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."},
+    {OPT_FSTR, "I", 0, "Ignored.  (Placeholder for '-I' compiler options.)"},
+    {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file."},
+    {OPT_FLAG, "l", (char*)&nolinenosflag, "Do not print #line statements."},
+    {OPT_FSTR, "O", 0, "Ignored.  (Placeholder for '-O' compiler options.)"},
+    {OPT_FLAG, "p", (char*)&showPrecedenceConflict,
+                    "Show conflicts resolved by precedence rules"},
+    {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."},
+    {OPT_FLAG, "r", (char*)&noResort, "Do not sort or renumber states"},
+    {OPT_FLAG, "s", (char*)&statistics,
+                                   "Print parser stats to standard output."},
+    {OPT_FLAG, "x", (char*)&version, "Print the version number."},
+    {OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."},
+    {OPT_FSTR, "W", 0, "Ignored.  (Placeholder for '-W' compiler options.)"},
+    {OPT_FLAG,0,0,0}
+  };
+  int i;
+  int exitcode;
+  struct lemon lem;
+  struct rule *rp;
+
+  OptInit(argv,options,stderr);
+  if( version ){
+     printf("Lemon version 1.0\n");
+     exit(0); 
+  }
+  if( OptNArgs()!=1 ){
+    fprintf(stderr,"Exactly one filename argument is required.\n");
+    exit(1);
+  }
+  memset(&lem, 0, sizeof(lem));
+  lem.errorcnt = 0;
+
+  /* Initialize the machine */
+  Strsafe_init();
+  Symbol_init();
+  State_init();
+  lem.argv0 = argv[0];
+  lem.filename = OptArg(0);
+  lem.basisflag = basisflag;
+  lem.nolinenosflag = nolinenosflag;
+  Symbol_new("$");
+  lem.errsym = Symbol_new("error");
+  lem.errsym->useCnt = 0;
+
+  /* Parse the input file */
+  Parse(&lem);
+  if( lem.errorcnt ) exit(lem.errorcnt);
+  if( lem.nrule==0 ){
+    fprintf(stderr,"Empty grammar.\n");
+    exit(1);
+  }
+
+  /* Count and index the symbols of the grammar */
+  Symbol_new("{default}");
+  lem.nsymbol = Symbol_count();
+  lem.symbols = Symbol_arrayof();
+  for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i;
+  qsort(lem.symbols,lem.nsymbol,sizeof(struct symbol*), Symbolcmpp);
+  for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i;
+  while( lem.symbols[i-1]->type==MULTITERMINAL ){ i--; }
+  assert( strcmp(lem.symbols[i-1]->name,"{default}")==0 );
+  lem.nsymbol = i - 1;
+  for(i=1; ISUPPER(lem.symbols[i]->name[0]); i++);
+  lem.nterminal = i;
+
+  /* Assign sequential rule numbers.  Start with 0.  Put rules that have no
+  ** reduce action C-code associated with them last, so that the switch()
+  ** statement that selects reduction actions will have a smaller jump table.
+  */
+  for(i=0, rp=lem.rule; rp; rp=rp->next){
+    rp->iRule = rp->code ? i++ : -1;
+  }
+  for(rp=lem.rule; rp; rp=rp->next){
+    if( rp->iRule<0 ) rp->iRule = i++;
+  }
+  lem.startRule = lem.rule;
+  lem.rule = Rule_sort(lem.rule);
+
+  /* Generate a reprint of the grammar, if requested on the command line */
+  if( rpflag ){
+    Reprint(&lem);
+  }else{
+    /* Initialize the size for all follow and first sets */
+    SetSize(lem.nterminal+1);
+
+    /* Find the precedence for every production rule (that has one) */
+    FindRulePrecedences(&lem);
+
+    /* Compute the lambda-nonterminals and the first-sets for every
+    ** nonterminal */
+    FindFirstSets(&lem);
+
+    /* Compute all LR(0) states.  Also record follow-set propagation
+    ** links so that the follow-set can be computed later */
+    lem.nstate = 0;
+    FindStates(&lem);
+    lem.sorted = State_arrayof();
+
+    /* Tie up loose ends on the propagation links */
+    FindLinks(&lem);
+
+    /* Compute the follow set of every reducible configuration */
+    FindFollowSets(&lem);
+
+    /* Compute the action tables */
+    FindActions(&lem);
+
+    /* Compress the action tables */
+    if( compress==0 ) CompressTables(&lem);
+
+    /* Reorder and renumber the states so that states with fewer choices
+    ** occur at the end.  This is an optimization that helps make the
+    ** generated parser tables smaller. */
+    if( noResort==0 ) ResortStates(&lem);
+
+    /* Generate a report of the parser generated.  (the "y.output" file) */
+    if( !quiet ) ReportOutput(&lem);
+
+    /* Generate the source code for the parser */
+    ReportTable(&lem, mhflag);
+
+    /* Produce a header file for use by the scanner.  (This step is
+    ** omitted if the "-m" option is used because makeheaders will
+    ** generate the file for us.) */
+    if( !mhflag ) ReportHeader(&lem);
+  }
+  if( statistics ){
+    printf("Parser statistics:\n");
+    stats_line("terminal symbols", lem.nterminal);
+    stats_line("non-terminal symbols", lem.nsymbol - lem.nterminal);
+    stats_line("total symbols", lem.nsymbol);
+    stats_line("rules", lem.nrule);
+    stats_line("states", lem.nxstate);
+    stats_line("conflicts", lem.nconflict);
+    stats_line("action table entries", lem.nactiontab);
+    stats_line("total table size (bytes)", lem.tablesize);
+  }
+  if( lem.nconflict > 0 ){
+    fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict);
+  }
+
+  /* return 0 on success, 1 on failure. */
+  exitcode = ((lem.errorcnt > 0) || (lem.nconflict > 0)) ? 1 : 0;
+  exit(exitcode);
+  return (exitcode);
+}
+/******************** From the file "msort.c" *******************************/
+/*
+** A generic merge-sort program.
+**
+** USAGE:
+** Let "ptr" be a pointer to some structure which is at the head of
+** a null-terminated list.  Then to sort the list call:
+**
+**     ptr = msort(ptr,&(ptr->next),cmpfnc);
+**
+** In the above, "cmpfnc" is a pointer to a function which compares
+** two instances of the structure and returns an integer, as in
+** strcmp.  The second argument is a pointer to the pointer to the
+** second element of the linked list.  This address is used to compute
+** the offset to the "next" field within the structure.  The offset to
+** the "next" field must be constant for all structures in the list.
+**
+** The function returns a new pointer which is the head of the list
+** after sorting.
+**
+** ALGORITHM:
+** Merge-sort.
+*/
+
+/*
+** Return a pointer to the next structure in the linked list.
+*/
+#define NEXT(A) (*(char**)(((char*)A)+offset))
+
+/*
+** Inputs:
+**   a:       A sorted, null-terminated linked list.  (May be null).
+**   b:       A sorted, null-terminated linked list.  (May be null).
+**   cmp:     A pointer to the comparison function.
+**   offset:  Offset in the structure to the "next" field.
+**
+** Return Value:
+**   A pointer to the head of a sorted list containing the elements
+**   of both a and b.
+**
+** Side effects:
+**   The "next" pointers for elements in the lists a and b are
+**   changed.
+*/
+static char *merge(
+  char *a,
+  char *b,
+  int (*cmp)(const char*,const char*),
+  int offset
+){
+  char *ptr, *head;
+
+  if( a==0 ){
+    head = b;
+  }else if( b==0 ){
+    head = a;
+  }else{
+    if( (*cmp)(a,b)<=0 ){
+      ptr = a;
+      a = NEXT(a);
+    }else{
+      ptr = b;
+      b = NEXT(b);
+    }
+    head = ptr;
+    while( a && b ){
+      if( (*cmp)(a,b)<=0 ){
+        NEXT(ptr) = a;
+        ptr = a;
+        a = NEXT(a);
+      }else{
+        NEXT(ptr) = b;
+        ptr = b;
+        b = NEXT(b);
+      }
+    }
+    if( a ) NEXT(ptr) = a;
+    else    NEXT(ptr) = b;
+  }
+  return head;
+}
+
+/*
+** Inputs:
+**   list:      Pointer to a singly-linked list of structures.
+**   next:      Pointer to pointer to the second element of the list.
+**   cmp:       A comparison function.
+**
+** Return Value:
+**   A pointer to the head of a sorted list containing the elements
+**   orginally in list.
+**
+** Side effects:
+**   The "next" pointers for elements in list are changed.
+*/
+#define LISTSIZE 30
+static char *msort(
+  char *list,
+  char **next,
+  int (*cmp)(const char*,const char*)
+){
+  unsigned long offset;
+  char *ep;
+  char *set[LISTSIZE];
+  int i;
+  offset = (unsigned long)((char*)next - (char*)list);
+  for(i=0; i<LISTSIZE; i++) set[i] = 0;
+  while( list ){
+    ep = list;
+    list = NEXT(list);
+    NEXT(ep) = 0;
+    for(i=0; i<LISTSIZE-1 && set[i]!=0; i++){
+      ep = merge(ep,set[i],cmp,offset);
+      set[i] = 0;
+    }
+    set[i] = ep;
+  }
+  ep = 0;
+  for(i=0; i<LISTSIZE; i++) if( set[i] ) ep = merge(set[i],ep,cmp,offset);
+  return ep;
+}
+/************************ From the file "option.c" **************************/
+static char **argv;
+static struct s_options *op;
+static FILE *errstream;
+
+#define ISOPT(X) ((X)[0]=='-'||(X)[0]=='+'||strchr((X),'=')!=0)
+
+/*
+** Print the command line with a carrot pointing to the k-th character
+** of the n-th field.
+*/
+static void errline(int n, int k, FILE *err)
+{
+  int spcnt, i;
+  if( argv[0] ) fprintf(err,"%s",argv[0]);
+  spcnt = lemonStrlen(argv[0]) + 1;
+  for(i=1; i<n && argv[i]; i++){
+    fprintf(err," %s",argv[i]);
+    spcnt += lemonStrlen(argv[i])+1;
+  }
+  spcnt += k;
+  for(; argv[i]; i++) fprintf(err," %s",argv[i]);
+  if( spcnt<20 ){
+    fprintf(err,"\n%*s^-- here\n",spcnt,"");
+  }else{
+    fprintf(err,"\n%*shere --^\n",spcnt-7,"");
+  }
+}
+
+/*
+** Return the index of the N-th non-switch argument.  Return -1
+** if N is out of range.
+*/
+static int argindex(int n)
+{
+  int i;
+  int dashdash = 0;
+  if( argv!=0 && *argv!=0 ){
+    for(i=1; argv[i]; i++){
+      if( dashdash || !ISOPT(argv[i]) ){
+        if( n==0 ) return i;
+        n--;
+      }
+      if( strcmp(argv[i],"--")==0 ) dashdash = 1;
+    }
+  }
+  return -1;
+}
+
+static char emsg[] = "Command line syntax error: ";
+
+/*
+** Process a flag command line argument.
+*/
+static int handleflags(int i, FILE *err)
+{
+  int v;
+  int errcnt = 0;
+  int j;
+  for(j=0; op[j].label; j++){
+    if( strncmp(&argv[i][1],op[j].label,lemonStrlen(op[j].label))==0 ) break;
+  }
+  v = argv[i][0]=='-' ? 1 : 0;
+  if( op[j].label==0 ){
+    if( err ){
+      fprintf(err,"%sundefined option.\n",emsg);
+      errline(i,1,err);
+    }
+    errcnt++;
+  }else if( op[j].arg==0 ){
+    /* Ignore this option */
+  }else if( op[j].type==OPT_FLAG ){
+    *((int*)op[j].arg) = v;
+  }else if( op[j].type==OPT_FFLAG ){
+    (*(void(*)(int))(op[j].arg))(v);
+  }else if( op[j].type==OPT_FSTR ){
+    (*(void(*)(char *))(op[j].arg))(&argv[i][2]);
+  }else{
+    if( err ){
+      fprintf(err,"%smissing argument on switch.\n",emsg);
+      errline(i,1,err);
+    }
+    errcnt++;
+  }
+  return errcnt;
+}
+
+/*
+** Process a command line switch which has an argument.
+*/
+static int handleswitch(int i, FILE *err)
+{
+  int lv = 0;
+  double dv = 0.0;
+  char *sv = 0, *end;
+  char *cp;
+  int j;
+  int errcnt = 0;
+  cp = strchr(argv[i],'=');
+  assert( cp!=0 );
+  *cp = 0;
+  for(j=0; op[j].label; j++){
+    if( strcmp(argv[i],op[j].label)==0 ) break;
+  }
+  *cp = '=';
+  if( op[j].label==0 ){
+    if( err ){
+      fprintf(err,"%sundefined option.\n",emsg);
+      errline(i,0,err);
+    }
+    errcnt++;
+  }else{
+    cp++;
+    switch( op[j].type ){
+      case OPT_FLAG:
+      case OPT_FFLAG:
+        if( err ){
+          fprintf(err,"%soption requires an argument.\n",emsg);
+          errline(i,0,err);
+        }
+        errcnt++;
+        break;
+      case OPT_DBL:
+      case OPT_FDBL:
+        dv = strtod(cp,&end);
+        if( *end ){
+          if( err ){
+            fprintf(err,
+               "%sillegal character in floating-point argument.\n",emsg);
+            errline(i,(int)((char*)end-(char*)argv[i]),err);
+          }
+          errcnt++;
+        }
+        break;
+      case OPT_INT:
+      case OPT_FINT:
+        lv = strtol(cp,&end,0);
+        if( *end ){
+          if( err ){
+            fprintf(err,"%sillegal character in integer argument.\n",emsg);
+            errline(i,(int)((char*)end-(char*)argv[i]),err);
+          }
+          errcnt++;
+        }
+        break;
+      case OPT_STR:
+      case OPT_FSTR:
+        sv = cp;
+        break;
+    }
+    switch( op[j].type ){
+      case OPT_FLAG:
+      case OPT_FFLAG:
+        break;
+      case OPT_DBL:
+        *(double*)(op[j].arg) = dv;
+        break;
+      case OPT_FDBL:
+        (*(void(*)(double))(op[j].arg))(dv);
+        break;
+      case OPT_INT:
+        *(int*)(op[j].arg) = lv;
+        break;
+      case OPT_FINT:
+        (*(void(*)(int))(op[j].arg))((int)lv);
+        break;
+      case OPT_STR:
+        *(char**)(op[j].arg) = sv;
+        break;
+      case OPT_FSTR:
+        (*(void(*)(char *))(op[j].arg))(sv);
+        break;
+    }
+  }
+  return errcnt;
+}
+
+int OptInit(char **a, struct s_options *o, FILE *err)
+{
+  int errcnt = 0;
+  argv = a;
+  op = o;
+  errstream = err;
+  if( argv && *argv && op ){
+    int i;
+    for(i=1; argv[i]; i++){
+      if( argv[i][0]=='+' || argv[i][0]=='-' ){
+        errcnt += handleflags(i,err);
+      }else if( strchr(argv[i],'=') ){
+        errcnt += handleswitch(i,err);
+      }
+    }
+  }
+  if( errcnt>0 ){
+    fprintf(err,"Valid command line options for \"%s\" are:\n",*a);
+    OptPrint();
+    exit(1);
+  }
+  return 0;
+}
+
+int OptNArgs(){
+  int cnt = 0;
+  int dashdash = 0;
+  int i;
+  if( argv!=0 && argv[0]!=0 ){
+    for(i=1; argv[i]; i++){
+      if( dashdash || !ISOPT(argv[i]) ) cnt++;
+      if( strcmp(argv[i],"--")==0 ) dashdash = 1;
+    }
+  }
+  return cnt;
+}
+
+char *OptArg(int n)
+{
+  int i;
+  i = argindex(n);
+  return i>=0 ? argv[i] : 0;
+}
+
+void OptErr(int n)
+{
+  int i;
+  i = argindex(n);
+  if( i>=0 ) errline(i,0,errstream);
+}
+
+void OptPrint(){
+  int i;
+  int max, len;
+  max = 0;
+  for(i=0; op[i].label; i++){
+    len = lemonStrlen(op[i].label) + 1;
+    switch( op[i].type ){
+      case OPT_FLAG:
+      case OPT_FFLAG:
+        break;
+      case OPT_INT:
+      case OPT_FINT:
+        len += 9;       /* length of "<integer>" */
+        break;
+      case OPT_DBL:
+      case OPT_FDBL:
+        len += 6;       /* length of "<real>" */
+        break;
+      case OPT_STR:
+      case OPT_FSTR:
+        len += 8;       /* length of "<string>" */
+        break;
+    }
+    if( len>max ) max = len;
+  }
+  for(i=0; op[i].label; i++){
+    switch( op[i].type ){
+      case OPT_FLAG:
+      case OPT_FFLAG:
+        fprintf(errstream,"  -%-*s  %s\n",max,op[i].label,op[i].message);
+        break;
+      case OPT_INT:
+      case OPT_FINT:
+        fprintf(errstream,"  -%s<integer>%*s  %s\n",op[i].label,
+          (int)(max-lemonStrlen(op[i].label)-9),"",op[i].message);
+        break;
+      case OPT_DBL:
+      case OPT_FDBL:
+        fprintf(errstream,"  -%s<real>%*s  %s\n",op[i].label,
+          (int)(max-lemonStrlen(op[i].label)-6),"",op[i].message);
+        break;
+      case OPT_STR:
+      case OPT_FSTR:
+        fprintf(errstream,"  -%s<string>%*s  %s\n",op[i].label,
+          (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message);
+        break;
+    }
+  }
+}
+/*********************** From the file "parse.c" ****************************/
+/*
+** Input file parser for the LEMON parser generator.
+*/
+
+/* The state of the parser */
+enum e_state {
+  INITIALIZE,
+  WAITING_FOR_DECL_OR_RULE,
+  WAITING_FOR_DECL_KEYWORD,
+  WAITING_FOR_DECL_ARG,
+  WAITING_FOR_PRECEDENCE_SYMBOL,
+  WAITING_FOR_ARROW,
+  IN_RHS,
+  LHS_ALIAS_1,
+  LHS_ALIAS_2,
+  LHS_ALIAS_3,
+  RHS_ALIAS_1,
+  RHS_ALIAS_2,
+  PRECEDENCE_MARK_1,
+  PRECEDENCE_MARK_2,
+  RESYNC_AFTER_RULE_ERROR,
+  RESYNC_AFTER_DECL_ERROR,
+  WAITING_FOR_DESTRUCTOR_SYMBOL,
+  WAITING_FOR_DATATYPE_SYMBOL,
+  WAITING_FOR_FALLBACK_ID,
+  WAITING_FOR_WILDCARD_ID,
+  WAITING_FOR_CLASS_ID,
+  WAITING_FOR_CLASS_TOKEN
+};
+struct pstate {
+  char *filename;       /* Name of the input file */
+  int tokenlineno;      /* Linenumber at which current token starts */
+  int errorcnt;         /* Number of errors so far */
+  char *tokenstart;     /* Text of current token */
+  struct lemon *gp;     /* Global state vector */
+  enum e_state state;        /* The state of the parser */
+  struct symbol *fallback;   /* The fallback token */
+  struct symbol *tkclass;    /* Token class symbol */
+  struct symbol *lhs;        /* Left-hand side of current rule */
+  const char *lhsalias;      /* Alias for the LHS */
+  int nrhs;                  /* Number of right-hand side symbols seen */
+  struct symbol *rhs[MAXRHS];  /* RHS symbols */
+  const char *alias[MAXRHS]; /* Aliases for each RHS symbol (or NULL) */
+  struct rule *prevrule;     /* Previous rule parsed */
+  const char *declkeyword;   /* Keyword of a declaration */
+  char **declargslot;        /* Where the declaration argument should be put */
+  int insertLineMacro;       /* Add #line before declaration insert */
+  int *decllinenoslot;       /* Where to write declaration line number */
+  enum e_assoc declassoc;    /* Assign this association to decl arguments */
+  int preccounter;           /* Assign this precedence to decl arguments */
+  struct rule *firstrule;    /* Pointer to first rule in the grammar */
+  struct rule *lastrule;     /* Pointer to the most recently parsed rule */
+};
+
+/* Parse a single token */
+static void parseonetoken(struct pstate *psp)
+{
+  const char *x;
+  x = Strsafe(psp->tokenstart);     /* Save the token permanently */
+#if 0
+  printf("%s:%d: Token=[%s] state=%d\n",psp->filename,psp->tokenlineno,
+    x,psp->state);
+#endif
+  switch( psp->state ){
+    case INITIALIZE:
+      psp->prevrule = 0;
+      psp->preccounter = 0;
+      psp->firstrule = psp->lastrule = 0;
+      psp->gp->nrule = 0;
+      /* Fall thru to next case */
+    case WAITING_FOR_DECL_OR_RULE:
+      if( x[0]=='%' ){
+        psp->state = WAITING_FOR_DECL_KEYWORD;
+      }else if( ISLOWER(x[0]) ){
+        psp->lhs = Symbol_new(x);
+        psp->nrhs = 0;
+        psp->lhsalias = 0;
+        psp->state = WAITING_FOR_ARROW;
+      }else if( x[0]=='{' ){
+        if( psp->prevrule==0 ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+"There is no prior rule upon which to attach the code \
+fragment which begins on this line.");
+          psp->errorcnt++;
+        }else if( psp->prevrule->code!=0 ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+"Code fragment beginning on this line is not the first \
+to follow the previous rule.");
+          psp->errorcnt++;
+        }else{
+          psp->prevrule->line = psp->tokenlineno;
+          psp->prevrule->code = &x[1];
+          psp->prevrule->noCode = 0;
+        }
+      }else if( x[0]=='[' ){
+        psp->state = PRECEDENCE_MARK_1;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Token \"%s\" should be either \"%%\" or a nonterminal name.",
+          x);
+        psp->errorcnt++;
+      }
+      break;
+    case PRECEDENCE_MARK_1:
+      if( !ISUPPER(x[0]) ){
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "The precedence symbol must be a terminal.");
+        psp->errorcnt++;
+      }else if( psp->prevrule==0 ){
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "There is no prior rule to assign precedence \"[%s]\".",x);
+        psp->errorcnt++;
+      }else if( psp->prevrule->precsym!=0 ){
+        ErrorMsg(psp->filename,psp->tokenlineno,
+"Precedence mark on this line is not the first \
+to follow the previous rule.");
+        psp->errorcnt++;
+      }else{
+        psp->prevrule->precsym = Symbol_new(x);
+      }
+      psp->state = PRECEDENCE_MARK_2;
+      break;
+    case PRECEDENCE_MARK_2:
+      if( x[0]!=']' ){
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Missing \"]\" on precedence mark.");
+        psp->errorcnt++;
+      }
+      psp->state = WAITING_FOR_DECL_OR_RULE;
+      break;
+    case WAITING_FOR_ARROW:
+      if( x[0]==':' && x[1]==':' && x[2]=='=' ){
+        psp->state = IN_RHS;
+      }else if( x[0]=='(' ){
+        psp->state = LHS_ALIAS_1;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Expected to see a \":\" following the LHS symbol \"%s\".",
+          psp->lhs->name);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case LHS_ALIAS_1:
+      if( ISALPHA(x[0]) ){
+        psp->lhsalias = x;
+        psp->state = LHS_ALIAS_2;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "\"%s\" is not a valid alias for the LHS \"%s\"\n",
+          x,psp->lhs->name);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case LHS_ALIAS_2:
+      if( x[0]==')' ){
+        psp->state = LHS_ALIAS_3;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case LHS_ALIAS_3:
+      if( x[0]==':' && x[1]==':' && x[2]=='=' ){
+        psp->state = IN_RHS;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Missing \"->\" following: \"%s(%s)\".",
+           psp->lhs->name,psp->lhsalias);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case IN_RHS:
+      if( x[0]=='.' ){
+        struct rule *rp;
+        rp = (struct rule *)calloc( sizeof(struct rule) + 
+             sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1);
+        if( rp==0 ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+            "Can't allocate enough memory for this rule.");
+          psp->errorcnt++;
+          psp->prevrule = 0;
+        }else{
+          int i;
+          rp->ruleline = psp->tokenlineno;
+          rp->rhs = (struct symbol**)&rp[1];
+          rp->rhsalias = (const char**)&(rp->rhs[psp->nrhs]);
+          for(i=0; i<psp->nrhs; i++){
+            rp->rhs[i] = psp->rhs[i];
+            rp->rhsalias[i] = psp->alias[i];
+          }
+          rp->lhs = psp->lhs;
+          rp->lhsalias = psp->lhsalias;
+          rp->nrhs = psp->nrhs;
+          rp->code = 0;
+          rp->noCode = 1;
+          rp->precsym = 0;
+          rp->index = psp->gp->nrule++;
+          rp->nextlhs = rp->lhs->rule;
+          rp->lhs->rule = rp;
+          rp->next = 0;
+          if( psp->firstrule==0 ){
+            psp->firstrule = psp->lastrule = rp;
+          }else{
+            psp->lastrule->next = rp;
+            psp->lastrule = rp;
+          }
+          psp->prevrule = rp;
+        }
+        psp->state = WAITING_FOR_DECL_OR_RULE;
+      }else if( ISALPHA(x[0]) ){
+        if( psp->nrhs>=MAXRHS ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+            "Too many symbols on RHS of rule beginning at \"%s\".",
+            x);
+          psp->errorcnt++;
+          psp->state = RESYNC_AFTER_RULE_ERROR;
+        }else{
+          psp->rhs[psp->nrhs] = Symbol_new(x);
+          psp->alias[psp->nrhs] = 0;
+          psp->nrhs++;
+        }
+      }else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 ){
+        struct symbol *msp = psp->rhs[psp->nrhs-1];
+        if( msp->type!=MULTITERMINAL ){
+          struct symbol *origsp = msp;
+          msp = (struct symbol *) calloc(1,sizeof(*msp));
+          memset(msp, 0, sizeof(*msp));
+          msp->type = MULTITERMINAL;
+          msp->nsubsym = 1;
+          msp->subsym = (struct symbol **) calloc(1,sizeof(struct symbol*));
+          msp->subsym[0] = origsp;
+          msp->name = origsp->name;
+          psp->rhs[psp->nrhs-1] = msp;
+        }
+        msp->nsubsym++;
+        msp->subsym = (struct symbol **) realloc(msp->subsym,
+          sizeof(struct symbol*)*msp->nsubsym);
+        msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]);
+        if( ISLOWER(x[1]) || ISLOWER(msp->subsym[0]->name[0]) ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+            "Cannot form a compound containing a non-terminal");
+          psp->errorcnt++;
+        }
+      }else if( x[0]=='(' && psp->nrhs>0 ){
+        psp->state = RHS_ALIAS_1;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Illegal character on RHS of rule: \"%s\".",x);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case RHS_ALIAS_1:
+      if( ISALPHA(x[0]) ){
+        psp->alias[psp->nrhs-1] = x;
+        psp->state = RHS_ALIAS_2;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "\"%s\" is not a valid alias for the RHS symbol \"%s\"\n",
+          x,psp->rhs[psp->nrhs-1]->name);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case RHS_ALIAS_2:
+      if( x[0]==')' ){
+        psp->state = IN_RHS;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_RULE_ERROR;
+      }
+      break;
+    case WAITING_FOR_DECL_KEYWORD:
+      if( ISALPHA(x[0]) ){
+        psp->declkeyword = x;
+        psp->declargslot = 0;
+        psp->decllinenoslot = 0;
+        psp->insertLineMacro = 1;
+        psp->state = WAITING_FOR_DECL_ARG;
+        if( strcmp(x,"name")==0 ){
+          psp->declargslot = &(psp->gp->name);
+          psp->insertLineMacro = 0;
+        }else if( strcmp(x,"include")==0 ){
+          psp->declargslot = &(psp->gp->include);
+        }else if( strcmp(x,"code")==0 ){
+          psp->declargslot = &(psp->gp->extracode);
+        }else if( strcmp(x,"token_destructor")==0 ){
+          psp->declargslot = &psp->gp->tokendest;
+        }else if( strcmp(x,"default_destructor")==0 ){
+          psp->declargslot = &psp->gp->vardest;
+        }else if( strcmp(x,"token_prefix")==0 ){
+          psp->declargslot = &psp->gp->tokenprefix;
+          psp->insertLineMacro = 0;
+        }else if( strcmp(x,"syntax_error")==0 ){
+          psp->declargslot = &(psp->gp->error);
+        }else if( strcmp(x,"parse_accept")==0 ){
+          psp->declargslot = &(psp->gp->accept);
+        }else if( strcmp(x,"parse_failure")==0 ){
+          psp->declargslot = &(psp->gp->failure);
+        }else if( strcmp(x,"stack_overflow")==0 ){
+          psp->declargslot = &(psp->gp->overflow);
+        }else if( strcmp(x,"extra_argument")==0 ){
+          psp->declargslot = &(psp->gp->arg);
+          psp->insertLineMacro = 0;
+        }else if( strcmp(x,"token_type")==0 ){
+          psp->declargslot = &(psp->gp->tokentype);
+          psp->insertLineMacro = 0;
+        }else if( strcmp(x,"default_type")==0 ){
+          psp->declargslot = &(psp->gp->vartype);
+          psp->insertLineMacro = 0;
+        }else if( strcmp(x,"stack_size")==0 ){
+          psp->declargslot = &(psp->gp->stacksize);
+          psp->insertLineMacro = 0;
+        }else if( strcmp(x,"start_symbol")==0 ){
+          psp->declargslot = &(psp->gp->start);
+          psp->insertLineMacro = 0;
+        }else if( strcmp(x,"left")==0 ){
+          psp->preccounter++;
+          psp->declassoc = LEFT;
+          psp->state = WAITING_FOR_PRECEDENCE_SYMBOL;
+        }else if( strcmp(x,"right")==0 ){
+          psp->preccounter++;
+          psp->declassoc = RIGHT;
+          psp->state = WAITING_FOR_PRECEDENCE_SYMBOL;
+        }else if( strcmp(x,"nonassoc")==0 ){
+          psp->preccounter++;
+          psp->declassoc = NONE;
+          psp->state = WAITING_FOR_PRECEDENCE_SYMBOL;
+        }else if( strcmp(x,"destructor")==0 ){
+          psp->state = WAITING_FOR_DESTRUCTOR_SYMBOL;
+        }else if( strcmp(x,"type")==0 ){
+          psp->state = WAITING_FOR_DATATYPE_SYMBOL;
+        }else if( strcmp(x,"fallback")==0 ){
+          psp->fallback = 0;
+          psp->state = WAITING_FOR_FALLBACK_ID;
+        }else if( strcmp(x,"wildcard")==0 ){
+          psp->state = WAITING_FOR_WILDCARD_ID;
+        }else if( strcmp(x,"token_class")==0 ){
+          psp->state = WAITING_FOR_CLASS_ID;
+        }else{
+          ErrorMsg(psp->filename,psp->tokenlineno,
+            "Unknown declaration keyword: \"%%%s\".",x);
+          psp->errorcnt++;
+          psp->state = RESYNC_AFTER_DECL_ERROR;
+        }
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Illegal declaration keyword: \"%s\".",x);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_DECL_ERROR;
+      }
+      break;
+    case WAITING_FOR_DESTRUCTOR_SYMBOL:
+      if( !ISALPHA(x[0]) ){
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Symbol name missing after %%destructor keyword");
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_DECL_ERROR;
+      }else{
+        struct symbol *sp = Symbol_new(x);
+        psp->declargslot = &sp->destructor;
+        psp->decllinenoslot = &sp->destLineno;
+        psp->insertLineMacro = 1;
+        psp->state = WAITING_FOR_DECL_ARG;
+      }
+      break;
+    case WAITING_FOR_DATATYPE_SYMBOL:
+      if( !ISALPHA(x[0]) ){
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Symbol name missing after %%type keyword");
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_DECL_ERROR;
+      }else{
+        struct symbol *sp = Symbol_find(x);
+        if((sp) && (sp->datatype)){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+            "Symbol %%type \"%s\" already defined", x);
+          psp->errorcnt++;
+          psp->state = RESYNC_AFTER_DECL_ERROR;
+        }else{
+          if (!sp){
+            sp = Symbol_new(x);
+          }
+          psp->declargslot = &sp->datatype;
+          psp->insertLineMacro = 0;
+          psp->state = WAITING_FOR_DECL_ARG;
+        }
+      }
+      break;
+    case WAITING_FOR_PRECEDENCE_SYMBOL:
+      if( x[0]=='.' ){
+        psp->state = WAITING_FOR_DECL_OR_RULE;
+      }else if( ISUPPER(x[0]) ){
+        struct symbol *sp;
+        sp = Symbol_new(x);
+        if( sp->prec>=0 ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+            "Symbol \"%s\" has already be given a precedence.",x);
+          psp->errorcnt++;
+        }else{
+          sp->prec = psp->preccounter;
+          sp->assoc = psp->declassoc;
+        }
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Can't assign a precedence to \"%s\".",x);
+        psp->errorcnt++;
+      }
+      break;
+    case WAITING_FOR_DECL_ARG:
+      if( x[0]=='{' || x[0]=='\"' || ISALNUM(x[0]) ){
+        const char *zOld, *zNew;
+        char *zBuf, *z;
+        int nOld, n, nLine = 0, nNew, nBack;
+        int addLineMacro;
+        char zLine[50];
+        zNew = x;
+        if( zNew[0]=='"' || zNew[0]=='{' ) zNew++;
+        nNew = lemonStrlen(zNew);
+        if( *psp->declargslot ){
+          zOld = *psp->declargslot;
+        }else{
+          zOld = "";
+        }
+        nOld = lemonStrlen(zOld);
+        n = nOld + nNew + 20;
+        addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro &&
+                        (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0);
+        if( addLineMacro ){
+          for(z=psp->filename, nBack=0; *z; z++){
+            if( *z=='\\' ) nBack++;
+          }
+          lemon_sprintf(zLine, "#line %d ", psp->tokenlineno);
+          nLine = lemonStrlen(zLine);
+          n += nLine + lemonStrlen(psp->filename) + nBack;
+        }
+        *psp->declargslot = (char *) realloc(*psp->declargslot, n);
+        zBuf = *psp->declargslot + nOld;
+        if( addLineMacro ){
+          if( nOld && zBuf[-1]!='\n' ){
+            *(zBuf++) = '\n';
+          }
+          memcpy(zBuf, zLine, nLine);
+          zBuf += nLine;
+          *(zBuf++) = '"';
+          for(z=psp->filename; *z; z++){
+            if( *z=='\\' ){
+              *(zBuf++) = '\\';
+            }
+            *(zBuf++) = *z;
+          }
+          *(zBuf++) = '"';
+          *(zBuf++) = '\n';
+        }
+        if( psp->decllinenoslot && psp->decllinenoslot[0]==0 ){
+          psp->decllinenoslot[0] = psp->tokenlineno;
+        }
+        memcpy(zBuf, zNew, nNew);
+        zBuf += nNew;
+        *zBuf = 0;
+        psp->state = WAITING_FOR_DECL_OR_RULE;
+      }else{
+        ErrorMsg(psp->filename,psp->tokenlineno,
+          "Illegal argument to %%%s: %s",psp->declkeyword,x);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_DECL_ERROR;
+      }
+      break;
+    case WAITING_FOR_FALLBACK_ID:
+      if( x[0]=='.' ){
+        psp->state = WAITING_FOR_DECL_OR_RULE;
+      }else if( !ISUPPER(x[0]) ){
+        ErrorMsg(psp->filename, psp->tokenlineno,
+          "%%fallback argument \"%s\" should be a token", x);
+        psp->errorcnt++;
+      }else{
+        struct symbol *sp = Symbol_new(x);
+        if( psp->fallback==0 ){
+          psp->fallback = sp;
+        }else if( sp->fallback ){
+          ErrorMsg(psp->filename, psp->tokenlineno,
+            "More than one fallback assigned to token %s", x);
+          psp->errorcnt++;
+        }else{
+          sp->fallback = psp->fallback;
+          psp->gp->has_fallback = 1;
+        }
+      }
+      break;
+    case WAITING_FOR_WILDCARD_ID:
+      if( x[0]=='.' ){
+        psp->state = WAITING_FOR_DECL_OR_RULE;
+      }else if( !ISUPPER(x[0]) ){
+        ErrorMsg(psp->filename, psp->tokenlineno,
+          "%%wildcard argument \"%s\" should be a token", x);
+        psp->errorcnt++;
+      }else{
+        struct symbol *sp = Symbol_new(x);
+        if( psp->gp->wildcard==0 ){
+          psp->gp->wildcard = sp;
+        }else{
+          ErrorMsg(psp->filename, psp->tokenlineno,
+            "Extra wildcard to token: %s", x);
+          psp->errorcnt++;
+        }
+      }
+      break;
+    case WAITING_FOR_CLASS_ID:
+      if( !ISLOWER(x[0]) ){
+        ErrorMsg(psp->filename, psp->tokenlineno,
+          "%%token_class must be followed by an identifier: ", x);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_DECL_ERROR;
+     }else if( Symbol_find(x) ){
+        ErrorMsg(psp->filename, psp->tokenlineno,
+          "Symbol \"%s\" already used", x);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_DECL_ERROR;
+      }else{
+        psp->tkclass = Symbol_new(x);
+        psp->tkclass->type = MULTITERMINAL;
+        psp->state = WAITING_FOR_CLASS_TOKEN;
+      }
+      break;
+    case WAITING_FOR_CLASS_TOKEN:
+      if( x[0]=='.' ){
+        psp->state = WAITING_FOR_DECL_OR_RULE;
+      }else if( ISUPPER(x[0]) || ((x[0]=='|' || x[0]=='/') && ISUPPER(x[1])) ){
+        struct symbol *msp = psp->tkclass;
+        msp->nsubsym++;
+        msp->subsym = (struct symbol **) realloc(msp->subsym,
+          sizeof(struct symbol*)*msp->nsubsym);
+        if( !ISUPPER(x[0]) ) x++;
+        msp->subsym[msp->nsubsym-1] = Symbol_new(x);
+      }else{
+        ErrorMsg(psp->filename, psp->tokenlineno,
+          "%%token_class argument \"%s\" should be a token", x);
+        psp->errorcnt++;
+        psp->state = RESYNC_AFTER_DECL_ERROR;
+      }
+      break;
+    case RESYNC_AFTER_RULE_ERROR:
+/*      if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE;
+**      break; */
+    case RESYNC_AFTER_DECL_ERROR:
+      if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE;
+      if( x[0]=='%' ) psp->state = WAITING_FOR_DECL_KEYWORD;
+      break;
+  }
+}
+
+/* Run the preprocessor over the input file text.  The global variables
+** azDefine[0] through azDefine[nDefine-1] contains the names of all defined
+** macros.  This routine looks for "%ifdef" and "%ifndef" and "%endif" and
+** comments them out.  Text in between is also commented out as appropriate.
+*/
+static void preprocess_input(char *z){
+  int i, j, k, n;
+  int exclude = 0;
+  int start = 0;
+  int lineno = 1;
+  int start_lineno = 1;
+  for(i=0; z[i]; i++){
+    if( z[i]=='\n' ) lineno++;
+    if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue;
+    if( strncmp(&z[i],"%endif",6)==0 && ISSPACE(z[i+6]) ){
+      if( exclude ){
+        exclude--;
+        if( exclude==0 ){
+          for(j=start; j<i; j++) if( z[j]!='\n' ) z[j] = ' ';
+        }
+      }
+      for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' ';
+    }else if( (strncmp(&z[i],"%ifdef",6)==0 && ISSPACE(z[i+6]))
+          || (strncmp(&z[i],"%ifndef",7)==0 && ISSPACE(z[i+7])) ){
+      if( exclude ){
+        exclude++;
+      }else{
+        for(j=i+7; ISSPACE(z[j]); j++){}
+        for(n=0; z[j+n] && !ISSPACE(z[j+n]); n++){}
+        exclude = 1;
+        for(k=0; k<nDefine; k++){
+          if( strncmp(azDefine[k],&z[j],n)==0 && lemonStrlen(azDefine[k])==n ){
+            exclude = 0;
+            break;
+          }
+        }
+        if( z[i+3]=='n' ) exclude = !exclude;
+        if( exclude ){
+          start = i;
+          start_lineno = lineno;
+        }
+      }
+      for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' ';
+    }
+  }
+  if( exclude ){
+    fprintf(stderr,"unterminated %%ifdef starting on line %d\n", start_lineno);
+    exit(1);
+  }
+}
+
+/* In spite of its name, this function is really a scanner.  It read
+** in the entire input file (all at once) then tokenizes it.  Each
+** token is passed to the function "parseonetoken" which builds all
+** the appropriate data structures in the global state vector "gp".
+*/
+void Parse(struct lemon *gp)
+{
+  struct pstate ps;
+  FILE *fp;
+  char *filebuf;
+  unsigned int filesize;
+  int lineno;
+  int c;
+  char *cp, *nextcp;
+  int startline = 0;
+
+  memset(&ps, '\0', sizeof(ps));
+  ps.gp = gp;
+  ps.filename = gp->filename;
+  ps.errorcnt = 0;
+  ps.state = INITIALIZE;
+
+  /* Begin by reading the input file */
+  fp = fopen(ps.filename,"rb");
+  if( fp==0 ){
+    ErrorMsg(ps.filename,0,"Can't open this file for reading.");
+    gp->errorcnt++;
+    return;
+  }
+  fseek(fp,0,2);
+  filesize = ftell(fp);
+  rewind(fp);
+  filebuf = (char *)malloc( filesize+1 );
+  if( filesize>100000000 || filebuf==0 ){
+    ErrorMsg(ps.filename,0,"Input file too large.");
+    gp->errorcnt++;
+    fclose(fp);
+    return;
+  }
+  if( fread(filebuf,1,filesize,fp)!=filesize ){
+    ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.",
+      filesize);
+    free(filebuf);
+    gp->errorcnt++;
+    fclose(fp);
+    return;
+  }
+  fclose(fp);
+  filebuf[filesize] = 0;
+
+  /* Make an initial pass through the file to handle %ifdef and %ifndef */
+  preprocess_input(filebuf);
+
+  /* Now scan the text of the input file */
+  lineno = 1;
+  for(cp=filebuf; (c= *cp)!=0; ){
+    if( c=='\n' ) lineno++;              /* Keep track of the line number */
+    if( ISSPACE(c) ){ cp++; continue; }  /* Skip all white space */
+    if( c=='/' && cp[1]=='/' ){          /* Skip C++ style comments */
+      cp+=2;
+      while( (c= *cp)!=0 && c!='\n' ) cp++;
+      continue;
+    }
+    if( c=='/' && cp[1]=='*' ){          /* Skip C style comments */
+      cp+=2;
+      while( (c= *cp)!=0 && (c!='/' || cp[-1]!='*') ){
+        if( c=='\n' ) lineno++;
+        cp++;
+      }
+      if( c ) cp++;
+      continue;
+    }
+    ps.tokenstart = cp;                /* Mark the beginning of the token */
+    ps.tokenlineno = lineno;           /* Linenumber on which token begins */
+    if( c=='\"' ){                     /* String literals */
+      cp++;
+      while( (c= *cp)!=0 && c!='\"' ){
+        if( c=='\n' ) lineno++;
+        cp++;
+      }
+      if( c==0 ){
+        ErrorMsg(ps.filename,startline,
+"String starting on this line is not terminated before the end of the file.");
+        ps.errorcnt++;
+        nextcp = cp;
+      }else{
+        nextcp = cp+1;
+      }
+    }else if( c=='{' ){               /* A block of C code */
+      int level;
+      cp++;
+      for(level=1; (c= *cp)!=0 && (level>1 || c!='}'); cp++){
+        if( c=='\n' ) lineno++;
+        else if( c=='{' ) level++;
+        else if( c=='}' ) level--;
+        else if( c=='/' && cp[1]=='*' ){  /* Skip comments */
+          int prevc;
+          cp = &cp[2];
+          prevc = 0;
+          while( (c= *cp)!=0 && (c!='/' || prevc!='*') ){
+            if( c=='\n' ) lineno++;
+            prevc = c;
+            cp++;
+          }
+        }else if( c=='/' && cp[1]=='/' ){  /* Skip C++ style comments too */
+          cp = &cp[2];
+          while( (c= *cp)!=0 && c!='\n' ) cp++;
+          if( c ) lineno++;
+        }else if( c=='\'' || c=='\"' ){    /* String a character literals */
+          int startchar, prevc;
+          startchar = c;
+          prevc = 0;
+          for(cp++; (c= *cp)!=0 && (c!=startchar || prevc=='\\'); cp++){
+            if( c=='\n' ) lineno++;
+            if( prevc=='\\' ) prevc = 0;
+            else              prevc = c;
+          }
+        }
+      }
+      if( c==0 ){
+        ErrorMsg(ps.filename,ps.tokenlineno,
+"C code starting on this line is not terminated before the end of the file.");
+        ps.errorcnt++;
+        nextcp = cp;
+      }else{
+        nextcp = cp+1;
+      }
+    }else if( ISALNUM(c) ){          /* Identifiers */
+      while( (c= *cp)!=0 && (ISALNUM(c) || c=='_') ) cp++;
+      nextcp = cp;
+    }else if( c==':' && cp[1]==':' && cp[2]=='=' ){ /* The operator "::=" */
+      cp += 3;
+      nextcp = cp;
+    }else if( (c=='/' || c=='|') && ISALPHA(cp[1]) ){
+      cp += 2;
+      while( (c = *cp)!=0 && (ISALNUM(c) || c=='_') ) cp++;
+      nextcp = cp;
+    }else{                          /* All other (one character) operators */
+      cp++;
+      nextcp = cp;
+    }
+    c = *cp;
+    *cp = 0;                        /* Null terminate the token */
+    parseonetoken(&ps);             /* Parse the token */
+    *cp = (char)c;                  /* Restore the buffer */
+    cp = nextcp;
+  }
+  free(filebuf);                    /* Release the buffer after parsing */
+  gp->rule = ps.firstrule;
+  gp->errorcnt = ps.errorcnt;
+}
+/*************************** From the file "plink.c" *********************/
+/*
+** Routines processing configuration follow-set propagation links
+** in the LEMON parser generator.
+*/
+static struct plink *plink_freelist = 0;
+
+/* Allocate a new plink */
+struct plink *Plink_new(){
+  struct plink *newlink;
+
+  if( plink_freelist==0 ){
+    int i;
+    int amt = 100;
+    plink_freelist = (struct plink *)calloc( amt, sizeof(struct plink) );
+    if( plink_freelist==0 ){
+      fprintf(stderr,
+      "Unable to allocate memory for a new follow-set propagation link.\n");
+      exit(1);
+    }
+    for(i=0; i<amt-1; i++) plink_freelist[i].next = &plink_freelist[i+1];
+    plink_freelist[amt-1].next = 0;
+  }
+  newlink = plink_freelist;
+  plink_freelist = plink_freelist->next;
+  return newlink;
+}
+
+/* Add a plink to a plink list */
+void Plink_add(struct plink **plpp, struct config *cfp)
+{
+  struct plink *newlink;
+  newlink = Plink_new();
+  newlink->next = *plpp;
+  *plpp = newlink;
+  newlink->cfp = cfp;
+}
+
+/* Transfer every plink on the list "from" to the list "to" */
+void Plink_copy(struct plink **to, struct plink *from)
+{
+  struct plink *nextpl;
+  while( from ){
+    nextpl = from->next;
+    from->next = *to;
+    *to = from;
+    from = nextpl;
+  }
+}
+
+/* Delete every plink on the list */
+void Plink_delete(struct plink *plp)
+{
+  struct plink *nextpl;
+
+  while( plp ){
+    nextpl = plp->next;
+    plp->next = plink_freelist;
+    plink_freelist = plp;
+    plp = nextpl;
+  }
+}
+/*********************** From the file "report.c" **************************/
+/*
+** Procedures for generating reports and tables in the LEMON parser generator.
+*/
+
+/* Generate a filename with the given suffix.  Space to hold the
+** name comes from malloc() and must be freed by the calling
+** function.
+*/
+PRIVATE char *file_makename(struct lemon *lemp, const char *suffix)
+{
+  char *name;
+  char *cp;
+
+  name = (char*)malloc( lemonStrlen(lemp->filename) + lemonStrlen(suffix) + 5 );
+  if( name==0 ){
+    fprintf(stderr,"Can't allocate space for a filename.\n");
+    exit(1);
+  }
+  lemon_strcpy(name,lemp->filename);
+  cp = strrchr(name,'.');
+  if( cp ) *cp = 0;
+  lemon_strcat(name,suffix);
+  return name;
+}
+
+/* Open a file with a name based on the name of the input file,
+** but with a different (specified) suffix, and return a pointer
+** to the stream */
+PRIVATE FILE *file_open(
+  struct lemon *lemp,
+  const char *suffix,
+  const char *mode
+){
+  FILE *fp;
+
+  if( lemp->outname ) free(lemp->outname);
+  lemp->outname = file_makename(lemp, suffix);
+  fp = fopen(lemp->outname,mode);
+  if( fp==0 && *mode=='w' ){
+    fprintf(stderr,"Can't open file \"%s\".\n",lemp->outname);
+    lemp->errorcnt++;
+    return 0;
+  }
+  return fp;
+}
+
+/* Duplicate the input file without comments and without actions 
+** on rules */
+void Reprint(struct lemon *lemp)
+{
+  struct rule *rp;
+  struct symbol *sp;
+  int i, j, maxlen, len, ncolumns, skip;
+  printf("// Reprint of input file \"%s\".\n// Symbols:\n",lemp->filename);
+  maxlen = 10;
+  for(i=0; i<lemp->nsymbol; i++){
+    sp = lemp->symbols[i];
+    len = lemonStrlen(sp->name);
+    if( len>maxlen ) maxlen = len;
+  }
+  ncolumns = 76/(maxlen+5);
+  if( ncolumns<1 ) ncolumns = 1;
+  skip = (lemp->nsymbol + ncolumns - 1)/ncolumns;
+  for(i=0; i<skip; i++){
+    printf("//");
+    for(j=i; j<lemp->nsymbol; j+=skip){
+      sp = lemp->symbols[j];
+      assert( sp->index==j );
+      printf(" %3d %-*.*s",j,maxlen,maxlen,sp->name);
+    }
+    printf("\n");
+  }
+  for(rp=lemp->rule; rp; rp=rp->next){
+    printf("%s",rp->lhs->name);
+    /*    if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */
+    printf(" ::=");
+    for(i=0; i<rp->nrhs; i++){
+      sp = rp->rhs[i];
+      if( sp->type==MULTITERMINAL ){
+        printf(" %s", sp->subsym[0]->name);
+        for(j=1; j<sp->nsubsym; j++){
+          printf("|%s", sp->subsym[j]->name);
+        }
+      }else{
+        printf(" %s", sp->name);
+      }
+      /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */
+    }
+    printf(".");
+    if( rp->precsym ) printf(" [%s]",rp->precsym->name);
+    /* if( rp->code ) printf("\n    %s",rp->code); */
+    printf("\n");
+  }
+}
+
+/* Print a single rule.
+*/
+void RulePrint(FILE *fp, struct rule *rp, int iCursor){
+  struct symbol *sp;
+  int i, j;
+  fprintf(fp,"%s ::=",rp->lhs->name);
+  for(i=0; i<=rp->nrhs; i++){
+    if( i==iCursor ) fprintf(fp," *");
+    if( i==rp->nrhs ) break;
+    sp = rp->rhs[i];
+    if( sp->type==MULTITERMINAL ){
+      fprintf(fp," %s", sp->subsym[0]->name);
+      for(j=1; j<sp->nsubsym; j++){
+        fprintf(fp,"|%s",sp->subsym[j]->name);
+      }
+    }else{
+      fprintf(fp," %s", sp->name);
+    }
+  }
+}
+
+/* Print the rule for a configuration.
+*/
+void ConfigPrint(FILE *fp, struct config *cfp){
+  RulePrint(fp, cfp->rp, cfp->dot);
+}
+
+/* #define TEST */
+#if 0
+/* Print a set */
+PRIVATE void SetPrint(out,set,lemp)
+FILE *out;
+char *set;
+struct lemon *lemp;
+{
+  int i;
+  char *spacer;
+  spacer = "";
+  fprintf(out,"%12s[","");
+  for(i=0; i<lemp->nterminal; i++){
+    if( SetFind(set,i) ){
+      fprintf(out,"%s%s",spacer,lemp->symbols[i]->name);
+      spacer = " ";
+    }
+  }
+  fprintf(out,"]\n");
+}
+
+/* Print a plink chain */
+PRIVATE void PlinkPrint(out,plp,tag)
+FILE *out;
+struct plink *plp;
+char *tag;
+{
+  while( plp ){
+    fprintf(out,"%12s%s (state %2d) ","",tag,plp->cfp->stp->statenum);
+    ConfigPrint(out,plp->cfp);
+    fprintf(out,"\n");
+    plp = plp->next;
+  }
+}
+#endif
+
+/* Print an action to the given file descriptor.  Return FALSE if
+** nothing was actually printed.
+*/
+int PrintAction(
+  struct action *ap,          /* The action to print */
+  FILE *fp,                   /* Print the action here */
+  int indent                  /* Indent by this amount */
+){
+  int result = 1;
+  switch( ap->type ){
+    case SHIFT: {
+      struct state *stp = ap->x.stp;
+      fprintf(fp,"%*s shift        %-7d",indent,ap->sp->name,stp->statenum);
+      break;
+    }
+    case REDUCE: {
+      struct rule *rp = ap->x.rp;
+      fprintf(fp,"%*s reduce       %-7d",indent,ap->sp->name,rp->iRule);
+      RulePrint(fp, rp, -1);
+      break;
+    }
+    case SHIFTREDUCE: {
+      struct rule *rp = ap->x.rp;
+      fprintf(fp,"%*s shift-reduce %-7d",indent,ap->sp->name,rp->iRule);
+      RulePrint(fp, rp, -1);
+      break;
+    }
+    case ACCEPT:
+      fprintf(fp,"%*s accept",indent,ap->sp->name);
+      break;
+    case ERROR:
+      fprintf(fp,"%*s error",indent,ap->sp->name);
+      break;
+    case SRCONFLICT:
+    case RRCONFLICT:
+      fprintf(fp,"%*s reduce       %-7d ** Parsing conflict **",
+        indent,ap->sp->name,ap->x.rp->iRule);
+      break;
+    case SSCONFLICT:
+      fprintf(fp,"%*s shift        %-7d ** Parsing conflict **", 
+        indent,ap->sp->name,ap->x.stp->statenum);
+      break;
+    case SH_RESOLVED:
+      if( showPrecedenceConflict ){
+        fprintf(fp,"%*s shift        %-7d -- dropped by precedence",
+                indent,ap->sp->name,ap->x.stp->statenum);
+      }else{
+        result = 0;
+      }
+      break;
+    case RD_RESOLVED:
+      if( showPrecedenceConflict ){
+        fprintf(fp,"%*s reduce %-7d -- dropped by precedence",
+                indent,ap->sp->name,ap->x.rp->iRule);
+      }else{
+        result = 0;
+      }
+      break;
+    case NOT_USED:
+      result = 0;
+      break;
+  }
+  if( result && ap->spOpt ){
+    fprintf(fp,"  /* because %s==%s */", ap->sp->name, ap->spOpt->name);
+  }
+  return result;
+}
+
+/* Generate the "*.out" log file */
+void ReportOutput(struct lemon *lemp)
+{
+  int i;
+  struct state *stp;
+  struct config *cfp;
+  struct action *ap;
+  FILE *fp;
+
+  fp = file_open(lemp,".out","wb");
+  if( fp==0 ) return;
+  for(i=0; i<lemp->nxstate; i++){
+    stp = lemp->sorted[i];
+    fprintf(fp,"State %d:\n",stp->statenum);
+    if( lemp->basisflag ) cfp=stp->bp;
+    else                  cfp=stp->cfp;
+    while( cfp ){
+      char buf[20];
+      if( cfp->dot==cfp->rp->nrhs ){
+        lemon_sprintf(buf,"(%d)",cfp->rp->iRule);
+        fprintf(fp,"    %5s ",buf);
+      }else{
+        fprintf(fp,"          ");
+      }
+      ConfigPrint(fp,cfp);
+      fprintf(fp,"\n");
+#if 0
+      SetPrint(fp,cfp->fws,lemp);
+      PlinkPrint(fp,cfp->fplp,"To  ");
+      PlinkPrint(fp,cfp->bplp,"From");
+#endif
+      if( lemp->basisflag ) cfp=cfp->bp;
+      else                  cfp=cfp->next;
+    }
+    fprintf(fp,"\n");
+    for(ap=stp->ap; ap; ap=ap->next){
+      if( PrintAction(ap,fp,30) ) fprintf(fp,"\n");
+    }
+    fprintf(fp,"\n");
+  }
+  fprintf(fp, "----------------------------------------------------\n");
+  fprintf(fp, "Symbols:\n");
+  for(i=0; i<lemp->nsymbol; i++){
+    int j;
+    struct symbol *sp;
+
+    sp = lemp->symbols[i];
+    fprintf(fp, "  %3d: %s", i, sp->name);
+    if( sp->type==NONTERMINAL ){
+      fprintf(fp, ":");
+      if( sp->lambda ){
+        fprintf(fp, " <lambda>");
+      }
+      for(j=0; j<lemp->nterminal; j++){
+        if( sp->firstset && SetFind(sp->firstset, j) ){
+          fprintf(fp, " %s", lemp->symbols[j]->name);
+        }
+      }
+    }
+    fprintf(fp, "\n");
+  }
+  fclose(fp);
+  return;
+}
+
+/* Search for the file "name" which is in the same directory as
+** the exacutable */
+PRIVATE char *pathsearch(char *argv0, char *name, int modemask)
+{
+  const char *pathlist;
+  char *pathbufptr;
+  char *pathbuf;
+  char *path,*cp;
+  char c;
+
+#ifdef __WIN32__
+  cp = strrchr(argv0,'\\');
+#else
+  cp = strrchr(argv0,'/');
+#endif
+  if( cp ){
+    c = *cp;
+    *cp = 0;
+    path = (char *)malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 );
+    if( path ) lemon_sprintf(path,"%s/%s",argv0,name);
+    *cp = c;
+  }else{
+    pathlist = getenv("PATH");
+    if( pathlist==0 ) pathlist = ".:/bin:/usr/bin";
+    pathbuf = (char *) malloc( lemonStrlen(pathlist) + 1 );
+    path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 );
+    if( (pathbuf != 0) && (path!=0) ){
+      pathbufptr = pathbuf;
+      lemon_strcpy(pathbuf, pathlist);
+      while( *pathbuf ){
+        cp = strchr(pathbuf,':');
+        if( cp==0 ) cp = &pathbuf[lemonStrlen(pathbuf)];
+        c = *cp;
+        *cp = 0;
+        lemon_sprintf(path,"%s/%s",pathbuf,name);
+        *cp = c;
+        if( c==0 ) pathbuf[0] = 0;
+        else pathbuf = &cp[1];
+        if( access(path,modemask)==0 ) break;
+      }
+      free(pathbufptr);
+    }
+  }
+  return path;
+}
+
+/* Given an action, compute the integer value for that action
+** which is to be put in the action table of the generated machine.
+** Return negative if no action should be generated.
+*/
+PRIVATE int compute_action(struct lemon *lemp, struct action *ap)
+{
+  int act;
+  switch( ap->type ){
+    case SHIFT:  act = ap->x.stp->statenum;                        break;
+    case SHIFTREDUCE: act = ap->x.rp->iRule + lemp->nstate;        break;
+    case REDUCE: act = ap->x.rp->iRule + lemp->nstate+lemp->nrule; break;
+    case ERROR:  act = lemp->nstate + lemp->nrule*2;               break;
+    case ACCEPT: act = lemp->nstate + lemp->nrule*2 + 1;           break;
+    default:     act = -1; break;
+  }
+  return act;
+}
+
+#define LINESIZE 1000
+/* The next cluster of routines are for reading the template file
+** and writing the results to the generated parser */
+/* The first function transfers data from "in" to "out" until
+** a line is seen which begins with "%%".  The line number is
+** tracked.
+**
+** if name!=0, then any word that begin with "Parse" is changed to
+** begin with *name instead.
+*/
+PRIVATE void tplt_xfer(char *name, FILE *in, FILE *out, int *lineno)
+{
+  int i, iStart;
+  char line[LINESIZE];
+  while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){
+    (*lineno)++;
+    iStart = 0;
+    if( name ){
+      for(i=0; line[i]; i++){
+        if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0
+          && (i==0 || !ISALPHA(line[i-1]))
+        ){
+          if( i>iStart ) fprintf(out,"%.*s",i-iStart,&line[iStart]);
+          fprintf(out,"%s",name);
+          i += 4;
+          iStart = i+1;
+        }
+      }
+    }
+    fprintf(out,"%s",&line[iStart]);
+  }
+}
+
+/* The next function finds the template file and opens it, returning
+** a pointer to the opened file. */
+PRIVATE FILE *tplt_open(struct lemon *lemp)
+{
+  static char templatename[] = "lempar.c";
+  char buf[1000];
+  FILE *in;
+  char *tpltname;
+  char *cp;
+
+  /* first, see if user specified a template filename on the command line. */
+  if (user_templatename != 0) {
+    if( access(user_templatename,004)==-1 ){
+      fprintf(stderr,"Can't find the parser driver template file \"%s\".\n",
+        user_templatename);
+      lemp->errorcnt++;
+      return 0;
+    }
+    in = fopen(user_templatename,"rb");
+    if( in==0 ){
+      fprintf(stderr,"Can't open the template file \"%s\".\n",
+              user_templatename);
+      lemp->errorcnt++;
+      return 0;
+    }
+    return in;
+  }
+
+  cp = strrchr(lemp->filename,'.');
+  if( cp ){
+    lemon_sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename);
+  }else{
+    lemon_sprintf(buf,"%s.lt",lemp->filename);
+  }
+  if( access(buf,004)==0 ){
+    tpltname = buf;
+  }else if( access(templatename,004)==0 ){
+    tpltname = templatename;
+  }else{
+    tpltname = pathsearch(lemp->argv0,templatename,0);
+  }
+  if( tpltname==0 ){
+    fprintf(stderr,"Can't find the parser driver template file \"%s\".\n",
+    templatename);
+    lemp->errorcnt++;
+    return 0;
+  }
+  in = fopen(tpltname,"rb");
+  if( in==0 ){
+    fprintf(stderr,"Can't open the template file \"%s\".\n",templatename);
+    lemp->errorcnt++;
+    return 0;
+  }
+  return in;
+}
+
+/* Print a #line directive line to the output file. */
+PRIVATE void tplt_linedir(FILE *out, int lineno, char *filename)
+{
+  fprintf(out,"#line %d \"",lineno);
+  while( *filename ){
+    if( *filename == '\\' ) putc('\\',out);
+    putc(*filename,out);
+    filename++;
+  }
+  fprintf(out,"\"\n");
+}
+
+/* Print a string to the file and keep the linenumber up to date */
+PRIVATE void tplt_print(FILE *out, struct lemon *lemp, char *str, int *lineno)
+{
+  if( str==0 ) return;
+  while( *str ){
+    putc(*str,out);
+    if( *str=='\n' ) (*lineno)++;
+    str++;
+  }
+  if( str[-1]!='\n' ){
+    putc('\n',out);
+    (*lineno)++;
+  }
+  if (!lemp->nolinenosflag) {
+    (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); 
+  }
+  return;
+}
+
+/*
+** The following routine emits code for the destructor for the
+** symbol sp
+*/
+void emit_destructor_code(
+  FILE *out,
+  struct symbol *sp,
+  struct lemon *lemp,
+  int *lineno
+){
+ char *cp = 0;
+
+ if( sp->type==TERMINAL ){
+   cp = lemp->tokendest;
+   if( cp==0 ) return;
+   fprintf(out,"{\n"); (*lineno)++;
+ }else if( sp->destructor ){
+   cp = sp->destructor;
+   fprintf(out,"{\n"); (*lineno)++;
+   if( !lemp->nolinenosflag ){
+     (*lineno)++;
+     tplt_linedir(out,sp->destLineno,lemp->filename);
+   }
+ }else if( lemp->vardest ){
+   cp = lemp->vardest;
+   if( cp==0 ) return;
+   fprintf(out,"{\n"); (*lineno)++;
+ }else{
+   assert( 0 );  /* Cannot happen */
+ }
+ for(; *cp; cp++){
+   if( *cp=='$' && cp[1]=='$' ){
+     fprintf(out,"(yypminor->yy%d)",sp->dtnum);
+     cp++;
+     continue;
+   }
+   if( *cp=='\n' ) (*lineno)++;
+   fputc(*cp,out);
+ }
+ fprintf(out,"\n"); (*lineno)++;
+ if (!lemp->nolinenosflag) { 
+   (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); 
+ }
+ fprintf(out,"}\n"); (*lineno)++;
+ return;
+}
+
+/*
+** Return TRUE (non-zero) if the given symbol has a destructor.
+*/
+int has_destructor(struct symbol *sp, struct lemon *lemp)
+{
+  int ret;
+  if( sp->type==TERMINAL ){
+    ret = lemp->tokendest!=0;
+  }else{
+    ret = lemp->vardest!=0 || sp->destructor!=0;
+  }
+  return ret;
+}
+
+/*
+** Append text to a dynamically allocated string.  If zText is 0 then
+** reset the string to be empty again.  Always return the complete text
+** of the string (which is overwritten with each call).
+**
+** n bytes of zText are stored.  If n==0 then all of zText up to the first
+** \000 terminator is stored.  zText can contain up to two instances of
+** %d.  The values of p1 and p2 are written into the first and second
+** %d.
+**
+** If n==-1, then the previous character is overwritten.
+*/
+PRIVATE char *append_str(const char *zText, int n, int p1, int p2){
+  static char empty[1] = { 0 };
+  static char *z = 0;
+  static int alloced = 0;
+  static int used = 0;
+  int c;
+  char zInt[40];
+  if( zText==0 ){
+    if( used==0 && z!=0 ) z[0] = 0;
+    used = 0;
+    return z;
+  }
+  if( n<=0 ){
+    if( n<0 ){
+      used += n;
+      assert( used>=0 );
+    }
+    n = lemonStrlen(zText);
+  }
+  if( (int) (n+sizeof(zInt)*2+used) >= alloced ){
+    alloced = n + sizeof(zInt)*2 + used + 200;
+    z = (char *) realloc(z,  alloced);
+  }
+  if( z==0 ) return empty;
+  while( n-- > 0 ){
+    c = *(zText++);
+    if( c=='%' && n>0 && zText[0]=='d' ){
+      lemon_sprintf(zInt, "%d", p1);
+      p1 = p2;
+      lemon_strcpy(&z[used], zInt);
+      used += lemonStrlen(&z[used]);
+      zText++;
+      n--;
+    }else{
+      z[used++] = (char)c;
+    }
+  }
+  z[used] = 0;
+  return z;
+}
+
+/*
+** Write and transform the rp->code string so that symbols are expanded.
+** Populate the rp->codePrefix and rp->codeSuffix strings, as appropriate.
+**
+** Return 1 if the expanded code requires that "yylhsminor" local variable
+** to be defined.
+*/
+PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
+  char *cp, *xp;
+  int i;
+  int rc = 0;            /* True if yylhsminor is used */
+  int dontUseRhs0 = 0;   /* If true, use of left-most RHS label is illegal */
+  const char *zSkip = 0; /* The zOvwrt comment within rp->code, or NULL */
+  char lhsused = 0;      /* True if the LHS element has been used */
+  char lhsdirect;        /* True if LHS writes directly into stack */
+  char used[MAXRHS];     /* True for each RHS element which is used */
+  char zLhs[50];         /* Convert the LHS symbol into this string */
+  char zOvwrt[900];      /* Comment that to allow LHS to overwrite RHS */
+
+  for(i=0; i<rp->nrhs; i++) used[i] = 0;
+  lhsused = 0;
+
+  if( rp->code==0 ){
+    static char newlinestr[2] = { '\n', '\0' };
+    rp->code = newlinestr;
+    rp->line = rp->ruleline;
+    rp->noCode = 1;
+  }else{
+    rp->noCode = 0;
+  }
+
+
+  if( rp->nrhs==0 ){
+    /* If there are no RHS symbols, then writing directly to the LHS is ok */
+    lhsdirect = 1;
+  }else if( rp->rhsalias[0]==0 ){
+    /* The left-most RHS symbol has no value.  LHS direct is ok.  But
+    ** we have to call the distructor on the RHS symbol first. */
+    lhsdirect = 1;
+    if( has_destructor(rp->rhs[0],lemp) ){
+      append_str(0,0,0,0);
+      append_str("  yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0,
+                 rp->rhs[0]->index,1-rp->nrhs);
+      rp->codePrefix = Strsafe(append_str(0,0,0,0));
+      rp->noCode = 0;
+    }
+  }else if( rp->lhsalias==0 ){
+    /* There is no LHS value symbol. */
+    lhsdirect = 1;
+  }else if( strcmp(rp->lhsalias,rp->rhsalias[0])==0 ){
+    /* The LHS symbol and the left-most RHS symbol are the same, so 
+    ** direct writing is allowed */
+    lhsdirect = 1;
+    lhsused = 1;
+    used[0] = 1;
+    if( rp->lhs->dtnum!=rp->rhs[0]->dtnum ){
+      ErrorMsg(lemp->filename,rp->ruleline,
+        "%s(%s) and %s(%s) share the same label but have "
+        "different datatypes.",
+        rp->lhs->name, rp->lhsalias, rp->rhs[0]->name, rp->rhsalias[0]);
+      lemp->errorcnt++;
+    }    
+  }else{
+    lemon_sprintf(zOvwrt, "/*%s-overwrites-%s*/",
+                  rp->lhsalias, rp->rhsalias[0]);
+    zSkip = strstr(rp->code, zOvwrt);
+    if( zSkip!=0 ){
+      /* The code contains a special comment that indicates that it is safe
+      ** for the LHS label to overwrite left-most RHS label. */
+      lhsdirect = 1;
+    }else{
+      lhsdirect = 0;
+    }
+  }
+  if( lhsdirect ){
+    sprintf(zLhs, "yymsp[%d].minor.yy%d",1-rp->nrhs,rp->lhs->dtnum);
+  }else{
+    rc = 1;
+    sprintf(zLhs, "yylhsminor.yy%d",rp->lhs->dtnum);
+  }
+
+  append_str(0,0,0,0);
+
+  /* This const cast is wrong but harmless, if we're careful. */
+  for(cp=(char *)rp->code; *cp; cp++){
+    if( cp==zSkip ){
+      append_str(zOvwrt,0,0,0);
+      cp += lemonStrlen(zOvwrt)-1;
+      dontUseRhs0 = 1;
+      continue;
+    }
+    if( ISALPHA(*cp) && (cp==rp->code || (!ISALNUM(cp[-1]) && cp[-1]!='_')) ){
+      char saved;
+      for(xp= &cp[1]; ISALNUM(*xp) || *xp=='_'; xp++);
+      saved = *xp;
+      *xp = 0;
+      if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){
+        append_str(zLhs,0,0,0);
+        cp = xp;
+        lhsused = 1;
+      }else{
+        for(i=0; i<rp->nrhs; i++){
+          if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){
+            if( i==0 && dontUseRhs0 ){
+              ErrorMsg(lemp->filename,rp->ruleline,
+                 "Label %s used after '%s'.",
+                 rp->rhsalias[0], zOvwrt);
+              lemp->errorcnt++;
+            }else if( cp!=rp->code && cp[-1]=='@' ){
+              /* If the argument is of the form @X then substituted
+              ** the token number of X, not the value of X */
+              append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0);
+            }else{
+              struct symbol *sp = rp->rhs[i];
+              int dtnum;
+              if( sp->type==MULTITERMINAL ){
+                dtnum = sp->subsym[0]->dtnum;
+              }else{
+                dtnum = sp->dtnum;
+              }
+              append_str("yymsp[%d].minor.yy%d",0,i-rp->nrhs+1, dtnum);
+            }
+            cp = xp;
+            used[i] = 1;
+            break;
+          }
+        }
+      }
+      *xp = saved;
+    }
+    append_str(cp, 1, 0, 0);
+  } /* End loop */
+
+  /* Main code generation completed */
+  cp = append_str(0,0,0,0);
+  if( cp && cp[0] ) rp->code = Strsafe(cp);
+  append_str(0,0,0,0);
+
+  /* Check to make sure the LHS has been used */
+  if( rp->lhsalias && !lhsused ){
+    ErrorMsg(lemp->filename,rp->ruleline,
+      "Label \"%s\" for \"%s(%s)\" is never used.",
+        rp->lhsalias,rp->lhs->name,rp->lhsalias);
+    lemp->errorcnt++;
+  }
+
+  /* Generate destructor code for RHS minor values which are not referenced.
+  ** Generate error messages for unused labels and duplicate labels.
+  */
+  for(i=0; i<rp->nrhs; i++){
+    if( rp->rhsalias[i] ){
+      if( i>0 ){
+        int j;
+        if( rp->lhsalias && strcmp(rp->lhsalias,rp->rhsalias[i])==0 ){
+          ErrorMsg(lemp->filename,rp->ruleline,
+            "%s(%s) has the same label as the LHS but is not the left-most "
+            "symbol on the RHS.",
+            rp->rhs[i]->name, rp->rhsalias);
+          lemp->errorcnt++;
+        }
+        for(j=0; j<i; j++){
+          if( rp->rhsalias[j] && strcmp(rp->rhsalias[j],rp->rhsalias[i])==0 ){
+            ErrorMsg(lemp->filename,rp->ruleline,
+              "Label %s used for multiple symbols on the RHS of a rule.",
+              rp->rhsalias[i]);
+            lemp->errorcnt++;
+            break;
+          }
+        }
+      }
+      if( !used[i] ){
+        ErrorMsg(lemp->filename,rp->ruleline,
+          "Label %s for \"%s(%s)\" is never used.",
+          rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]);
+        lemp->errorcnt++;
+      }
+    }else if( i>0 && has_destructor(rp->rhs[i],lemp) ){
+      append_str("  yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0,
+         rp->rhs[i]->index,i-rp->nrhs+1);
+    }
+  }
+
+  /* If unable to write LHS values directly into the stack, write the
+  ** saved LHS value now. */
+  if( lhsdirect==0 ){
+    append_str("  yymsp[%d].minor.yy%d = ", 0, 1-rp->nrhs, rp->lhs->dtnum);
+    append_str(zLhs, 0, 0, 0);
+    append_str(";\n", 0, 0, 0);
+  }
+
+  /* Suffix code generation complete */
+  cp = append_str(0,0,0,0);
+  if( cp && cp[0] ){
+    rp->codeSuffix = Strsafe(cp);
+    rp->noCode = 0;
+  }
+
+  return rc;
+}
+
+/* 
+** Generate code which executes when the rule "rp" is reduced.  Write
+** the code to "out".  Make sure lineno stays up-to-date.
+*/
+PRIVATE void emit_code(
+  FILE *out,
+  struct rule *rp,
+  struct lemon *lemp,
+  int *lineno
+){
+ const char *cp;
+
+ /* Setup code prior to the #line directive */
+ if( rp->codePrefix && rp->codePrefix[0] ){
+   fprintf(out, "{%s", rp->codePrefix);
+   for(cp=rp->codePrefix; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; }
+ }
+
+ /* Generate code to do the reduce action */
+ if( rp->code ){
+   if( !lemp->nolinenosflag ){
+     (*lineno)++;
+     tplt_linedir(out,rp->line,lemp->filename);
+   }
+   fprintf(out,"{%s",rp->code);
+   for(cp=rp->code; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; }
+   fprintf(out,"}\n"); (*lineno)++;
+   if( !lemp->nolinenosflag ){
+     (*lineno)++;
+     tplt_linedir(out,*lineno,lemp->outname);
+   }
+ }
+
+ /* Generate breakdown code that occurs after the #line directive */
+ if( rp->codeSuffix && rp->codeSuffix[0] ){
+   fprintf(out, "%s", rp->codeSuffix);
+   for(cp=rp->codeSuffix; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; }
+ }
+
+ if( rp->codePrefix ){
+   fprintf(out, "}\n"); (*lineno)++;
+ }
+
+ return;
+}
+
+/*
+** Print the definition of the union used for the parser's data stack.
+** This union contains fields for every possible data type for tokens
+** and nonterminals.  In the process of computing and printing this
+** union, also set the ".dtnum" field of every terminal and nonterminal
+** symbol.
+*/
+void print_stack_union(
+  FILE *out,                  /* The output stream */
+  struct lemon *lemp,         /* The main info structure for this parser */
+  int *plineno,               /* Pointer to the line number */
+  int mhflag                  /* True if generating makeheaders output */
+){
+  int lineno = *plineno;    /* The line number of the output */
+  char **types;             /* A hash table of datatypes */
+  int arraysize;            /* Size of the "types" array */
+  int maxdtlength;          /* Maximum length of any ".datatype" field. */
+  char *stddt;              /* Standardized name for a datatype */
+  int i,j;                  /* Loop counters */
+  unsigned hash;            /* For hashing the name of a type */
+  const char *name;         /* Name of the parser */
+
+  /* Allocate and initialize types[] and allocate stddt[] */
+  arraysize = lemp->nsymbol * 2;
+  types = (char**)calloc( arraysize, sizeof(char*) );
+  if( types==0 ){
+    fprintf(stderr,"Out of memory.\n");
+    exit(1);
+  }
+  for(i=0; i<arraysize; i++) types[i] = 0;
+  maxdtlength = 0;
+  if( lemp->vartype ){
+    maxdtlength = lemonStrlen(lemp->vartype);
+  }
+  for(i=0; i<lemp->nsymbol; i++){
+    int len;
+    struct symbol *sp = lemp->symbols[i];
+    if( sp->datatype==0 ) continue;
+    len = lemonStrlen(sp->datatype);
+    if( len>maxdtlength ) maxdtlength = len;
+  }
+  stddt = (char*)malloc( maxdtlength*2 + 1 );
+  if( stddt==0 ){
+    fprintf(stderr,"Out of memory.\n");
+    exit(1);
+  }
+
+  /* Build a hash table of datatypes. The ".dtnum" field of each symbol
+  ** is filled in with the hash index plus 1.  A ".dtnum" value of 0 is
+  ** used for terminal symbols.  If there is no %default_type defined then
+  ** 0 is also used as the .dtnum value for nonterminals which do not specify
+  ** a datatype using the %type directive.
+  */
+  for(i=0; i<lemp->nsymbol; i++){
+    struct symbol *sp = lemp->symbols[i];
+    char *cp;
+    if( sp==lemp->errsym ){
+      sp->dtnum = arraysize+1;
+      continue;
+    }
+    if( sp->type!=NONTERMINAL || (sp->datatype==0 && lemp->vartype==0) ){
+      sp->dtnum = 0;
+      continue;
+    }
+    cp = sp->datatype;
+    if( cp==0 ) cp = lemp->vartype;
+    j = 0;
+    while( ISSPACE(*cp) ) cp++;
+    while( *cp ) stddt[j++] = *cp++;
+    while( j>0 && ISSPACE(stddt[j-1]) ) j--;
+    stddt[j] = 0;
+    if( lemp->tokentype && strcmp(stddt, lemp->tokentype)==0 ){
+      sp->dtnum = 0;
+      continue;
+    }
+    hash = 0;
+    for(j=0; stddt[j]; j++){
+      hash = hash*53 + stddt[j];
+    }
+    hash = (hash & 0x7fffffff)%arraysize;
+    while( types[hash] ){
+      if( strcmp(types[hash],stddt)==0 ){
+        sp->dtnum = hash + 1;
+        break;
+      }
+      hash++;
+      if( hash>=(unsigned)arraysize ) hash = 0;
+    }
+    if( types[hash]==0 ){
+      sp->dtnum = hash + 1;
+      types[hash] = (char*)malloc( lemonStrlen(stddt)+1 );
+      if( types[hash]==0 ){
+        fprintf(stderr,"Out of memory.\n");
+        exit(1);
+      }
+      lemon_strcpy(types[hash],stddt);
+    }
+  }
+
+  /* Print out the definition of YYTOKENTYPE and YYMINORTYPE */
+  name = lemp->name ? lemp->name : "Parse";
+  lineno = *plineno;
+  if( mhflag ){ fprintf(out,"#if INTERFACE\n"); lineno++; }
+  fprintf(out,"#define %sTOKENTYPE %s\n",name,
+    lemp->tokentype?lemp->tokentype:"void*");  lineno++;
+  if( mhflag ){ fprintf(out,"#endif\n"); lineno++; }
+  fprintf(out,"typedef union {\n"); lineno++;
+  fprintf(out,"  int yyinit;\n"); lineno++;
+  fprintf(out,"  %sTOKENTYPE yy0;\n",name); lineno++;
+  for(i=0; i<arraysize; i++){
+    if( types[i]==0 ) continue;
+    fprintf(out,"  %s yy%d;\n",types[i],i+1); lineno++;
+    free(types[i]);
+  }
+  if( lemp->errsym->useCnt ){
+    fprintf(out,"  int yy%d;\n",lemp->errsym->dtnum); lineno++;
+  }
+  free(stddt);
+  free(types);
+  fprintf(out,"} YYMINORTYPE;\n"); lineno++;
+  *plineno = lineno;
+}
+
+/*
+** Return the name of a C datatype able to represent values between
+** lwr and upr, inclusive.  If pnByte!=NULL then also write the sizeof
+** for that type (1, 2, or 4) into *pnByte.
+*/
+static const char *minimum_size_type(int lwr, int upr, int *pnByte){
+  const char *zType = "int";
+  int nByte = 4;
+  if( lwr>=0 ){
+    if( upr<=255 ){
+      zType = "unsigned char";
+      nByte = 1;
+    }else if( upr<65535 ){
+      zType = "unsigned short int";
+      nByte = 2;
+    }else{
+      zType = "unsigned int";
+      nByte = 4;
+    }
+  }else if( lwr>=-127 && upr<=127 ){
+    zType = "signed char";
+    nByte = 1;
+  }else if( lwr>=-32767 && upr<32767 ){
+    zType = "short";
+    nByte = 2;
+  }
+  if( pnByte ) *pnByte = nByte;
+  return zType;
+}
+
+/*
+** Each state contains a set of token transaction and a set of
+** nonterminal transactions.  Each of these sets makes an instance
+** of the following structure.  An array of these structures is used
+** to order the creation of entries in the yy_action[] table.
+*/
+struct axset {
+  struct state *stp;   /* A pointer to a state */
+  int isTkn;           /* True to use tokens.  False for non-terminals */
+  int nAction;         /* Number of actions */
+  int iOrder;          /* Original order of action sets */
+};
+
+/*
+** Compare to axset structures for sorting purposes
+*/
+static int axset_compare(const void *a, const void *b){
+  struct axset *p1 = (struct axset*)a;
+  struct axset *p2 = (struct axset*)b;
+  int c;
+  c = p2->nAction - p1->nAction;
+  if( c==0 ){
+    c = p1->iOrder - p2->iOrder;
+  }
+  assert( c!=0 || p1==p2 );
+  return c;
+}
+
+/*
+** Write text on "out" that describes the rule "rp".
+*/
+static void writeRuleText(FILE *out, struct rule *rp){
+  int j;
+  fprintf(out,"%s ::=", rp->lhs->name);
+  for(j=0; j<rp->nrhs; j++){
+    struct symbol *sp = rp->rhs[j];
+    if( sp->type!=MULTITERMINAL ){
+      fprintf(out," %s", sp->name);
+    }else{
+      int k;
+      fprintf(out," %s", sp->subsym[0]->name);
+      for(k=1; k<sp->nsubsym; k++){
+        fprintf(out,"|%s",sp->subsym[k]->name);
+      }
+    }
+  }
+}
+
+
+/* Generate C source code for the parser */
+void ReportTable(
+  struct lemon *lemp,
+  int mhflag     /* Output in makeheaders format if true */
+){
+  FILE *out, *in;
+  char line[LINESIZE];
+  int  lineno;
+  struct state *stp;
+  struct action *ap;
+  struct rule *rp;
+  struct acttab *pActtab;
+  int i, j, n, sz;
+  int szActionType;     /* sizeof(YYACTIONTYPE) */
+  int szCodeType;       /* sizeof(YYCODETYPE)   */
+  const char *name;
+  int mnTknOfst, mxTknOfst;
+  int mnNtOfst, mxNtOfst;
+  struct axset *ax;
+
+  in = tplt_open(lemp);
+  if( in==0 ) return;
+  out = file_open(lemp,".c","wb");
+  if( out==0 ){
+    fclose(in);
+    return;
+  }
+  lineno = 1;
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate the include code, if any */
+  tplt_print(out,lemp,lemp->include,&lineno);
+  if( mhflag ){
+    char *incName = file_makename(lemp, ".h");
+    fprintf(out,"#include \"%s\"\n", incName); lineno++;
+    free(incName);
+  }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate #defines for all tokens */
+  if( mhflag ){
+    const char *prefix;
+    fprintf(out,"#if INTERFACE\n"); lineno++;
+    if( lemp->tokenprefix ) prefix = lemp->tokenprefix;
+    else                    prefix = "";
+    for(i=1; i<lemp->nterminal; i++){
+      fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
+      lineno++;
+    }
+    fprintf(out,"#endif\n"); lineno++;
+  }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate the defines */
+  fprintf(out,"#define YYCODETYPE %s\n",
+    minimum_size_type(0, lemp->nsymbol+1, &szCodeType)); lineno++;
+  fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1);  lineno++;
+  fprintf(out,"#define YYACTIONTYPE %s\n",
+    minimum_size_type(0,lemp->nstate+lemp->nrule*2+5,&szActionType)); lineno++;
+  if( lemp->wildcard ){
+    fprintf(out,"#define YYWILDCARD %d\n",
+       lemp->wildcard->index); lineno++;
+  }
+  print_stack_union(out,lemp,&lineno,mhflag);
+  fprintf(out, "#ifndef YYSTACKDEPTH\n"); lineno++;
+  if( lemp->stacksize ){
+    fprintf(out,"#define YYSTACKDEPTH %s\n",lemp->stacksize);  lineno++;
+  }else{
+    fprintf(out,"#define YYSTACKDEPTH 100\n");  lineno++;
+  }
+  fprintf(out, "#endif\n"); lineno++;
+  if( mhflag ){
+    fprintf(out,"#if INTERFACE\n"); lineno++;
+  }
+  name = lemp->name ? lemp->name : "Parse";
+  if( lemp->arg && lemp->arg[0] ){
+    i = lemonStrlen(lemp->arg);
+    while( i>=1 && ISSPACE(lemp->arg[i-1]) ) i--;
+    while( i>=1 && (ISALNUM(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--;
+    fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg);  lineno++;
+    fprintf(out,"#define %sARG_PDECL ,%s\n",name,lemp->arg);  lineno++;
+    fprintf(out,"#define %sARG_FETCH %s = yypParser->%s\n",
+                 name,lemp->arg,&lemp->arg[i]);  lineno++;
+    fprintf(out,"#define %sARG_STORE yypParser->%s = %s\n",
+                 name,&lemp->arg[i],&lemp->arg[i]);  lineno++;
+  }else{
+    fprintf(out,"#define %sARG_SDECL\n",name);  lineno++;
+    fprintf(out,"#define %sARG_PDECL\n",name);  lineno++;
+    fprintf(out,"#define %sARG_FETCH\n",name); lineno++;
+    fprintf(out,"#define %sARG_STORE\n",name); lineno++;
+  }
+  if( mhflag ){
+    fprintf(out,"#endif\n"); lineno++;
+  }
+  if( lemp->errsym->useCnt ){
+    fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++;
+    fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++;
+  }
+  if( lemp->has_fallback ){
+    fprintf(out,"#define YYFALLBACK 1\n");  lineno++;
+  }
+
+  /* Compute the action table, but do not output it yet.  The action
+  ** table must be computed before generating the YYNSTATE macro because
+  ** we need to know how many states can be eliminated.
+  */
+  ax = (struct axset *) calloc(lemp->nxstate*2, sizeof(ax[0]));
+  if( ax==0 ){
+    fprintf(stderr,"malloc failed\n");
+    exit(1);
+  }
+  for(i=0; i<lemp->nxstate; i++){
+    stp = lemp->sorted[i];
+    ax[i*2].stp = stp;
+    ax[i*2].isTkn = 1;
+    ax[i*2].nAction = stp->nTknAct;
+    ax[i*2+1].stp = stp;
+    ax[i*2+1].isTkn = 0;
+    ax[i*2+1].nAction = stp->nNtAct;
+  }
+  mxTknOfst = mnTknOfst = 0;
+  mxNtOfst = mnNtOfst = 0;
+  /* In an effort to minimize the action table size, use the heuristic
+  ** of placing the largest action sets first */
+  for(i=0; i<lemp->nxstate*2; i++) ax[i].iOrder = i;
+  qsort(ax, lemp->nxstate*2, sizeof(ax[0]), axset_compare);
+  pActtab = acttab_alloc();
+  for(i=0; i<lemp->nxstate*2 && ax[i].nAction>0; i++){
+    stp = ax[i].stp;
+    if( ax[i].isTkn ){
+      for(ap=stp->ap; ap; ap=ap->next){
+        int action;
+        if( ap->sp->index>=lemp->nterminal ) continue;
+        action = compute_action(lemp, ap);
+        if( action<0 ) continue;
+        acttab_action(pActtab, ap->sp->index, action);
+      }
+      stp->iTknOfst = acttab_insert(pActtab);
+      if( stp->iTknOfst<mnTknOfst ) mnTknOfst = stp->iTknOfst;
+      if( stp->iTknOfst>mxTknOfst ) mxTknOfst = stp->iTknOfst;
+    }else{
+      for(ap=stp->ap; ap; ap=ap->next){
+        int action;
+        if( ap->sp->index<lemp->nterminal ) continue;
+        if( ap->sp->index==lemp->nsymbol ) continue;
+        action = compute_action(lemp, ap);
+        if( action<0 ) continue;
+        acttab_action(pActtab, ap->sp->index, action);
+      }
+      stp->iNtOfst = acttab_insert(pActtab);
+      if( stp->iNtOfst<mnNtOfst ) mnNtOfst = stp->iNtOfst;
+      if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst;
+    }
+#if 0  /* Uncomment for a trace of how the yy_action[] table fills out */
+    { int jj, nn;
+      for(jj=nn=0; jj<pActtab->nAction; jj++){
+        if( pActtab->aAction[jj].action<0 ) nn++;
+      }
+      printf("%4d: State %3d %s n: %2d size: %5d freespace: %d\n",
+             i, stp->statenum, ax[i].isTkn ? "Token" : "Var  ",
+             ax[i].nAction, pActtab->nAction, nn);
+    }
+#endif
+  }
+  free(ax);
+
+  /* Mark rules that are actually used for reduce actions after all
+  ** optimizations have been applied
+  */
+  for(rp=lemp->rule; rp; rp=rp->next) rp->doesReduce = LEMON_FALSE;
+  for(i=0; i<lemp->nxstate; i++){
+    struct action *ap;
+    for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){
+      if( ap->type==REDUCE || ap->type==SHIFTREDUCE ){
+        ap->x.rp->doesReduce = i;
+      }
+    }
+  }
+
+  /* Finish rendering the constants now that the action table has
+  ** been computed */
+  fprintf(out,"#define YYNSTATE             %d\n",lemp->nxstate);  lineno++;
+  fprintf(out,"#define YYNRULE              %d\n",lemp->nrule);  lineno++;
+  fprintf(out,"#define YY_MAX_SHIFT         %d\n",lemp->nxstate-1); lineno++;
+  fprintf(out,"#define YY_MIN_SHIFTREDUCE   %d\n",lemp->nstate); lineno++;
+  i = lemp->nstate + lemp->nrule;
+  fprintf(out,"#define YY_MAX_SHIFTREDUCE   %d\n", i-1); lineno++;
+  fprintf(out,"#define YY_MIN_REDUCE        %d\n", i); lineno++;
+  i = lemp->nstate + lemp->nrule*2;
+  fprintf(out,"#define YY_MAX_REDUCE        %d\n", i-1); lineno++;
+  fprintf(out,"#define YY_ERROR_ACTION      %d\n", i); lineno++;
+  fprintf(out,"#define YY_ACCEPT_ACTION     %d\n", i+1); lineno++;
+  fprintf(out,"#define YY_NO_ACTION         %d\n", i+2); lineno++;
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Now output the action table and its associates:
+  **
+  **  yy_action[]        A single table containing all actions.
+  **  yy_lookahead[]     A table containing the lookahead for each entry in
+  **                     yy_action.  Used to detect hash collisions.
+  **  yy_shift_ofst[]    For each state, the offset into yy_action for
+  **                     shifting terminals.
+  **  yy_reduce_ofst[]   For each state, the offset into yy_action for
+  **                     shifting non-terminals after a reduce.
+  **  yy_default[]       Default action for each state.
+  */
+
+  /* Output the yy_action table */
+  lemp->nactiontab = n = acttab_size(pActtab);
+  lemp->tablesize += n*szActionType;
+  fprintf(out,"#define YY_ACTTAB_COUNT (%d)\n", n); lineno++;
+  fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++;
+  for(i=j=0; i<n; i++){
+    int action = acttab_yyaction(pActtab, i);
+    if( action<0 ) action = lemp->nstate + lemp->nrule + 2;
+    if( j==0 ) fprintf(out," /* %5d */ ", i);
+    fprintf(out, " %4d,", action);
+    if( j==9 || i==n-1 ){
+      fprintf(out, "\n"); lineno++;
+      j = 0;
+    }else{
+      j++;
+    }
+  }
+  fprintf(out, "};\n"); lineno++;
+
+  /* Output the yy_lookahead table */
+  lemp->tablesize += n*szCodeType;
+  fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++;
+  for(i=j=0; i<n; i++){
+    int la = acttab_yylookahead(pActtab, i);
+    if( la<0 ) la = lemp->nsymbol;
+    if( j==0 ) fprintf(out," /* %5d */ ", i);
+    fprintf(out, " %4d,", la);
+    if( j==9 || i==n-1 ){
+      fprintf(out, "\n"); lineno++;
+      j = 0;
+    }else{
+      j++;
+    }
+  }
+  fprintf(out, "};\n"); lineno++;
+
+  /* Output the yy_shift_ofst[] table */
+  n = lemp->nxstate;
+  while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--;
+  fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", lemp->nactiontab); lineno++;
+  fprintf(out, "#define YY_SHIFT_COUNT    (%d)\n", n-1); lineno++;
+  fprintf(out, "#define YY_SHIFT_MIN      (%d)\n", mnTknOfst); lineno++;
+  fprintf(out, "#define YY_SHIFT_MAX      (%d)\n", mxTknOfst); lineno++;
+  fprintf(out, "static const %s yy_shift_ofst[] = {\n", 
+       minimum_size_type(mnTknOfst, lemp->nterminal+lemp->nactiontab, &sz));
+       lineno++;
+  lemp->tablesize += n*sz;
+  for(i=j=0; i<n; i++){
+    int ofst;
+    stp = lemp->sorted[i];
+    ofst = stp->iTknOfst;
+    if( ofst==NO_OFFSET ) ofst = lemp->nactiontab;
+    if( j==0 ) fprintf(out," /* %5d */ ", i);
+    fprintf(out, " %4d,", ofst);
+    if( j==9 || i==n-1 ){
+      fprintf(out, "\n"); lineno++;
+      j = 0;
+    }else{
+      j++;
+    }
+  }
+  fprintf(out, "};\n"); lineno++;
+
+  /* Output the yy_reduce_ofst[] table */
+  fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
+  n = lemp->nxstate;
+  while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--;
+  fprintf(out, "#define YY_REDUCE_COUNT (%d)\n", n-1); lineno++;
+  fprintf(out, "#define YY_REDUCE_MIN   (%d)\n", mnNtOfst); lineno++;
+  fprintf(out, "#define YY_REDUCE_MAX   (%d)\n", mxNtOfst); lineno++;
+  fprintf(out, "static const %s yy_reduce_ofst[] = {\n", 
+          minimum_size_type(mnNtOfst-1, mxNtOfst, &sz)); lineno++;
+  lemp->tablesize += n*sz;
+  for(i=j=0; i<n; i++){
+    int ofst;
+    stp = lemp->sorted[i];
+    ofst = stp->iNtOfst;
+    if( ofst==NO_OFFSET ) ofst = mnNtOfst - 1;
+    if( j==0 ) fprintf(out," /* %5d */ ", i);
+    fprintf(out, " %4d,", ofst);
+    if( j==9 || i==n-1 ){
+      fprintf(out, "\n"); lineno++;
+      j = 0;
+    }else{
+      j++;
+    }
+  }
+  fprintf(out, "};\n"); lineno++;
+
+  /* Output the default action table */
+  fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++;
+  n = lemp->nxstate;
+  lemp->tablesize += n*szActionType;
+  for(i=j=0; i<n; i++){
+    stp = lemp->sorted[i];
+    if( j==0 ) fprintf(out," /* %5d */ ", i);
+    fprintf(out, " %4d,", stp->iDfltReduce+lemp->nstate+lemp->nrule);
+    if( j==9 || i==n-1 ){
+      fprintf(out, "\n"); lineno++;
+      j = 0;
+    }else{
+      j++;
+    }
+  }
+  fprintf(out, "};\n"); lineno++;
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate the table of fallback tokens.
+  */
+  if( lemp->has_fallback ){
+    int mx = lemp->nterminal - 1;
+    while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; }
+    lemp->tablesize += (mx+1)*szCodeType;
+    for(i=0; i<=mx; i++){
+      struct symbol *p = lemp->symbols[i];
+      if( p->fallback==0 ){
+        fprintf(out, "    0,  /* %10s => nothing */\n", p->name);
+      }else{
+        fprintf(out, "  %3d,  /* %10s => %s */\n", p->fallback->index,
+          p->name, p->fallback->name);
+      }
+      lineno++;
+    }
+  }
+  tplt_xfer(lemp->name, in, out, &lineno);
+
+  /* Generate a table containing the symbolic name of every symbol
+  */
+  for(i=0; i<lemp->nsymbol; i++){
+    lemon_sprintf(line,"\"%s\",",lemp->symbols[i]->name);
+    fprintf(out,"  %-15s",line);
+    if( (i&3)==3 ){ fprintf(out,"\n"); lineno++; }
+  }
+  if( (i&3)!=0 ){ fprintf(out,"\n"); lineno++; }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate a table containing a text string that describes every
+  ** rule in the rule set of the grammar.  This information is used
+  ** when tracing REDUCE actions.
+  */
+  for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
+    assert( rp->iRule==i );
+    fprintf(out," /* %3d */ \"", i);
+    writeRuleText(out, rp);
+    fprintf(out,"\",\n"); lineno++;
+  }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate code which executes every time a symbol is popped from
+  ** the stack while processing errors or while destroying the parser. 
+  ** (In other words, generate the %destructor actions)
+  */
+  if( lemp->tokendest ){
+    int once = 1;
+    for(i=0; i<lemp->nsymbol; i++){
+      struct symbol *sp = lemp->symbols[i];
+      if( sp==0 || sp->type!=TERMINAL ) continue;
+      if( once ){
+        fprintf(out, "      /* TERMINAL Destructor */\n"); lineno++;
+        once = 0;
+      }
+      fprintf(out,"    case %d: /* %s */\n", sp->index, sp->name); lineno++;
+    }
+    for(i=0; i<lemp->nsymbol && lemp->symbols[i]->type!=TERMINAL; i++);
+    if( i<lemp->nsymbol ){
+      emit_destructor_code(out,lemp->symbols[i],lemp,&lineno);
+      fprintf(out,"      break;\n"); lineno++;
+    }
+  }
+  if( lemp->vardest ){
+    struct symbol *dflt_sp = 0;
+    int once = 1;
+    for(i=0; i<lemp->nsymbol; i++){
+      struct symbol *sp = lemp->symbols[i];
+      if( sp==0 || sp->type==TERMINAL ||
+          sp->index<=0 || sp->destructor!=0 ) continue;
+      if( once ){
+        fprintf(out, "      /* Default NON-TERMINAL Destructor */\n"); lineno++;
+        once = 0;
+      }
+      fprintf(out,"    case %d: /* %s */\n", sp->index, sp->name); lineno++;
+      dflt_sp = sp;
+    }
+    if( dflt_sp!=0 ){
+      emit_destructor_code(out,dflt_sp,lemp,&lineno);
+    }
+    fprintf(out,"      break;\n"); lineno++;
+  }
+  for(i=0; i<lemp->nsymbol; i++){
+    struct symbol *sp = lemp->symbols[i];
+    if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue;
+    if( sp->destLineno<0 ) continue;  /* Already emitted */
+    fprintf(out,"    case %d: /* %s */\n", sp->index, sp->name); lineno++;
+
+    /* Combine duplicate destructors into a single case */
+    for(j=i+1; j<lemp->nsymbol; j++){
+      struct symbol *sp2 = lemp->symbols[j];
+      if( sp2 && sp2->type!=TERMINAL && sp2->destructor
+          && sp2->dtnum==sp->dtnum
+          && strcmp(sp->destructor,sp2->destructor)==0 ){
+         fprintf(out,"    case %d: /* %s */\n",
+                 sp2->index, sp2->name); lineno++;
+         sp2->destLineno = -1;  /* Avoid emitting this destructor again */
+      }
+    }
+
+    emit_destructor_code(out,lemp->symbols[i],lemp,&lineno);
+    fprintf(out,"      break;\n"); lineno++;
+  }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate code which executes whenever the parser stack overflows */
+  tplt_print(out,lemp,lemp->overflow,&lineno);
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate the table of rule information 
+  **
+  ** Note: This code depends on the fact that rules are number
+  ** sequentually beginning with 0.
+  */
+  for(rp=lemp->rule; rp; rp=rp->next){
+    fprintf(out,"  { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++;
+  }
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate code which execution during each REDUCE action */
+  i = 0;
+  for(rp=lemp->rule; rp; rp=rp->next){
+    i += translate_code(lemp, rp);
+  }
+  if( i ){
+    fprintf(out,"        YYMINORTYPE yylhsminor;\n"); lineno++;
+  }
+  /* First output rules other than the default: rule */
+  for(rp=lemp->rule; rp; rp=rp->next){
+    struct rule *rp2;               /* Other rules with the same action */
+    if( rp->codeEmitted ) continue;
+    if( rp->noCode ){
+      /* No C code actions, so this will be part of the "default:" rule */
+      continue;
+    }
+    fprintf(out,"      case %d: /* ", rp->iRule);
+    writeRuleText(out, rp);
+    fprintf(out, " */\n"); lineno++;
+    for(rp2=rp->next; rp2; rp2=rp2->next){
+      if( rp2->code==rp->code && rp2->codePrefix==rp->codePrefix
+             && rp2->codeSuffix==rp->codeSuffix ){
+        fprintf(out,"      case %d: /* ", rp2->iRule);
+        writeRuleText(out, rp2);
+        fprintf(out," */ yytestcase(yyruleno==%d);\n", rp2->iRule); lineno++;
+        rp2->codeEmitted = 1;
+      }
+    }
+    emit_code(out,rp,lemp,&lineno);
+    fprintf(out,"        break;\n"); lineno++;
+    rp->codeEmitted = 1;
+  }
+  /* Finally, output the default: rule.  We choose as the default: all
+  ** empty actions. */
+  fprintf(out,"      default:\n"); lineno++;
+  for(rp=lemp->rule; rp; rp=rp->next){
+    if( rp->codeEmitted ) continue;
+    assert( rp->noCode );
+    fprintf(out,"      /* (%d) ", rp->iRule);
+    writeRuleText(out, rp);
+    if( rp->doesReduce ){
+      fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->iRule); lineno++;
+    }else{
+      fprintf(out, " (OPTIMIZED OUT) */ assert(yyruleno!=%d);\n",
+              rp->iRule); lineno++;
+    }
+  }
+  fprintf(out,"        break;\n"); lineno++;
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate code which executes if a parse fails */
+  tplt_print(out,lemp,lemp->failure,&lineno);
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate code which executes when a syntax error occurs */
+  tplt_print(out,lemp,lemp->error,&lineno);
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Generate code which executes when the parser accepts its input */
+  tplt_print(out,lemp,lemp->accept,&lineno);
+  tplt_xfer(lemp->name,in,out,&lineno);
+
+  /* Append any addition code the user desires */
+  tplt_print(out,lemp,lemp->extracode,&lineno);
+
+  fclose(in);
+  fclose(out);
+  return;
+}
+
+/* Generate a header file for the parser */
+void ReportHeader(struct lemon *lemp)
+{
+  FILE *out, *in;
+  const char *prefix;
+  char line[LINESIZE];
+  char pattern[LINESIZE];
+  int i;
+
+  if( lemp->tokenprefix ) prefix = lemp->tokenprefix;
+  else                    prefix = "";
+  in = file_open(lemp,".h","rb");
+  if( in ){
+    int nextChar;
+    for(i=1; i<lemp->nterminal && fgets(line,LINESIZE,in); i++){
+      lemon_sprintf(pattern,"#define %s%-30s %3d\n",
+                    prefix,lemp->symbols[i]->name,i);
+      if( strcmp(line,pattern) ) break;
+    }
+    nextChar = fgetc(in);
+    fclose(in);
+    if( i==lemp->nterminal && nextChar==EOF ){
+      /* No change in the file.  Don't rewrite it. */
+      return;
+    }
+  }
+  out = file_open(lemp,".h","wb");
+  if( out ){
+    for(i=1; i<lemp->nterminal; i++){
+      fprintf(out,"#define %s%-30s %3d\n",prefix,lemp->symbols[i]->name,i);
+    }
+    fclose(out);  
+  }
+  return;
+}
+
+/* Reduce the size of the action tables, if possible, by making use
+** of defaults.
+**
+** In this version, we take the most frequent REDUCE action and make
+** it the default.  Except, there is no default if the wildcard token
+** is a possible look-ahead.
+*/
+void CompressTables(struct lemon *lemp)
+{
+  struct state *stp;
+  struct action *ap, *ap2, *nextap;
+  struct rule *rp, *rp2, *rbest;
+  int nbest, n;
+  int i;
+  int usesWildcard;
+
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+    nbest = 0;
+    rbest = 0;
+    usesWildcard = 0;
+
+    for(ap=stp->ap; ap; ap=ap->next){
+      if( ap->type==SHIFT && ap->sp==lemp->wildcard ){
+        usesWildcard = 1;
+      }
+      if( ap->type!=REDUCE ) continue;
+      rp = ap->x.rp;
+      if( rp->lhsStart ) continue;
+      if( rp==rbest ) continue;
+      n = 1;
+      for(ap2=ap->next; ap2; ap2=ap2->next){
+        if( ap2->type!=REDUCE ) continue;
+        rp2 = ap2->x.rp;
+        if( rp2==rbest ) continue;
+        if( rp2==rp ) n++;
+      }
+      if( n>nbest ){
+        nbest = n;
+        rbest = rp;
+      }
+    }
+    /* Do not make a default if the number of rules to default
+    ** is not at least 1 or if the wildcard token is a possible
+    ** lookahead.
+    */
+    if( nbest<1 || usesWildcard ) continue;
+
+
+    /* Combine matching REDUCE actions into a single default */
+    for(ap=stp->ap; ap; ap=ap->next){
+      if( ap->type==REDUCE && ap->x.rp==rbest ) break;
+    }
+    assert( ap );
+    ap->sp = Symbol_new("{default}");
+    for(ap=ap->next; ap; ap=ap->next){
+      if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED;
+    }
+    stp->ap = Action_sort(stp->ap);
+
+    for(ap=stp->ap; ap; ap=ap->next){
+      if( ap->type==SHIFT ) break;
+      if( ap->type==REDUCE && ap->x.rp!=rbest ) break;
+    }
+    if( ap==0 ){
+      stp->autoReduce = 1;
+      stp->pDfltReduce = rbest;
+    }
+  }
+
+  /* Make a second pass over all states and actions.  Convert
+  ** every action that is a SHIFT to an autoReduce state into
+  ** a SHIFTREDUCE action.
+  */
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+    for(ap=stp->ap; ap; ap=ap->next){
+      struct state *pNextState;
+      if( ap->type!=SHIFT ) continue;
+      pNextState = ap->x.stp;
+      if( pNextState->autoReduce && pNextState->pDfltReduce!=0 ){
+        ap->type = SHIFTREDUCE;
+        ap->x.rp = pNextState->pDfltReduce;
+      }
+    }
+  }
+
+  /* If a SHIFTREDUCE action specifies a rule that has a single RHS term
+  ** (meaning that the SHIFTREDUCE will land back in the state where it
+  ** started) and if there is no C-code associated with the reduce action,
+  ** then we can go ahead and convert the action to be the same as the
+  ** action for the RHS of the rule.
+  */
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+    for(ap=stp->ap; ap; ap=nextap){
+      nextap = ap->next;
+      if( ap->type!=SHIFTREDUCE ) continue;
+      rp = ap->x.rp;
+      if( rp->noCode==0 ) continue;
+      if( rp->nrhs!=1 ) continue;
+#if 1
+      /* Only apply this optimization to non-terminals.  It would be OK to
+      ** apply it to terminal symbols too, but that makes the parser tables
+      ** larger. */
+      if( ap->sp->index<lemp->nterminal ) continue;
+#endif
+      /* If we reach this point, it means the optimization can be applied */
+      nextap = ap;
+      for(ap2=stp->ap; ap2 && (ap2==ap || ap2->sp!=rp->lhs); ap2=ap2->next){}
+      assert( ap2!=0 );
+      ap->spOpt = ap2->sp;
+      ap->type = ap2->type;
+      ap->x = ap2->x;
+    }
+  }
+}
+
+
+/*
+** Compare two states for sorting purposes.  The smaller state is the
+** one with the most non-terminal actions.  If they have the same number
+** of non-terminal actions, then the smaller is the one with the most
+** token actions.
+*/
+static int stateResortCompare(const void *a, const void *b){
+  const struct state *pA = *(const struct state**)a;
+  const struct state *pB = *(const struct state**)b;
+  int n;
+
+  n = pB->nNtAct - pA->nNtAct;
+  if( n==0 ){
+    n = pB->nTknAct - pA->nTknAct;
+    if( n==0 ){
+      n = pB->statenum - pA->statenum;
+    }
+  }
+  assert( n!=0 );
+  return n;
+}
+
+
+/*
+** Renumber and resort states so that states with fewer choices
+** occur at the end.  Except, keep state 0 as the first state.
+*/
+void ResortStates(struct lemon *lemp)
+{
+  int i;
+  struct state *stp;
+  struct action *ap;
+
+  for(i=0; i<lemp->nstate; i++){
+    stp = lemp->sorted[i];
+    stp->nTknAct = stp->nNtAct = 0;
+    stp->iDfltReduce = lemp->nrule;  /* Init dflt action to "syntax error" */
+    stp->iTknOfst = NO_OFFSET;
+    stp->iNtOfst = NO_OFFSET;
+    for(ap=stp->ap; ap; ap=ap->next){
+      int iAction = compute_action(lemp,ap);
+      if( iAction>=0 ){
+        if( ap->sp->index<lemp->nterminal ){
+          stp->nTknAct++;
+        }else if( ap->sp->index<lemp->nsymbol ){
+          stp->nNtAct++;
+        }else{
+          assert( stp->autoReduce==0 || stp->pDfltReduce==ap->x.rp );
+          stp->iDfltReduce = iAction - lemp->nstate - lemp->nrule;
+        }
+      }
+    }
+  }
+  qsort(&lemp->sorted[1], lemp->nstate-1, sizeof(lemp->sorted[0]),
+        stateResortCompare);
+  for(i=0; i<lemp->nstate; i++){
+    lemp->sorted[i]->statenum = i;
+  }
+  lemp->nxstate = lemp->nstate;
+  while( lemp->nxstate>1 && lemp->sorted[lemp->nxstate-1]->autoReduce ){
+    lemp->nxstate--;
+  }
+}
+
+
+/***************** From the file "set.c" ************************************/
+/*
+** Set manipulation routines for the LEMON parser generator.
+*/
+
+static int size = 0;
+
+/* Set the set size */
+void SetSize(int n)
+{
+  size = n+1;
+}
+
+/* Allocate a new set */
+char *SetNew(){
+  char *s;
+  s = (char*)calloc( size, 1);
+  if( s==0 ){
+    extern void memory_error();
+    memory_error();
+  }
+  return s;
+}
+
+/* Deallocate a set */
+void SetFree(char *s)
+{
+  free(s);
+}
+
+/* Add a new element to the set.  Return TRUE if the element was added
+** and FALSE if it was already there. */
+int SetAdd(char *s, int e)
+{
+  int rv;
+  assert( e>=0 && e<size );
+  rv = s[e];
+  s[e] = 1;
+  return !rv;
+}
+
+/* Add every element of s2 to s1.  Return TRUE if s1 changes. */
+int SetUnion(char *s1, char *s2)
+{
+  int i, progress;
+  progress = 0;
+  for(i=0; i<size; i++){
+    if( s2[i]==0 ) continue;
+    if( s1[i]==0 ){
+      progress = 1;
+      s1[i] = 1;
+    }
+  }
+  return progress;
+}
+/********************** From the file "table.c" ****************************/
+/*
+** All code in this file has been automatically generated
+** from a specification in the file
+**              "table.q"
+** by the associative array code building program "aagen".
+** Do not edit this file!  Instead, edit the specification
+** file, then rerun aagen.
+*/
+/*
+** Code for processing tables in the LEMON parser generator.
+*/
+
+PRIVATE unsigned strhash(const char *x)
+{
+  unsigned h = 0;
+  while( *x ) h = h*13 + *(x++);
+  return h;
+}
+
+/* Works like strdup, sort of.  Save a string in malloced memory, but
+** keep strings in a table so that the same string is not in more
+** than one place.
+*/
+const char *Strsafe(const char *y)
+{
+  const char *z;
+  char *cpy;
+
+  if( y==0 ) return 0;
+  z = Strsafe_find(y);
+  if( z==0 && (cpy=(char *)malloc( lemonStrlen(y)+1 ))!=0 ){
+    lemon_strcpy(cpy,y);
+    z = cpy;
+    Strsafe_insert(z);
+  }
+  MemoryCheck(z);
+  return z;
+}
+
+/* There is one instance of the following structure for each
+** associative array of type "x1".
+*/
+struct s_x1 {
+  int size;               /* The number of available slots. */
+                          /*   Must be a power of 2 greater than or */
+                          /*   equal to 1 */
+  int count;              /* Number of currently slots filled */
+  struct s_x1node *tbl;  /* The data stored here */
+  struct s_x1node **ht;  /* Hash table for lookups */
+};
+
+/* There is one instance of this structure for every data element
+** in an associative array of type "x1".
+*/
+typedef struct s_x1node {
+  const char *data;        /* The data */
+  struct s_x1node *next;   /* Next entry with the same hash */
+  struct s_x1node **from;  /* Previous link */
+} x1node;
+
+/* There is only one instance of the array, which is the following */
+static struct s_x1 *x1a;
+
+/* Allocate a new associative array */
+void Strsafe_init(){
+  if( x1a ) return;
+  x1a = (struct s_x1*)malloc( sizeof(struct s_x1) );
+  if( x1a ){
+    x1a->size = 1024;
+    x1a->count = 0;
+    x1a->tbl = (x1node*)calloc(1024, sizeof(x1node) + sizeof(x1node*));
+    if( x1a->tbl==0 ){
+      free(x1a);
+      x1a = 0;
+    }else{
+      int i;
+      x1a->ht = (x1node**)&(x1a->tbl[1024]);
+      for(i=0; i<1024; i++) x1a->ht[i] = 0;
+    }
+  }
+}
+/* Insert a new record into the array.  Return TRUE if successful.
+** Prior data with the same key is NOT overwritten */
+int Strsafe_insert(const char *data)
+{
+  x1node *np;
+  unsigned h;
+  unsigned ph;
+
+  if( x1a==0 ) return 0;
+  ph = strhash(data);
+  h = ph & (x1a->size-1);
+  np = x1a->ht[h];
+  while( np ){
+    if( strcmp(np->data,data)==0 ){
+      /* An existing entry with the same key is found. */
+      /* Fail because overwrite is not allows. */
+      return 0;
+    }
+    np = np->next;
+  }
+  if( x1a->count>=x1a->size ){
+    /* Need to make the hash table bigger */
+    int i,arrSize;
+    struct s_x1 array;
+    array.size = arrSize = x1a->size*2;
+    array.count = x1a->count;
+    array.tbl = (x1node*)calloc(arrSize, sizeof(x1node) + sizeof(x1node*));
+    if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
+    array.ht = (x1node**)&(array.tbl[arrSize]);
+    for(i=0; i<arrSize; i++) array.ht[i] = 0;
+    for(i=0; i<x1a->count; i++){
+      x1node *oldnp, *newnp;
+      oldnp = &(x1a->tbl[i]);
+      h = strhash(oldnp->data) & (arrSize-1);
+      newnp = &(array.tbl[i]);
+      if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
+      newnp->next = array.ht[h];
+      newnp->data = oldnp->data;
+      newnp->from = &(array.ht[h]);
+      array.ht[h] = newnp;
+    }
+    free(x1a->tbl);
+    *x1a = array;
+  }
+  /* Insert the new data */
+  h = ph & (x1a->size-1);
+  np = &(x1a->tbl[x1a->count++]);
+  np->data = data;
+  if( x1a->ht[h] ) x1a->ht[h]->from = &(np->next);
+  np->next = x1a->ht[h];
+  x1a->ht[h] = np;
+  np->from = &(x1a->ht[h]);
+  return 1;
+}
+
+/* Return a pointer to data assigned to the given key.  Return NULL
+** if no such key. */
+const char *Strsafe_find(const char *key)
+{
+  unsigned h;
+  x1node *np;
+
+  if( x1a==0 ) return 0;
+  h = strhash(key) & (x1a->size-1);
+  np = x1a->ht[h];
+  while( np ){
+    if( strcmp(np->data,key)==0 ) break;
+    np = np->next;
+  }
+  return np ? np->data : 0;
+}
+
+/* Return a pointer to the (terminal or nonterminal) symbol "x".
+** Create a new symbol if this is the first time "x" has been seen.
+*/
+struct symbol *Symbol_new(const char *x)
+{
+  struct symbol *sp;
+
+  sp = Symbol_find(x);
+  if( sp==0 ){
+    sp = (struct symbol *)calloc(1, sizeof(struct symbol) );
+    MemoryCheck(sp);
+    sp->name = Strsafe(x);
+    sp->type = ISUPPER(*x) ? TERMINAL : NONTERMINAL;
+    sp->rule = 0;
+    sp->fallback = 0;
+    sp->prec = -1;
+    sp->assoc = UNK;
+    sp->firstset = 0;
+    sp->lambda = LEMON_FALSE;
+    sp->destructor = 0;
+    sp->destLineno = 0;
+    sp->datatype = 0;
+    sp->useCnt = 0;
+    Symbol_insert(sp,sp->name);
+  }
+  sp->useCnt++;
+  return sp;
+}
+
+/* Compare two symbols for sorting purposes.  Return negative,
+** zero, or positive if a is less then, equal to, or greater
+** than b.
+**
+** Symbols that begin with upper case letters (terminals or tokens)
+** must sort before symbols that begin with lower case letters
+** (non-terminals).  And MULTITERMINAL symbols (created using the
+** %token_class directive) must sort at the very end. Other than
+** that, the order does not matter.
+**
+** We find experimentally that leaving the symbols in their original
+** order (the order they appeared in the grammar file) gives the
+** smallest parser tables in SQLite.
+*/
+int Symbolcmpp(const void *_a, const void *_b)
+{
+  const struct symbol *a = *(const struct symbol **) _a;
+  const struct symbol *b = *(const struct symbol **) _b;
+  int i1 = a->type==MULTITERMINAL ? 3 : a->name[0]>'Z' ? 2 : 1;
+  int i2 = b->type==MULTITERMINAL ? 3 : b->name[0]>'Z' ? 2 : 1;
+  return i1==i2 ? a->index - b->index : i1 - i2;
+}
+
+/* There is one instance of the following structure for each
+** associative array of type "x2".
+*/
+struct s_x2 {
+  int size;               /* The number of available slots. */
+                          /*   Must be a power of 2 greater than or */
+                          /*   equal to 1 */
+  int count;              /* Number of currently slots filled */
+  struct s_x2node *tbl;  /* The data stored here */
+  struct s_x2node **ht;  /* Hash table for lookups */
+};
+
+/* There is one instance of this structure for every data element
+** in an associative array of type "x2".
+*/
+typedef struct s_x2node {
+  struct symbol *data;     /* The data */
+  const char *key;         /* The key */
+  struct s_x2node *next;   /* Next entry with the same hash */
+  struct s_x2node **from;  /* Previous link */
+} x2node;
+
+/* There is only one instance of the array, which is the following */
+static struct s_x2 *x2a;
+
+/* Allocate a new associative array */
+void Symbol_init(){
+  if( x2a ) return;
+  x2a = (struct s_x2*)malloc( sizeof(struct s_x2) );
+  if( x2a ){
+    x2a->size = 128;
+    x2a->count = 0;
+    x2a->tbl = (x2node*)calloc(128, sizeof(x2node) + sizeof(x2node*));
+    if( x2a->tbl==0 ){
+      free(x2a);
+      x2a = 0;
+    }else{
+      int i;
+      x2a->ht = (x2node**)&(x2a->tbl[128]);
+      for(i=0; i<128; i++) x2a->ht[i] = 0;
+    }
+  }
+}
+/* Insert a new record into the array.  Return TRUE if successful.
+** Prior data with the same key is NOT overwritten */
+int Symbol_insert(struct symbol *data, const char *key)
+{
+  x2node *np;
+  unsigned h;
+  unsigned ph;
+
+  if( x2a==0 ) return 0;
+  ph = strhash(key);
+  h = ph & (x2a->size-1);
+  np = x2a->ht[h];
+  while( np ){
+    if( strcmp(np->key,key)==0 ){
+      /* An existing entry with the same key is found. */
+      /* Fail because overwrite is not allows. */
+      return 0;
+    }
+    np = np->next;
+  }
+  if( x2a->count>=x2a->size ){
+    /* Need to make the hash table bigger */
+    int i,arrSize;
+    struct s_x2 array;
+    array.size = arrSize = x2a->size*2;
+    array.count = x2a->count;
+    array.tbl = (x2node*)calloc(arrSize, sizeof(x2node) + sizeof(x2node*));
+    if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
+    array.ht = (x2node**)&(array.tbl[arrSize]);
+    for(i=0; i<arrSize; i++) array.ht[i] = 0;
+    for(i=0; i<x2a->count; i++){
+      x2node *oldnp, *newnp;
+      oldnp = &(x2a->tbl[i]);
+      h = strhash(oldnp->key) & (arrSize-1);
+      newnp = &(array.tbl[i]);
+      if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
+      newnp->next = array.ht[h];
+      newnp->key = oldnp->key;
+      newnp->data = oldnp->data;
+      newnp->from = &(array.ht[h]);
+      array.ht[h] = newnp;
+    }
+    free(x2a->tbl);
+    *x2a = array;
+  }
+  /* Insert the new data */
+  h = ph & (x2a->size-1);
+  np = &(x2a->tbl[x2a->count++]);
+  np->key = key;
+  np->data = data;
+  if( x2a->ht[h] ) x2a->ht[h]->from = &(np->next);
+  np->next = x2a->ht[h];
+  x2a->ht[h] = np;
+  np->from = &(x2a->ht[h]);
+  return 1;
+}
+
+/* Return a pointer to data assigned to the given key.  Return NULL
+** if no such key. */
+struct symbol *Symbol_find(const char *key)
+{
+  unsigned h;
+  x2node *np;
+
+  if( x2a==0 ) return 0;
+  h = strhash(key) & (x2a->size-1);
+  np = x2a->ht[h];
+  while( np ){
+    if( strcmp(np->key,key)==0 ) break;
+    np = np->next;
+  }
+  return np ? np->data : 0;
+}
+
+/* Return the n-th data.  Return NULL if n is out of range. */
+struct symbol *Symbol_Nth(int n)
+{
+  struct symbol *data;
+  if( x2a && n>0 && n<=x2a->count ){
+    data = x2a->tbl[n-1].data;
+  }else{
+    data = 0;
+  }
+  return data;
+}
+
+/* Return the size of the array */
+int Symbol_count()
+{
+  return x2a ? x2a->count : 0;
+}
+
+/* Return an array of pointers to all data in the table.
+** The array is obtained from malloc.  Return NULL if memory allocation
+** problems, or if the array is empty. */
+struct symbol **Symbol_arrayof()
+{
+  struct symbol **array;
+  int i,arrSize;
+  if( x2a==0 ) return 0;
+  arrSize = x2a->count;
+  array = (struct symbol **)calloc(arrSize, sizeof(struct symbol *));
+  if( array ){
+    for(i=0; i<arrSize; i++) array[i] = x2a->tbl[i].data;
+  }
+  return array;
+}
+
+/* Compare two configurations */
+int Configcmp(const char *_a,const char *_b)
+{
+  const struct config *a = (struct config *) _a;
+  const struct config *b = (struct config *) _b;
+  int x;
+  x = a->rp->index - b->rp->index;
+  if( x==0 ) x = a->dot - b->dot;
+  return x;
+}
+
+/* Compare two states */
+PRIVATE int statecmp(struct config *a, struct config *b)
+{
+  int rc;
+  for(rc=0; rc==0 && a && b;  a=a->bp, b=b->bp){
+    rc = a->rp->index - b->rp->index;
+    if( rc==0 ) rc = a->dot - b->dot;
+  }
+  if( rc==0 ){
+    if( a ) rc = 1;
+    if( b ) rc = -1;
+  }
+  return rc;
+}
+
+/* Hash a state */
+PRIVATE unsigned statehash(struct config *a)
+{
+  unsigned h=0;
+  while( a ){
+    h = h*571 + a->rp->index*37 + a->dot;
+    a = a->bp;
+  }
+  return h;
+}
+
+/* Allocate a new state structure */
+struct state *State_new()
+{
+  struct state *newstate;
+  newstate = (struct state *)calloc(1, sizeof(struct state) );
+  MemoryCheck(newstate);
+  return newstate;
+}
+
+/* There is one instance of the following structure for each
+** associative array of type "x3".
+*/
+struct s_x3 {
+  int size;               /* The number of available slots. */
+                          /*   Must be a power of 2 greater than or */
+                          /*   equal to 1 */
+  int count;              /* Number of currently slots filled */
+  struct s_x3node *tbl;  /* The data stored here */
+  struct s_x3node **ht;  /* Hash table for lookups */
+};
+
+/* There is one instance of this structure for every data element
+** in an associative array of type "x3".
+*/
+typedef struct s_x3node {
+  struct state *data;                  /* The data */
+  struct config *key;                   /* The key */
+  struct s_x3node *next;   /* Next entry with the same hash */
+  struct s_x3node **from;  /* Previous link */
+} x3node;
+
+/* There is only one instance of the array, which is the following */
+static struct s_x3 *x3a;
+
+/* Allocate a new associative array */
+void State_init(){
+  if( x3a ) return;
+  x3a = (struct s_x3*)malloc( sizeof(struct s_x3) );
+  if( x3a ){
+    x3a->size = 128;
+    x3a->count = 0;
+    x3a->tbl = (x3node*)calloc(128, sizeof(x3node) + sizeof(x3node*));
+    if( x3a->tbl==0 ){
+      free(x3a);
+      x3a = 0;
+    }else{
+      int i;
+      x3a->ht = (x3node**)&(x3a->tbl[128]);
+      for(i=0; i<128; i++) x3a->ht[i] = 0;
+    }
+  }
+}
+/* Insert a new record into the array.  Return TRUE if successful.
+** Prior data with the same key is NOT overwritten */
+int State_insert(struct state *data, struct config *key)
+{
+  x3node *np;
+  unsigned h;
+  unsigned ph;
+
+  if( x3a==0 ) return 0;
+  ph = statehash(key);
+  h = ph & (x3a->size-1);
+  np = x3a->ht[h];
+  while( np ){
+    if( statecmp(np->key,key)==0 ){
+      /* An existing entry with the same key is found. */
+      /* Fail because overwrite is not allows. */
+      return 0;
+    }
+    np = np->next;
+  }
+  if( x3a->count>=x3a->size ){
+    /* Need to make the hash table bigger */
+    int i,arrSize;
+    struct s_x3 array;
+    array.size = arrSize = x3a->size*2;
+    array.count = x3a->count;
+    array.tbl = (x3node*)calloc(arrSize, sizeof(x3node) + sizeof(x3node*));
+    if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
+    array.ht = (x3node**)&(array.tbl[arrSize]);
+    for(i=0; i<arrSize; i++) array.ht[i] = 0;
+    for(i=0; i<x3a->count; i++){
+      x3node *oldnp, *newnp;
+      oldnp = &(x3a->tbl[i]);
+      h = statehash(oldnp->key) & (arrSize-1);
+      newnp = &(array.tbl[i]);
+      if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
+      newnp->next = array.ht[h];
+      newnp->key = oldnp->key;
+      newnp->data = oldnp->data;
+      newnp->from = &(array.ht[h]);
+      array.ht[h] = newnp;
+    }
+    free(x3a->tbl);
+    *x3a = array;
+  }
+  /* Insert the new data */
+  h = ph & (x3a->size-1);
+  np = &(x3a->tbl[x3a->count++]);
+  np->key = key;
+  np->data = data;
+  if( x3a->ht[h] ) x3a->ht[h]->from = &(np->next);
+  np->next = x3a->ht[h];
+  x3a->ht[h] = np;
+  np->from = &(x3a->ht[h]);
+  return 1;
+}
+
+/* Return a pointer to data assigned to the given key.  Return NULL
+** if no such key. */
+struct state *State_find(struct config *key)
+{
+  unsigned h;
+  x3node *np;
+
+  if( x3a==0 ) return 0;
+  h = statehash(key) & (x3a->size-1);
+  np = x3a->ht[h];
+  while( np ){
+    if( statecmp(np->key,key)==0 ) break;
+    np = np->next;
+  }
+  return np ? np->data : 0;
+}
+
+/* Return an array of pointers to all data in the table.
+** The array is obtained from malloc.  Return NULL if memory allocation
+** problems, or if the array is empty. */
+struct state **State_arrayof()
+{
+  struct state **array;
+  int i,arrSize;
+  if( x3a==0 ) return 0;
+  arrSize = x3a->count;
+  array = (struct state **)calloc(arrSize, sizeof(struct state *));
+  if( array ){
+    for(i=0; i<arrSize; i++) array[i] = x3a->tbl[i].data;
+  }
+  return array;
+}
+
+/* Hash a configuration */
+PRIVATE unsigned confighash(struct config *a)
+{
+  unsigned h=0;
+  h = h*571 + a->rp->index*37 + a->dot;
+  return h;
+}
+
+/* There is one instance of the following structure for each
+** associative array of type "x4".
+*/
+struct s_x4 {
+  int size;               /* The number of available slots. */
+                          /*   Must be a power of 2 greater than or */
+                          /*   equal to 1 */
+  int count;              /* Number of currently slots filled */
+  struct s_x4node *tbl;  /* The data stored here */
+  struct s_x4node **ht;  /* Hash table for lookups */
+};
+
+/* There is one instance of this structure for every data element
+** in an associative array of type "x4".
+*/
+typedef struct s_x4node {
+  struct config *data;                  /* The data */
+  struct s_x4node *next;   /* Next entry with the same hash */
+  struct s_x4node **from;  /* Previous link */
+} x4node;
+
+/* There is only one instance of the array, which is the following */
+static struct s_x4 *x4a;
+
+/* Allocate a new associative array */
+void Configtable_init(){
+  if( x4a ) return;
+  x4a = (struct s_x4*)malloc( sizeof(struct s_x4) );
+  if( x4a ){
+    x4a->size = 64;
+    x4a->count = 0;
+    x4a->tbl = (x4node*)calloc(64, sizeof(x4node) + sizeof(x4node*));
+    if( x4a->tbl==0 ){
+      free(x4a);
+      x4a = 0;
+    }else{
+      int i;
+      x4a->ht = (x4node**)&(x4a->tbl[64]);
+      for(i=0; i<64; i++) x4a->ht[i] = 0;
+    }
+  }
+}
+/* Insert a new record into the array.  Return TRUE if successful.
+** Prior data with the same key is NOT overwritten */
+int Configtable_insert(struct config *data)
+{
+  x4node *np;
+  unsigned h;
+  unsigned ph;
+
+  if( x4a==0 ) return 0;
+  ph = confighash(data);
+  h = ph & (x4a->size-1);
+  np = x4a->ht[h];
+  while( np ){
+    if( Configcmp((const char *) np->data,(const char *) data)==0 ){
+      /* An existing entry with the same key is found. */
+      /* Fail because overwrite is not allows. */
+      return 0;
+    }
+    np = np->next;
+  }
+  if( x4a->count>=x4a->size ){
+    /* Need to make the hash table bigger */
+    int i,arrSize;
+    struct s_x4 array;
+    array.size = arrSize = x4a->size*2;
+    array.count = x4a->count;
+    array.tbl = (x4node*)calloc(arrSize, sizeof(x4node) + sizeof(x4node*));
+    if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
+    array.ht = (x4node**)&(array.tbl[arrSize]);
+    for(i=0; i<arrSize; i++) array.ht[i] = 0;
+    for(i=0; i<x4a->count; i++){
+      x4node *oldnp, *newnp;
+      oldnp = &(x4a->tbl[i]);
+      h = confighash(oldnp->data) & (arrSize-1);
+      newnp = &(array.tbl[i]);
+      if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
+      newnp->next = array.ht[h];
+      newnp->data = oldnp->data;
+      newnp->from = &(array.ht[h]);
+      array.ht[h] = newnp;
+    }
+    free(x4a->tbl);
+    *x4a = array;
+  }
+  /* Insert the new data */
+  h = ph & (x4a->size-1);
+  np = &(x4a->tbl[x4a->count++]);
+  np->data = data;
+  if( x4a->ht[h] ) x4a->ht[h]->from = &(np->next);
+  np->next = x4a->ht[h];
+  x4a->ht[h] = np;
+  np->from = &(x4a->ht[h]);
+  return 1;
+}
+
+/* Return a pointer to data assigned to the given key.  Return NULL
+** if no such key. */
+struct config *Configtable_find(struct config *key)
+{
+  int h;
+  x4node *np;
+
+  if( x4a==0 ) return 0;
+  h = confighash(key) & (x4a->size-1);
+  np = x4a->ht[h];
+  while( np ){
+    if( Configcmp((const char *) np->data,(const char *) key)==0 ) break;
+    np = np->next;
+  }
+  return np ? np->data : 0;
+}
+
+/* Remove all data from the table.  Pass each data to the function "f"
+** as it is removed.  ("f" may be null to avoid this step.) */
+void Configtable_clear(int(*f)(struct config *))
+{
+  int i;
+  if( x4a==0 || x4a->count==0 ) return;
+  if( f ) for(i=0; i<x4a->count; i++) (*f)(x4a->tbl[i].data);
+  for(i=0; i<x4a->size; i++) x4a->ht[i] = 0;
+  x4a->count = 0;
+  return;
+}
diff --git a/lemon/lempar.c b/lemon/lempar.c
new file mode 100644 (file)
index 0000000..5195d9c
--- /dev/null
@@ -0,0 +1,946 @@
+/*
+** 2000-05-29
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** Driver template for the LEMON parser generator.
+**
+** The "lemon" program processes an LALR(1) input grammar file, then uses
+** this template to construct a parser.  The "lemon" program inserts text
+** at each "%%" line.  Also, any "P-a-r-s-e" identifer prefix (without the
+** interstitial "-" characters) contained in this template is changed into
+** the value of the %name directive from the grammar.  Otherwise, the content
+** of this template is copied straight through into the generate parser
+** source file.
+**
+** The following is the concatenation of all %include directives from the
+** input grammar file:
+*/
+#include <stdio.h>
+/************ Begin %include sections from the grammar ************************/
+%%
+/**************** End of %include directives **********************************/
+/* These constants specify the various numeric values for terminal symbols
+** in a format understandable to "makeheaders".  This section is blank unless
+** "lemon" is run with the "-m" command-line option.
+***************** Begin makeheaders token definitions *************************/
+%%
+/**************** End makeheaders token definitions ***************************/
+
+/* The next sections is a series of control #defines.
+** various aspects of the generated parser.
+**    YYCODETYPE         is the data type used to store the integer codes
+**                       that represent terminal and non-terminal symbols.
+**                       "unsigned char" is used if there are fewer than
+**                       256 symbols.  Larger types otherwise.
+**    YYNOCODE           is a number of type YYCODETYPE that is not used for
+**                       any terminal or nonterminal symbol.
+**    YYFALLBACK         If defined, this indicates that one or more tokens
+**                       (also known as: "terminal symbols") have fall-back
+**                       values which should be used if the original symbol
+**                       would not parse.  This permits keywords to sometimes
+**                       be used as identifiers, for example.
+**    YYACTIONTYPE       is the data type used for "action codes" - numbers
+**                       that indicate what to do in response to the next
+**                       token.
+**    ParseTOKENTYPE     is the data type used for minor type for terminal
+**                       symbols.  Background: A "minor type" is a semantic
+**                       value associated with a terminal or non-terminal
+**                       symbols.  For example, for an "ID" terminal symbol,
+**                       the minor type might be the name of the identifier.
+**                       Each non-terminal can have a different minor type.
+**                       Terminal symbols all have the same minor type, though.
+**                       This macros defines the minor type for terminal 
+**                       symbols.
+**    YYMINORTYPE        is the data type used for all minor types.
+**                       This is typically a union of many types, one of
+**                       which is ParseTOKENTYPE.  The entry in the union
+**                       for terminal symbols is called "yy0".
+**    YYSTACKDEPTH       is the maximum depth of the parser's stack.  If
+**                       zero the stack is dynamically sized using realloc()
+**    ParseARG_SDECL     A static variable declaration for the %extra_argument
+**    ParseARG_PDECL     A parameter declaration for the %extra_argument
+**    ParseARG_STORE     Code to store %extra_argument into yypParser
+**    ParseARG_FETCH     Code to extract %extra_argument from yypParser
+**    YYERRORSYMBOL      is the code number of the error symbol.  If not
+**                       defined, then do no error processing.
+**    YYNSTATE           the combined number of states.
+**    YYNRULE            the number of rules in the grammar
+**    YY_MAX_SHIFT       Maximum value for shift actions
+**    YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
+**    YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
+**    YY_MIN_REDUCE      Maximum value for reduce actions
+**    YY_ERROR_ACTION    The yy_action[] code for syntax error
+**    YY_ACCEPT_ACTION   The yy_action[] code for accept
+**    YY_NO_ACTION       The yy_action[] code for no-op
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/************* Begin control #defines *****************************************/
+%%
+/************* End control #defines *******************************************/
+
+/* Define the yytestcase() macro to be a no-op if is not already defined
+** otherwise.
+**
+** Applications can choose to define yytestcase() in the %include section
+** to a macro that can assist in verifying code coverage.  For production
+** code the yytestcase() macro should be turned off.  But it is useful
+** for testing.
+*/
+#ifndef yytestcase
+# define yytestcase(X)
+#endif
+
+
+/* Next are the tables used to determine what action to take based on the
+** current state and lookahead token.  These tables are used to implement
+** functions that take a state number and lookahead value and return an
+** action integer.  
+**
+** Suppose the action integer is N.  Then the action is determined as
+** follows
+**
+**   0 <= N <= YY_MAX_SHIFT             Shift N.  That is, push the lookahead
+**                                      token onto the stack and goto state N.
+**
+**   N between YY_MIN_SHIFTREDUCE       Shift to an arbitrary state then
+**     and YY_MAX_SHIFTREDUCE           reduce by rule N-YY_MIN_SHIFTREDUCE.
+**
+**   N between YY_MIN_REDUCE            Reduce by rule N-YY_MIN_REDUCE
+**     and YY_MAX_REDUCE
+**
+**   N == YY_ERROR_ACTION               A syntax error has occurred.
+**
+**   N == YY_ACCEPT_ACTION              The parser accepts its input.
+**
+**   N == YY_NO_ACTION                  No such action.  Denotes unused
+**                                      slots in the yy_action[] table.
+**
+** The action table is constructed as a single large table named yy_action[].
+** Given state S and lookahead X, the action is computed as either:
+**
+**    (A)   N = yy_action[ yy_shift_ofst[S] + X ]
+**    (B)   N = yy_default[S]
+**
+** The (A) formula is preferred.  The B formula is used instead if:
+**    (1)  The yy_shift_ofst[S]+X value is out of range, or
+**    (2)  yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or
+**    (3)  yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT.
+** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that
+** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X.
+** Hence only tests (1) and (2) need to be evaluated.)
+**
+** The formulas above are for computing the action when the lookahead is
+** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
+** a reduce action) then the yy_reduce_ofst[] array is used in place of
+** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
+** YY_SHIFT_USE_DFLT.
+**
+** The following are the tables generated in this section:
+**
+**  yy_action[]        A single table containing all actions.
+**  yy_lookahead[]     A table containing the lookahead for each entry in
+**                     yy_action.  Used to detect hash collisions.
+**  yy_shift_ofst[]    For each state, the offset into yy_action for
+**                     shifting terminals.
+**  yy_reduce_ofst[]   For each state, the offset into yy_action for
+**                     shifting non-terminals after a reduce.
+**  yy_default[]       Default action for each state.
+**
+*********** Begin parsing tables **********************************************/
+%%
+/********** End of lemon-generated parsing tables *****************************/
+
+/* The next table maps tokens (terminal symbols) into fallback tokens.  
+** If a construct like the following:
+** 
+**      %fallback ID X Y Z.
+**
+** appears in the grammar, then ID becomes a fallback token for X, Y,
+** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
+** but it does not parse, the type of the token is changed to ID and
+** the parse is retried before an error is thrown.
+**
+** This feature can be used, for example, to cause some keywords in a language
+** to revert to identifiers if they keyword does not apply in the context where
+** it appears.
+*/
+#ifdef YYFALLBACK
+static const YYCODETYPE yyFallback[] = {
+%%
+};
+#endif /* YYFALLBACK */
+
+/* The following structure represents a single element of the
+** parser's stack.  Information stored includes:
+**
+**   +  The state number for the parser at this level of the stack.
+**
+**   +  The value of the token stored at this level of the stack.
+**      (In other words, the "major" token.)
+**
+**   +  The semantic value stored at this level of the stack.  This is
+**      the information used by the action routines in the grammar.
+**      It is sometimes called the "minor" token.
+**
+** After the "shift" half of a SHIFTREDUCE action, the stateno field
+** actually contains the reduce action for the second half of the
+** SHIFTREDUCE.
+*/
+struct yyStackEntry {
+  YYACTIONTYPE stateno;  /* The state-number, or reduce action in SHIFTREDUCE */
+  YYCODETYPE major;      /* The major token value.  This is the code
+                         ** number for the token at this stack level */
+  YYMINORTYPE minor;     /* The user-supplied minor token value.  This
+                         ** is the value of the token  */
+};
+typedef struct yyStackEntry yyStackEntry;
+
+/* The state of the parser is completely contained in an instance of
+** the following structure */
+struct yyParser {
+  yyStackEntry *yytos;          /* Pointer to top element of the stack */
+#ifdef YYTRACKMAXSTACKDEPTH
+  int yyhwm;                    /* High-water mark of the stack */
+#endif
+#ifndef YYNOERRORRECOVERY
+  int yyerrcnt;                 /* Shifts left before out of the error */
+#endif
+  ParseARG_SDECL                /* A place to hold %extra_argument */
+#if YYSTACKDEPTH<=0
+  int yystksz;                  /* Current side of the stack */
+  yyStackEntry *yystack;        /* The parser's stack */
+  yyStackEntry yystk0;          /* First stack entry */
+#else
+  yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
+#endif
+};
+typedef struct yyParser yyParser;
+
+#ifndef NDEBUG
+#include <stdio.h>
+static FILE *yyTraceFILE = 0;
+static char *yyTracePrompt = 0;
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* 
+** Turn parser tracing on by giving a stream to which to write the trace
+** and a prompt to preface each trace message.  Tracing is turned off
+** by making either argument NULL 
+**
+** Inputs:
+** <ul>
+** <li> A FILE* to which trace output should be written.
+**      If NULL, then tracing is turned off.
+** <li> A prefix string written at the beginning of every
+**      line of trace output.  If NULL, then tracing is
+**      turned off.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
+  yyTraceFILE = TraceFILE;
+  yyTracePrompt = zTracePrompt;
+  if( yyTraceFILE==0 ) yyTracePrompt = 0;
+  else if( yyTracePrompt==0 ) yyTraceFILE = 0;
+}
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing shifts, the names of all terminals and nonterminals
+** are required.  The following table supplies these names */
+static const char *const yyTokenName[] = { 
+%%
+};
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing reduce actions, the names of all rules are required.
+*/
+static const char *const yyRuleName[] = {
+%%
+};
+#endif /* NDEBUG */
+
+
+#if YYSTACKDEPTH<=0
+/*
+** Try to increase the size of the parser stack.  Return the number
+** of errors.  Return 0 on success.
+*/
+static int yyGrowStack(yyParser *p){
+  int newSize;
+  int idx;
+  yyStackEntry *pNew;
+
+  newSize = p->yystksz*2 + 100;
+  idx = p->yytos ? (int)(p->yytos - p->yystack) : 0;
+  if( p->yystack==&p->yystk0 ){
+    pNew = malloc(newSize*sizeof(pNew[0]));
+    if( pNew ) pNew[0] = p->yystk0;
+  }else{
+    pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+  }
+  if( pNew ){
+    p->yystack = pNew;
+    p->yytos = &p->yystack[idx];
+#ifndef NDEBUG
+    if( yyTraceFILE ){
+      fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
+              yyTracePrompt, p->yystksz, newSize);
+    }
+#endif
+    p->yystksz = newSize;
+  }
+  return pNew==0; 
+}
+#endif
+
+/* Datatype of the argument to the memory allocated passed as the
+** second argument to ParseAlloc() below.  This can be changed by
+** putting an appropriate #define in the %include section of the input
+** grammar.
+*/
+#ifndef YYMALLOCARGTYPE
+# define YYMALLOCARGTYPE size_t
+#endif
+
+/* 
+** This function allocates a new parser.
+** The only argument is a pointer to a function which works like
+** malloc.
+**
+** Inputs:
+** A pointer to the function used to allocate memory.
+**
+** Outputs:
+** A pointer to a parser.  This pointer is used in subsequent calls
+** to Parse and ParseFree.
+*/
+void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){
+  yyParser *pParser;
+  pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
+  if( pParser ){
+#ifdef YYTRACKMAXSTACKDEPTH
+    pParser->yyhwm = 0;
+#endif
+#if YYSTACKDEPTH<=0
+    pParser->yytos = NULL;
+    pParser->yystack = NULL;
+    pParser->yystksz = 0;
+    if( yyGrowStack(pParser) ){
+      pParser->yystack = &pParser->yystk0;
+      pParser->yystksz = 1;
+    }
+#endif
+#ifndef YYNOERRORRECOVERY
+    pParser->yyerrcnt = -1;
+#endif
+    pParser->yytos = pParser->yystack;
+    pParser->yystack[0].stateno = 0;
+    pParser->yystack[0].major = 0;
+  }
+  return pParser;
+}
+
+/* The following function deletes the "minor type" or semantic value
+** associated with a symbol.  The symbol can be either a terminal
+** or nonterminal. "yymajor" is the symbol code, and "yypminor" is
+** a pointer to the value to be deleted.  The code used to do the 
+** deletions is derived from the %destructor and/or %token_destructor
+** directives of the input grammar.
+*/
+static void yy_destructor(
+  yyParser *yypParser,    /* The parser */
+  YYCODETYPE yymajor,     /* Type code for object to destroy */
+  YYMINORTYPE *yypminor   /* The object to be destroyed */
+){
+  ParseARG_FETCH;
+  switch( yymajor ){
+    /* Here is inserted the actions which take place when a
+    ** terminal or non-terminal is destroyed.  This can happen
+    ** when the symbol is popped from the stack during a
+    ** reduce or during error processing or when a parser is 
+    ** being destroyed before it is finished parsing.
+    **
+    ** Note: during a reduce, the only symbols destroyed are those
+    ** which appear on the RHS of the rule, but which are *not* used
+    ** inside the C code.
+    */
+/********* Begin destructor definitions ***************************************/
+%%
+/********* End destructor definitions *****************************************/
+    default:  break;   /* If no destructor action specified: do nothing */
+  }
+}
+
+/*
+** Pop the parser's stack once.
+**
+** If there is a destructor routine associated with the token which
+** is popped from the stack, then call it.
+*/
+static void yy_pop_parser_stack(yyParser *pParser){
+  yyStackEntry *yytos;
+  assert( pParser->yytos!=0 );
+  assert( pParser->yytos > pParser->yystack );
+  yytos = pParser->yytos--;
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sPopping %s\n",
+      yyTracePrompt,
+      yyTokenName[yytos->major]);
+  }
+#endif
+  yy_destructor(pParser, yytos->major, &yytos->minor);
+}
+
+/* 
+** Deallocate and destroy a parser.  Destructors are called for
+** all stack elements before shutting the parser down.
+**
+** If the YYPARSEFREENEVERNULL macro exists (for example because it
+** is defined in a %include section of the input grammar) then it is
+** assumed that the input pointer is never NULL.
+*/
+void ParseFree(
+  void *p,                    /* The parser to be deleted */
+  void (*freeProc)(void*)     /* Function used to reclaim memory */
+){
+  yyParser *pParser = (yyParser*)p;
+#ifndef YYPARSEFREENEVERNULL
+  if( pParser==0 ) return;
+#endif
+  while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
+#if YYSTACKDEPTH<=0
+  if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
+#endif
+  (*freeProc)((void*)pParser);
+}
+
+/*
+** Return the peak depth of the stack for a parser.
+*/
+#ifdef YYTRACKMAXSTACKDEPTH
+int ParseStackPeak(void *p){
+  yyParser *pParser = (yyParser*)p;
+  return pParser->yyhwm;
+}
+#endif
+
+/*
+** Find the appropriate action for a parser given the terminal
+** look-ahead token iLookAhead.
+*/
+static unsigned int yy_find_shift_action(
+  yyParser *pParser,        /* The parser */
+  YYCODETYPE iLookAhead     /* The look-ahead token */
+){
+  int i;
+  int stateno = pParser->yytos->stateno;
+  if( stateno>=YY_MIN_REDUCE ) return stateno;
+  assert( stateno <= YY_SHIFT_COUNT );
+  do{
+    i = yy_shift_ofst[stateno];
+    assert( iLookAhead!=YYNOCODE );
+    i += iLookAhead;
+    if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+#ifdef YYFALLBACK
+      YYCODETYPE iFallback;            /* Fallback token */
+      if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+             && (iFallback = yyFallback[iLookAhead])!=0 ){
+#ifndef NDEBUG
+        if( yyTraceFILE ){
+          fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+             yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+        }
+#endif
+        assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
+        iLookAhead = iFallback;
+        continue;
+      }
+#endif
+#ifdef YYWILDCARD
+      {
+        int j = i - iLookAhead + YYWILDCARD;
+        if( 
+#if YY_SHIFT_MIN+YYWILDCARD<0
+          j>=0 &&
+#endif
+#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
+          j<YY_ACTTAB_COUNT &&
+#endif
+          yy_lookahead[j]==YYWILDCARD && iLookAhead>0
+        ){
+#ifndef NDEBUG
+          if( yyTraceFILE ){
+            fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
+               yyTracePrompt, yyTokenName[iLookAhead],
+               yyTokenName[YYWILDCARD]);
+          }
+#endif /* NDEBUG */
+          return yy_action[j];
+        }
+      }
+#endif /* YYWILDCARD */
+      return yy_default[stateno];
+    }else{
+      return yy_action[i];
+    }
+  }while(1);
+}
+
+/*
+** Find the appropriate action for a parser given the non-terminal
+** look-ahead token iLookAhead.
+*/
+static int yy_find_reduce_action(
+  int stateno,              /* Current state number */
+  YYCODETYPE iLookAhead     /* The look-ahead token */
+){
+  int i;
+#ifdef YYERRORSYMBOL
+  if( stateno>YY_REDUCE_COUNT ){
+    return yy_default[stateno];
+  }
+#else
+  assert( stateno<=YY_REDUCE_COUNT );
+#endif
+  i = yy_reduce_ofst[stateno];
+  assert( i!=YY_REDUCE_USE_DFLT );
+  assert( iLookAhead!=YYNOCODE );
+  i += iLookAhead;
+#ifdef YYERRORSYMBOL
+  if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+    return yy_default[stateno];
+  }
+#else
+  assert( i>=0 && i<YY_ACTTAB_COUNT );
+  assert( yy_lookahead[i]==iLookAhead );
+#endif
+  return yy_action[i];
+}
+
+/*
+** The following routine is called if the stack overflows.
+*/
+static void yyStackOverflow(yyParser *yypParser){
+   ParseARG_FETCH;
+   yypParser->yytos--;
+#ifndef NDEBUG
+   if( yyTraceFILE ){
+     fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+   }
+#endif
+   while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
+   /* Here code is inserted which will execute if the parser
+   ** stack every overflows */
+/******** Begin %stack_overflow code ******************************************/
+%%
+/******** End %stack_overflow code ********************************************/
+   ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
+}
+
+/*
+** Print tracing information for a SHIFT action
+*/
+#ifndef NDEBUG
+static void yyTraceShift(yyParser *yypParser, int yyNewState){
+  if( yyTraceFILE ){
+    if( yyNewState<YYNSTATE ){
+      fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n",
+         yyTracePrompt,yyTokenName[yypParser->yytos->major],
+         yyNewState);
+    }else{
+      fprintf(yyTraceFILE,"%sShift '%s'\n",
+         yyTracePrompt,yyTokenName[yypParser->yytos->major]);
+    }
+  }
+}
+#else
+# define yyTraceShift(X,Y)
+#endif
+
+/*
+** Perform a shift action.
+*/
+static void yy_shift(
+  yyParser *yypParser,          /* The parser to be shifted */
+  int yyNewState,               /* The new state to shift in */
+  int yyMajor,                  /* The major token to shift in */
+  ParseTOKENTYPE yyMinor        /* The minor token to shift in */
+){
+  yyStackEntry *yytos;
+  yypParser->yytos++;
+#ifdef YYTRACKMAXSTACKDEPTH
+  if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
+    yypParser->yyhwm++;
+    assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
+  }
+#endif
+#if YYSTACKDEPTH>0 
+  if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){
+    yyStackOverflow(yypParser);
+    return;
+  }
+#else
+  if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){
+    if( yyGrowStack(yypParser) ){
+      yyStackOverflow(yypParser);
+      return;
+    }
+  }
+#endif
+  if( yyNewState > YY_MAX_SHIFT ){
+    yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
+  }
+  yytos = yypParser->yytos;
+  yytos->stateno = (YYACTIONTYPE)yyNewState;
+  yytos->major = (YYCODETYPE)yyMajor;
+  yytos->minor.yy0 = yyMinor;
+  yyTraceShift(yypParser, yyNewState);
+}
+
+/* The following table contains information about every rule that
+** is used during the reduce.
+*/
+static const struct {
+  YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
+  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
+} yyRuleInfo[] = {
+%%
+};
+
+static void yy_accept(yyParser*);  /* Forward Declaration */
+
+/*
+** Perform a reduce action and the shift that must immediately
+** follow the reduce.
+*/
+static void yy_reduce(
+  yyParser *yypParser,         /* The parser */
+  unsigned int yyruleno        /* Number of the rule by which to reduce */
+){
+  int yygoto;                     /* The next state */
+  int yyact;                      /* The next action */
+  yyStackEntry *yymsp;            /* The top of the parser's stack */
+  int yysize;                     /* Amount to pop the stack */
+  ParseARG_FETCH;
+  yymsp = yypParser->yytos;
+#ifndef NDEBUG
+  if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
+    yysize = yyRuleInfo[yyruleno].nrhs;
+    fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt,
+      yyRuleName[yyruleno], yymsp[-yysize].stateno);
+  }
+#endif /* NDEBUG */
+
+  /* Check that the stack is large enough to grow by a single entry
+  ** if the RHS of the rule is empty.  This ensures that there is room
+  ** enough on the stack to push the LHS value */
+  if( yyRuleInfo[yyruleno].nrhs==0 ){
+#ifdef YYTRACKMAXSTACKDEPTH
+    if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
+      yypParser->yyhwm++;
+      assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack));
+    }
+#endif
+#if YYSTACKDEPTH>0 
+    if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){
+      yyStackOverflow(yypParser);
+      return;
+    }
+#else
+    if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
+      if( yyGrowStack(yypParser) ){
+        yyStackOverflow(yypParser);
+        return;
+      }
+      yymsp = yypParser->yytos;
+    }
+#endif
+  }
+
+  switch( yyruleno ){
+  /* Beginning here are the reduction cases.  A typical example
+  ** follows:
+  **   case 0:
+  **  #line <lineno> <grammarfile>
+  **     { ... }           // User supplied code
+  **  #line <lineno> <thisfile>
+  **     break;
+  */
+/********** Begin reduce actions **********************************************/
+%%
+/********** End reduce actions ************************************************/
+  };
+  assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
+  yygoto = yyRuleInfo[yyruleno].lhs;
+  yysize = yyRuleInfo[yyruleno].nrhs;
+  yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
+  if( yyact <= YY_MAX_SHIFTREDUCE ){
+    if( yyact>YY_MAX_SHIFT ){
+      yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
+    }
+    yymsp -= yysize-1;
+    yypParser->yytos = yymsp;
+    yymsp->stateno = (YYACTIONTYPE)yyact;
+    yymsp->major = (YYCODETYPE)yygoto;
+    yyTraceShift(yypParser, yyact);
+  }else{
+    assert( yyact == YY_ACCEPT_ACTION );
+    yypParser->yytos -= yysize;
+    yy_accept(yypParser);
+  }
+}
+
+/*
+** The following code executes when the parse fails
+*/
+#ifndef YYNOERRORRECOVERY
+static void yy_parse_failed(
+  yyParser *yypParser           /* The parser */
+){
+  ParseARG_FETCH;
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
+  }
+#endif
+  while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
+  /* Here code is inserted which will be executed whenever the
+  ** parser fails */
+/************ Begin %parse_failure code ***************************************/
+%%
+/************ End %parse_failure code *****************************************/
+  ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+#endif /* YYNOERRORRECOVERY */
+
+/*
+** The following code executes when a syntax error first occurs.
+*/
+static void yy_syntax_error(
+  yyParser *yypParser,           /* The parser */
+  int yymajor,                   /* The major type of the error token */
+  ParseTOKENTYPE yyminor         /* The minor type of the error token */
+){
+  ParseARG_FETCH;
+#define TOKEN yyminor
+/************ Begin %syntax_error code ****************************************/
+%%
+/************ End %syntax_error code ******************************************/
+  ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following is executed when the parser accepts
+*/
+static void yy_accept(
+  yyParser *yypParser           /* The parser */
+){
+  ParseARG_FETCH;
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
+  }
+#endif
+#ifndef YYNOERRORRECOVERY
+  yypParser->yyerrcnt = -1;
+#endif
+  assert( yypParser->yytos==yypParser->yystack );
+  /* Here code is inserted which will be executed whenever the
+  ** parser accepts */
+/*********** Begin %parse_accept code *****************************************/
+%%
+/*********** End %parse_accept code *******************************************/
+  ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/* The main parser program.
+** The first argument is a pointer to a structure obtained from
+** "ParseAlloc" which describes the current state of the parser.
+** The second argument is the major token number.  The third is
+** the minor token.  The fourth optional argument is whatever the
+** user wants (and specified in the grammar) and is available for
+** use by the action routines.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser (an opaque structure.)
+** <li> The major token number.
+** <li> The minor token number.
+** <li> An option argument of a grammar-specified type.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void Parse(
+  void *yyp,                   /* The parser */
+  int yymajor,                 /* The major token code number */
+  ParseTOKENTYPE yyminor       /* The value for the token */
+  ParseARG_PDECL               /* Optional %extra_argument parameter */
+){
+  YYMINORTYPE yyminorunion;
+  unsigned int yyact;   /* The parser action. */
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+  int yyendofinput;     /* True if we are at the end of input */
+#endif
+#ifdef YYERRORSYMBOL
+  int yyerrorhit = 0;   /* True if yymajor has invoked an error */
+#endif
+  yyParser *yypParser;  /* The parser */
+
+  yypParser = (yyParser*)yyp;
+  assert( yypParser->yytos!=0 );
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+  yyendofinput = (yymajor==0);
+#endif
+  ParseARG_STORE;
+
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]);
+  }
+#endif
+
+  do{
+    yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
+    if( yyact <= YY_MAX_SHIFTREDUCE ){
+      yy_shift(yypParser,yyact,yymajor,yyminor);
+#ifndef YYNOERRORRECOVERY
+      yypParser->yyerrcnt--;
+#endif
+      yymajor = YYNOCODE;
+    }else if( yyact <= YY_MAX_REDUCE ){
+      yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
+    }else{
+      assert( yyact == YY_ERROR_ACTION );
+      yyminorunion.yy0 = yyminor;
+#ifdef YYERRORSYMBOL
+      int yymx;
+#endif
+#ifndef NDEBUG
+      if( yyTraceFILE ){
+        fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
+      }
+#endif
+#ifdef YYERRORSYMBOL
+      /* A syntax error has occurred.
+      ** The response to an error depends upon whether or not the
+      ** grammar defines an error token "ERROR".  
+      **
+      ** This is what we do if the grammar does define ERROR:
+      **
+      **  * Call the %syntax_error function.
+      **
+      **  * Begin popping the stack until we enter a state where
+      **    it is legal to shift the error symbol, then shift
+      **    the error symbol.
+      **
+      **  * Set the error count to three.
+      **
+      **  * Begin accepting and shifting new tokens.  No new error
+      **    processing will occur until three tokens have been
+      **    shifted successfully.
+      **
+      */
+      if( yypParser->yyerrcnt<0 ){
+        yy_syntax_error(yypParser,yymajor,yyminor);
+      }
+      yymx = yypParser->yytos->major;
+      if( yymx==YYERRORSYMBOL || yyerrorhit ){
+#ifndef NDEBUG
+        if( yyTraceFILE ){
+          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
+             yyTracePrompt,yyTokenName[yymajor]);
+        }
+#endif
+        yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
+        yymajor = YYNOCODE;
+      }else{
+        while( yypParser->yytos >= yypParser->yystack
+            && yymx != YYERRORSYMBOL
+            && (yyact = yy_find_reduce_action(
+                        yypParser->yytos->stateno,
+                        YYERRORSYMBOL)) >= YY_MIN_REDUCE
+        ){
+          yy_pop_parser_stack(yypParser);
+        }
+        if( yypParser->yytos < yypParser->yystack || yymajor==0 ){
+          yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+          yy_parse_failed(yypParser);
+#ifndef YYNOERRORRECOVERY
+          yypParser->yyerrcnt = -1;
+#endif
+          yymajor = YYNOCODE;
+        }else if( yymx!=YYERRORSYMBOL ){
+          yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor);
+        }
+      }
+      yypParser->yyerrcnt = 3;
+      yyerrorhit = 1;
+#elif defined(YYNOERRORRECOVERY)
+      /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
+      ** do any kind of error recovery.  Instead, simply invoke the syntax
+      ** error routine and continue going as if nothing had happened.
+      **
+      ** Applications can set this macro (for example inside %include) if
+      ** they intend to abandon the parse upon the first syntax error seen.
+      */
+      yy_syntax_error(yypParser,yymajor, yyminor);
+      yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+      yymajor = YYNOCODE;
+      
+#else  /* YYERRORSYMBOL is not defined */
+      /* This is what we do if the grammar does not define ERROR:
+      **
+      **  * Report an error message, and throw away the input token.
+      **
+      **  * If the input token is $, then fail the parse.
+      **
+      ** As before, subsequent error messages are suppressed until
+      ** three input tokens have been successfully shifted.
+      */
+      if( yypParser->yyerrcnt<=0 ){
+        yy_syntax_error(yypParser,yymajor, yyminor);
+      }
+      yypParser->yyerrcnt = 3;
+      yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+      if( yyendofinput ){
+        yy_parse_failed(yypParser);
+#ifndef YYNOERRORRECOVERY
+        yypParser->yyerrcnt = -1;
+#endif
+      }
+      yymajor = YYNOCODE;
+#endif
+    }
+  }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack );
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    yyStackEntry *i;
+    char cDiv = '[';
+    fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt);
+    for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){
+      fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]);
+      cDiv = ' ';
+    }
+    fprintf(yyTraceFILE,"]\n");
+  }
+#endif
+  return;
+}
diff --git a/src/argtable3.c b/src/argtable3.c
new file mode 100755 (executable)
index 0000000..2bc0121
--- /dev/null
@@ -0,0 +1,4955 @@
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *     * Redistributions of source code must retain the above copyright\r
+ *       notice, this list of conditions and the following disclaimer.\r
+ *     * Redistributions in binary form must reproduce the above copyright\r
+ *       notice, this list of conditions and the following disclaimer in the\r
+ *       documentation and/or other materials provided with the distribution.\r
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors\r
+ *       may be used to endorse or promote products derived from this software\r
+ *       without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 2013 Tom G. Huang\r
+ * <tomghuang@gmail.com>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *     * Redistributions of source code must retain the above copyright\r
+ *       notice, this list of conditions and the following disclaimer.\r
+ *     * Redistributions in binary form must reproduce the above copyright\r
+ *       notice, this list of conditions and the following disclaimer in the\r
+ *       documentation and/or other materials provided with the distribution.\r
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors\r
+ *       may be used to endorse or promote products derived from this software\r
+ *       without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#ifndef ARG_UTILS_H\r
+#define ARG_UTILS_H\r
+\r
+#define ARG_ENABLE_TRACE 0\r
+#define ARG_ENABLE_LOG 1\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+enum\r
+{\r
+    EMINCOUNT = 1,\r
+    EMAXCOUNT,\r
+    EBADINT,\r
+    EOVERFLOW,\r
+    EBADDOUBLE,\r
+    EBADDATE,\r
+    EREGNOMATCH\r
+};\r
+\r
+\r
+#if defined(_MSC_VER)\r
+#define ARG_TRACE(x) \\r
+    __pragma(warning(push)) \\r
+    __pragma(warning(disable:4127)) \\r
+    do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0) \\r
+    __pragma(warning(pop))\r
+\r
+#define ARG_LOG(x) \\r
+    __pragma(warning(push)) \\r
+    __pragma(warning(disable:4127)) \\r
+    do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0) \\r
+    __pragma(warning(pop))\r
+#else\r
+#define ARG_TRACE(x) \\r
+    do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0)\r
+\r
+#define ARG_LOG(x) \\r
+    do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0)\r
+#endif \r
+\r
+extern void dbg_printf(const char *fmt, ...);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif\r
+\r
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *     * Redistributions of source code must retain the above copyright\r
+ *       notice, this list of conditions and the following disclaimer.\r
+ *     * Redistributions in binary form must reproduce the above copyright\r
+ *       notice, this list of conditions and the following disclaimer in the\r
+ *       documentation and/or other materials provided with the distribution.\r
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors\r
+ *       may be used to endorse or promote products derived from this software\r
+ *       without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include <stdarg.h>\r
+#include <stdio.h>\r
+\r
+\r
+void dbg_printf(const char *fmt, ...)\r
+{\r
+    va_list args;\r
+    va_start(args, fmt);\r
+    vfprintf(stderr, fmt, args);\r
+    va_end(args);\r
+}\r
+\r
+/*     $Id: getopt.h,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */\r
+/*     $OpenBSD: getopt.h,v 1.1 2002/12/03 20:24:29 millert Exp $      */\r
+/*     $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $    */\r
+\r
+/*-\r
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.\r
+ * All rights reserved.\r
+ *\r
+ * This code is derived from software contributed to The NetBSD Foundation\r
+ * by Dieter Baron and Thomas Klausner.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ *    notice, this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ *    notice, this list of conditions and the following disclaimer in the\r
+ *    documentation and/or other materials provided with the distribution.\r
+ * 3. All advertising materials mentioning features or use of this software\r
+ *    must display the following acknowledgement:\r
+ *        This product includes software developed by the NetBSD\r
+ *        Foundation, Inc. and its contributors.\r
+ * 4. Neither the name of The NetBSD Foundation nor the names of its\r
+ *    contributors may be used to endorse or promote products derived\r
+ *    from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\r
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\r
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+#ifndef _GETOPT_H_\r
+#define _GETOPT_H_\r
+\r
+#if 0\r
+#include <sys/cdefs.h>\r
+#endif\r
+\r
+/*\r
+ * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions\r
+ */\r
+#define no_argument        0\r
+#define required_argument  1\r
+#define optional_argument  2\r
+\r
+struct option {\r
+       /* name of long option */\r
+       const char *name;\r
+       /*\r
+        * one of no_argument, required_argument, and optional_argument:\r
+        * whether option takes an argument\r
+        */\r
+       int has_arg;\r
+       /* if not NULL, set *flag to val when option found */\r
+       int *flag;\r
+       /* if flag not NULL, value to set *flag to; else return value */\r
+       int val;\r
+};\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+int     getopt_long(int, char * const *, const char *,\r
+           const struct option *, int *);\r
+int     getopt_long_only(int, char * const *, const char *,\r
+           const struct option *, int *);\r
+#ifndef _GETOPT_DEFINED\r
+#define _GETOPT_DEFINED\r
+int     getopt(int, char * const *, const char *);\r
+int     getsubopt(char **, char * const *, char **);\r
+\r
+extern   char *optarg;                  /* getopt(3) external variables */\r
+extern   int opterr;\r
+extern   int optind;\r
+extern   int optopt;\r
+extern   int optreset;\r
+extern   char *suboptarg;               /* getsubopt(3) external variable */\r
+#endif /* _GETOPT_DEFINED */\r
\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+#endif /* !_GETOPT_H_ */\r
+/*     $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $        */\r
+/*     $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $    */\r
+/*     $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $      */\r
+\r
+/*\r
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>\r
+ *\r
+ * Permission to use, copy, modify, and distribute this software for any\r
+ * purpose with or without fee is hereby granted, provided that the above\r
+ * copyright notice and this permission notice appear in all copies.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\r
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\r
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\r
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\r
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\r
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
+ *\r
+ * Sponsored in part by the Defense Advanced Research Projects\r
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force\r
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.\r
+ */\r
+\r
+#ifndef lint\r
+static const char rcsid[]="$Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $";\r
+#endif /* lint */\r
+/*-\r
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.\r
+ * All rights reserved.\r
+ *\r
+ * This code is derived from software contributed to The NetBSD Foundation\r
+ * by Dieter Baron and Thomas Klausner.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ *    notice, this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ *    notice, this list of conditions and the following disclaimer in the\r
+ *    documentation and/or other materials provided with the distribution.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\r
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\r
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+#if 0\r
+#include <err.h>\r
+#endif\r
+#include <errno.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+\r
+#define        REPLACE_GETOPT          /* use this getopt as the system getopt(3) */\r
+\r
+#ifdef REPLACE_GETOPT\r
+int    opterr = 1;             /* if error message should be printed */\r
+int    optind = 1;             /* index into parent argv vector */\r
+int    optopt = '?';           /* character checked for validity */\r
+int    optreset;               /* reset getopt */\r
+char    *optarg;               /* argument associated with option */\r
+#endif\r
+\r
+#define PRINT_ERROR    ((opterr) && (*options != ':'))\r
+\r
+#define FLAG_PERMUTE   0x01    /* permute non-options to the end of argv */\r
+#define FLAG_ALLARGS   0x02    /* treat non-options as args to option "-1" */\r
+#define FLAG_LONGONLY  0x04    /* operate as getopt_long_only */\r
+\r
+/* return values */\r
+#define        BADCH           (int)'?'\r
+#define        BADARG          ((*options == ':') ? (int)':' : (int)'?')\r
+#define        INORDER         (int)1\r
+\r
+#define        EMSG            ""\r
+\r
+static int getopt_internal(int, char * const *, const char *,\r
+                          const struct option *, int *, int);\r
+static int parse_long_options(char * const *, const char *,\r
+                             const struct option *, int *, int);\r
+static int gcd(int, int);\r
+static void permute_args(int, int, int, char * const *);\r
+\r
+static char *place = EMSG; /* option letter processing */\r
+\r
+/* XXX: set optreset to 1 rather than these two */\r
+static int nonopt_start = -1; /* first non option argument (for permute) */\r
+static int nonopt_end = -1;   /* first option after non options (for permute) */\r
+\r
+/* Error messages */\r
+static const char recargchar[] = "option requires an argument -- %c";\r
+static const char recargstring[] = "option requires an argument -- %s";\r
+static const char ambig[] = "ambiguous option -- %.*s";\r
+static const char noarg[] = "option doesn't take an argument -- %.*s";\r
+static const char illoptchar[] = "unknown option -- %c";\r
+static const char illoptstring[] = "unknown option -- %s";\r
+\r
+\r
+\r
+#ifdef _WIN32\r
+\r
+/* Windows needs warnx().  We change the definition though:\r
+ *  1. (another) global is defined, opterrmsg, which holds the error message\r
+ *  2. errors are always printed out on stderr w/o the program name\r
+ * Note that opterrmsg always gets set no matter what opterr is set to.  The\r
+ * error message will not be printed if opterr is 0 as usual.\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <stdarg.h>\r
+\r
+extern char opterrmsg[128];\r
+char opterrmsg[128]; /* buffer for the last error message */\r
+\r
+static void warnx(const char *fmt, ...)\r
+{\r
+       va_list ap;\r
+       va_start(ap, fmt);\r
+    /*\r
+    Make sure opterrmsg is always zero-terminated despite the _vsnprintf()\r
+    implementation specifics and manually suppress the warning.\r
+    */\r
+    memset(opterrmsg, 0, sizeof opterrmsg);\r
+       if (fmt != NULL)\r
+               _vsnprintf(opterrmsg, sizeof(opterrmsg) - 1, fmt, ap);\r
+       va_end(ap);\r
+\r
+#pragma warning(suppress: 6053)\r
+       fprintf(stderr, "%s\n", opterrmsg);\r
+}\r
+\r
+#else\r
+#include <err.h>\r
+#endif /*_WIN32*/\r
+\r
+\r
+/*\r
+ * Compute the greatest common divisor of a and b.\r
+ */\r
+static int\r
+gcd(int a, int b)\r
+{\r
+       int c;\r
+\r
+       c = a % b;\r
+       while (c != 0) {\r
+               a = b;\r
+               b = c;\r
+               c = a % b;\r
+       }\r
+\r
+       return (b);\r
+}\r
+\r
+/*\r
+ * Exchange the block from nonopt_start to nonopt_end with the block\r
+ * from nonopt_end to opt_end (keeping the same order of arguments\r
+ * in each block).\r
+ */\r
+static void\r
+permute_args(int panonopt_start, int panonopt_end, int opt_end,\r
+       char * const *nargv)\r
+{\r
+       int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;\r
+       char *swap;\r
+\r
+       /*\r
+        * compute lengths of blocks and number and size of cycles\r
+        */\r
+       nnonopts = panonopt_end - panonopt_start;\r
+       nopts = opt_end - panonopt_end;\r
+       ncycle = gcd(nnonopts, nopts);\r
+       cyclelen = (opt_end - panonopt_start) / ncycle;\r
+\r
+       for (i = 0; i < ncycle; i++) {\r
+               cstart = panonopt_end+i;\r
+               pos = cstart;\r
+               for (j = 0; j < cyclelen; j++) {\r
+                       if (pos >= panonopt_end)\r
+                               pos -= nnonopts;\r
+                       else\r
+                               pos += nopts;\r
+                       swap = nargv[pos];\r
+                       /* LINTED const cast */\r
+                       ((char **) nargv)[pos] = nargv[cstart];\r
+                       /* LINTED const cast */\r
+                       ((char **)nargv)[cstart] = swap;\r
+               }\r
+       }\r
+}\r
+\r
+/*\r
+ * parse_long_options --\r
+ *     Parse long options in argc/argv argument vector.\r
+ * Returns -1 if short_too is set and the option does not match long_options.\r
+ */\r
+static int\r
+parse_long_options(char * const *nargv, const char *options,\r
+       const struct option *long_options, int *idx, int short_too)\r
+{\r
+       char *current_argv, *has_equal;\r
+       size_t current_argv_len;\r
+       int i, match;\r
+\r
+       current_argv = place;\r
+       match = -1;\r
+\r
+       optind++;\r
+\r
+       if ((has_equal = strchr(current_argv, '=')) != NULL) {\r
+               /* argument found (--option=arg) */\r
+               current_argv_len = has_equal - current_argv;\r
+               has_equal++;\r
+       } else\r
+               current_argv_len = strlen(current_argv);\r
+\r
+       for (i = 0; long_options[i].name; i++) {\r
+               /* find matching long option */\r
+               if (strncmp(current_argv, long_options[i].name,\r
+                   current_argv_len))\r
+                       continue;\r
+\r
+               if (strlen(long_options[i].name) == current_argv_len) {\r
+                       /* exact match */\r
+                       match = i;\r
+                       break;\r
+               }\r
+               /*\r
+                * If this is a known short option, don't allow\r
+                * a partial match of a single character.\r
+                */\r
+               if (short_too && current_argv_len == 1)\r
+                       continue;\r
+\r
+               if (match == -1)        /* partial match */\r
+                       match = i;\r
+               else {\r
+                       /* ambiguous abbreviation */\r
+                       if (PRINT_ERROR)\r
+                               warnx(ambig, (int)current_argv_len,\r
+                                    current_argv);\r
+                       optopt = 0;\r
+                       return (BADCH);\r
+               }\r
+       }\r
+       if (match != -1) {              /* option found */\r
+               if (long_options[match].has_arg == no_argument\r
+                   && has_equal) {\r
+                       if (PRINT_ERROR)\r
+                               warnx(noarg, (int)current_argv_len,\r
+                                    current_argv);\r
+                       /*\r
+                        * XXX: GNU sets optopt to val regardless of flag\r
+                        */\r
+                       if (long_options[match].flag == NULL)\r
+                               optopt = long_options[match].val;\r
+                       else\r
+                               optopt = 0;\r
+                       return (BADARG);\r
+               }\r
+               if (long_options[match].has_arg == required_argument ||\r
+                   long_options[match].has_arg == optional_argument) {\r
+                       if (has_equal)\r
+                               optarg = has_equal;\r
+                       else if (long_options[match].has_arg ==\r
+                           required_argument) {\r
+                               /*\r
+                                * optional argument doesn't use next nargv\r
+                                */\r
+                               optarg = nargv[optind++];\r
+                       }\r
+               }\r
+               if ((long_options[match].has_arg == required_argument)\r
+                   && (optarg == NULL)) {\r
+                       /*\r
+                        * Missing argument; leading ':' indicates no error\r
+                        * should be generated.\r
+                        */\r
+                       if (PRINT_ERROR)\r
+                               warnx(recargstring,\r
+                                   current_argv);\r
+                       /*\r
+                        * XXX: GNU sets optopt to val regardless of flag\r
+                        */\r
+                       if (long_options[match].flag == NULL)\r
+                               optopt = long_options[match].val;\r
+                       else\r
+                               optopt = 0;\r
+                       --optind;\r
+                       return (BADARG);\r
+               }\r
+       } else {                        /* unknown option */\r
+               if (short_too) {\r
+                       --optind;\r
+                       return (-1);\r
+               }\r
+               if (PRINT_ERROR)\r
+                       warnx(illoptstring, current_argv);\r
+               optopt = 0;\r
+               return (BADCH);\r
+       }\r
+       if (idx)\r
+               *idx = match;\r
+       if (long_options[match].flag) {\r
+               *long_options[match].flag = long_options[match].val;\r
+               return (0);\r
+       } else\r
+               return (long_options[match].val);\r
+}\r
+\r
+/*\r
+ * getopt_internal --\r
+ *     Parse argc/argv argument vector.  Called by user level routines.\r
+ */\r
+static int\r
+getopt_internal(int nargc, char * const *nargv, const char *options,\r
+       const struct option *long_options, int *idx, int flags)\r
+{\r
+       char *oli;                              /* option letter list index */\r
+       int optchar, short_too;\r
+       static int posixly_correct = -1;\r
+\r
+       if (options == NULL)\r
+               return (-1);\r
+\r
+       /*\r
+        * Disable GNU extensions if POSIXLY_CORRECT is set or options\r
+        * string begins with a '+'.\r
+        */\r
+       if (posixly_correct == -1)\r
+               posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);\r
+       if (posixly_correct || *options == '+')\r
+               flags &= ~FLAG_PERMUTE;\r
+       else if (*options == '-')\r
+               flags |= FLAG_ALLARGS;\r
+       if (*options == '+' || *options == '-')\r
+               options++;\r
+\r
+       /*\r
+        * XXX Some GNU programs (like cvs) set optind to 0 instead of\r
+        * XXX using optreset.  Work around this braindamage.\r
+        */\r
+       if (optind == 0)\r
+               optind = optreset = 1;\r
+\r
+       optarg = NULL;\r
+       if (optreset)\r
+               nonopt_start = nonopt_end = -1;\r
+start:\r
+       if (optreset || !*place) {              /* update scanning pointer */\r
+               optreset = 0;\r
+               if (optind >= nargc) {          /* end of argument vector */\r
+                       place = EMSG;\r
+                       if (nonopt_end != -1) {\r
+                               /* do permutation, if we have to */\r
+                               permute_args(nonopt_start, nonopt_end,\r
+                                   optind, nargv);\r
+                               optind -= nonopt_end - nonopt_start;\r
+                       }\r
+                       else if (nonopt_start != -1) {\r
+                               /*\r
+                                * If we skipped non-options, set optind\r
+                                * to the first of them.\r
+                                */\r
+                               optind = nonopt_start;\r
+                       }\r
+                       nonopt_start = nonopt_end = -1;\r
+                       return (-1);\r
+               }\r
+               if (*(place = nargv[optind]) != '-' ||\r
+                   (place[1] == '\0' && strchr(options, '-') == NULL)) {\r
+                       place = EMSG;           /* found non-option */\r
+                       if (flags & FLAG_ALLARGS) {\r
+                               /*\r
+                                * GNU extension:\r
+                                * return non-option as argument to option 1\r
+                                */\r
+                               optarg = nargv[optind++];\r
+                               return (INORDER);\r
+                       }\r
+                       if (!(flags & FLAG_PERMUTE)) {\r
+                               /*\r
+                                * If no permutation wanted, stop parsing\r
+                                * at first non-option.\r
+                                */\r
+                               return (-1);\r
+                       }\r
+                       /* do permutation */\r
+                       if (nonopt_start == -1)\r
+                               nonopt_start = optind;\r
+                       else if (nonopt_end != -1) {\r
+                               permute_args(nonopt_start, nonopt_end,\r
+                                   optind, nargv);\r
+                               nonopt_start = optind -\r
+                                   (nonopt_end - nonopt_start);\r
+                               nonopt_end = -1;\r
+                       }\r
+                       optind++;\r
+                       /* process next argument */\r
+                       goto start;\r
+               }\r
+               if (nonopt_start != -1 && nonopt_end == -1)\r
+                       nonopt_end = optind;\r
+\r
+               /*\r
+                * If we have "-" do nothing, if "--" we are done.\r
+                */\r
+               if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {\r
+                       optind++;\r
+                       place = EMSG;\r
+                       /*\r
+                        * We found an option (--), so if we skipped\r
+                        * non-options, we have to permute.\r
+                        */\r
+                       if (nonopt_end != -1) {\r
+                               permute_args(nonopt_start, nonopt_end,\r
+                                   optind, nargv);\r
+                               optind -= nonopt_end - nonopt_start;\r
+                       }\r
+                       nonopt_start = nonopt_end = -1;\r
+                       return (-1);\r
+               }\r
+       }\r
+\r
+       /*\r
+        * Check long options if:\r
+        *  1) we were passed some\r
+        *  2) the arg is not just "-"\r
+        *  3) either the arg starts with -- we are getopt_long_only()\r
+        */\r
+       if (long_options != NULL && place != nargv[optind] &&\r
+           (*place == '-' || (flags & FLAG_LONGONLY))) {\r
+               short_too = 0;\r
+               if (*place == '-')\r
+                       place++;                /* --foo long option */\r
+               else if (*place != ':' && strchr(options, *place) != NULL)\r
+                       short_too = 1;          /* could be short option too */\r
+\r
+               optchar = parse_long_options(nargv, options, long_options,\r
+                   idx, short_too);\r
+               if (optchar != -1) {\r
+                       place = EMSG;\r
+                       return (optchar);\r
+               }\r
+       }\r
+\r
+       if ((optchar = (int)*place++) == (int)':' ||\r
+           (optchar == (int)'-' && *place != '\0') ||\r
+           (oli = strchr(options, optchar)) == NULL) {\r
+               /*\r
+                * If the user specified "-" and  '-' isn't listed in\r
+                * options, return -1 (non-option) as per POSIX.\r
+                * Otherwise, it is an unknown option character (or ':').\r
+                */\r
+               if (optchar == (int)'-' && *place == '\0')\r
+                       return (-1);\r
+               if (!*place)\r
+                       ++optind;\r
+               if (PRINT_ERROR)\r
+                       warnx(illoptchar, optchar);\r
+               optopt = optchar;\r
+               return (BADCH);\r
+       }\r
+       if (long_options != NULL && optchar == 'W' && oli[1] == ';') {\r
+               /* -W long-option */\r
+               if (*place)                     /* no space */\r
+                       /* NOTHING */;\r
+               else if (++optind >= nargc) {   /* no arg */\r
+                       place = EMSG;\r
+                       if (PRINT_ERROR)\r
+                               warnx(recargchar, optchar);\r
+                       optopt = optchar;\r
+                       return (BADARG);\r
+               } else                          /* white space */\r
+                       place = nargv[optind];\r
+               optchar = parse_long_options(nargv, options, long_options,\r
+                   idx, 0);\r
+               place = EMSG;\r
+               return (optchar);\r
+       }\r
+       if (*++oli != ':') {                    /* doesn't take argument */\r
+               if (!*place)\r
+                       ++optind;\r
+       } else {                                /* takes (optional) argument */\r
+               optarg = NULL;\r
+               if (*place)                     /* no white space */\r
+                       optarg = place;\r
+               else if (oli[1] != ':') {       /* arg not optional */\r
+                       if (++optind >= nargc) {        /* no arg */\r
+                               place = EMSG;\r
+                               if (PRINT_ERROR)\r
+                                       warnx(recargchar, optchar);\r
+                               optopt = optchar;\r
+                               return (BADARG);\r
+                       } else\r
+                               optarg = nargv[optind];\r
+               }\r
+               place = EMSG;\r
+               ++optind;\r
+       }\r
+       /* dump back option letter */\r
+       return (optchar);\r
+}\r
+\r
+#ifdef REPLACE_GETOPT\r
+/*\r
+ * getopt --\r
+ *     Parse argc/argv argument vector.\r
+ *\r
+ * [eventually this will replace the BSD getopt]\r
+ */\r
+int\r
+getopt(int nargc, char * const *nargv, const char *options)\r
+{\r
+\r
+       /*\r
+        * We don't pass FLAG_PERMUTE to getopt_internal() since\r
+        * the BSD getopt(3) (unlike GNU) has never done this.\r
+        *\r
+        * Furthermore, since many privileged programs call getopt()\r
+        * before dropping privileges it makes sense to keep things\r
+        * as simple (and bug-free) as possible.\r
+        */\r
+       return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));\r
+}\r
+#endif /* REPLACE_GETOPT */\r
+\r
+/*\r
+ * getopt_long --\r
+ *     Parse argc/argv argument vector.\r
+ */\r
+int\r
+getopt_long(int nargc, char * const *nargv, const char *options,\r
+    const struct option *long_options, int *idx)\r
+{\r
+\r
+       return (getopt_internal(nargc, nargv, options, long_options, idx,\r
+           FLAG_PERMUTE));\r
+}\r
+\r
+/*\r
+ * getopt_long_only --\r
+ *     Parse argc/argv argument vector.\r
+ */\r
+int\r
+getopt_long_only(int nargc, char * const *nargv, const char *options,\r
+    const struct option *long_options, int *idx)\r
+{\r
+\r
+       return (getopt_internal(nargc, nargv, options, long_options, idx,\r
+           FLAG_PERMUTE|FLAG_LONGONLY));\r
+}\r
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *     * Redistributions of source code must retain the above copyright\r
+ *       notice, this list of conditions and the following disclaimer.\r
+ *     * Redistributions in binary form must reproduce the above copyright\r
+ *       notice, this list of conditions and the following disclaimer in the\r
+ *       documentation and/or other materials provided with the distribution.\r
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors\r
+ *       may be used to endorse or promote products derived from this software\r
+ *       without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "argtable3.h"\r
+\r
+\r
+char * arg_strptime(const char *buf, const char *fmt, struct tm *tm);\r
+\r
+\r
+static void arg_date_resetfn(struct arg_date *parent)\r
+{\r
+    ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+    parent->count = 0;\r
+}\r
+\r
+\r
+static int arg_date_scanfn(struct arg_date *parent, const char *argval)\r
+{\r
+    int errorcode = 0;\r
+\r
+    if (parent->count == parent->hdr.maxcount)\r
+    {\r
+        errorcode = EMAXCOUNT;\r
+    }\r
+    else if (!argval)\r
+    {\r
+        /* no argument value was given, leave parent->tmval[] unaltered but still count it */\r
+        parent->count++;\r
+    }\r
+    else\r
+    {\r
+        const char *pend;\r
+        struct tm tm = parent->tmval[parent->count];\r
+\r
+        /* parse the given argument value, store result in parent->tmval[] */\r
+        pend = arg_strptime(argval, parent->format, &tm);\r
+        if (pend && pend[0] == '\0')\r
+            parent->tmval[parent->count++] = tm;\r
+        else\r
+            errorcode = EBADDATE;\r
+    }\r
+\r
+    ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+    return errorcode;\r
+}\r
+\r
+\r
+static int arg_date_checkfn(struct arg_date *parent)\r
+{\r
+    int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;\r
+\r
+    ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+    return errorcode;\r
+}\r
+\r
+\r
+static void arg_date_errorfn(\r
+    struct arg_date *parent,\r
+    FILE *fp,\r
+    int errorcode,\r
+    const char *argval,\r
+    const char *progname)\r
+{\r
+    const char *shortopts = parent->hdr.shortopts;\r
+    const char *longopts  = parent->hdr.longopts;\r
+    const char *datatype  = parent->hdr.datatype;\r
+\r
+    /* make argval NULL safe */\r
+    argval = argval ? argval : "";\r
+\r
+    fprintf(fp, "%s: ", progname);\r
+    switch(errorcode)\r
+    {\r
+    case EMINCOUNT:\r
+        fputs("missing option ", fp);\r
+        arg_print_option(fp, shortopts, longopts, datatype, "\n");\r
+        break;\r
+\r
+    case EMAXCOUNT:\r
+        fputs("excess option ", fp);\r
+        arg_print_option(fp, shortopts, longopts, argval, "\n");\r
+        break;\r
+\r
+    case EBADDATE:\r
+    {\r
+        struct tm tm;\r
+        char buff[200];\r
+\r
+        fprintf(fp, "illegal timestamp format \"%s\"\n", argval);\r
+        memset(&tm, 0, sizeof(tm));\r
+        arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm);\r
+        strftime(buff, sizeof(buff), parent->format, &tm);\r
+        printf("correct format is \"%s\"\n", buff);\r
+        break;\r
+    }\r
+    }\r
+}\r
+\r
+\r
+struct arg_date * arg_date0(\r
+    const char * shortopts,\r
+    const char * longopts,\r
+    const char * format,\r
+    const char *datatype,\r
+    const char *glossary)\r
+{\r
+    return arg_daten(shortopts, longopts, format, datatype, 0, 1, glossary);\r
+}\r
+\r
+\r
+struct arg_date * arg_date1(\r
+    const char * shortopts,\r
+    const char * longopts,\r
+    const char * format,\r
+    const char *datatype,\r
+    const char *glossary)\r
+{\r
+    return arg_daten(shortopts, longopts, format, datatype, 1, 1, glossary);\r
+}\r
+\r
+\r
+struct arg_date * arg_daten(\r
+    const char * shortopts,\r
+    const char * longopts,\r
+    const char * format,\r
+    const char *datatype,\r
+    int mincount,\r
+    int maxcount,\r
+    const char *glossary)\r
+{\r
+    size_t nbytes;\r
+    struct arg_date *result;\r
+\r
+    /* foolproof things by ensuring maxcount is not less than mincount */\r
+    maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+    /* default time format is the national date format for the locale */\r
+    if (!format)\r
+        format = "%x";\r
+\r
+    nbytes = sizeof(struct arg_date)         /* storage for struct arg_date */\r
+        + maxcount * sizeof(struct tm);    /* storage for tmval[maxcount] array */\r
+\r
+    /* allocate storage for the arg_date struct + tmval[] array.    */\r
+    /* we use calloc because we want the tmval[] array zero filled. */\r
+    result = (struct arg_date *)calloc(1, nbytes);\r
+    if (result)\r
+    {\r
+        /* init the arg_hdr struct */\r
+        result->hdr.flag      = ARG_HASVALUE;\r
+        result->hdr.shortopts = shortopts;\r
+        result->hdr.longopts  = longopts;\r
+        result->hdr.datatype  = datatype ? datatype : format;\r
+        result->hdr.glossary  = glossary;\r
+        result->hdr.mincount  = mincount;\r
+        result->hdr.maxcount  = maxcount;\r
+        result->hdr.parent    = result;\r
+        result->hdr.resetfn   = (arg_resetfn *)arg_date_resetfn;\r
+        result->hdr.scanfn    = (arg_scanfn *)arg_date_scanfn;\r
+        result->hdr.checkfn   = (arg_checkfn *)arg_date_checkfn;\r
+        result->hdr.errorfn   = (arg_errorfn *)arg_date_errorfn;\r
+\r
+        /* store the tmval[maxcount] array immediately after the arg_date struct */\r
+        result->tmval  = (struct tm *)(result + 1);\r
+\r
+        /* init the remaining arg_date member variables */\r
+        result->count = 0;\r
+        result->format = format;\r
+    }\r
+\r
+    ARG_TRACE(("arg_daten() returns %p\n", result));\r
+    return result;\r
+}\r
+\r
+\r
+/*-\r
+ * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.\r
+ * All rights reserved.\r
+ *\r
+ * This code was contributed to The NetBSD Foundation by Klaus Klein.\r
+ * Heavily optimised by David Laight\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ *    notice, this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ *    notice, this list of conditions and the following disclaimer in the\r
+ *    documentation and/or other materials provided with the distribution.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\r
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\r
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include <time.h>\r
+\r
+/*\r
+ * We do not implement alternate representations. However, we always\r
+ * check whether a given modifier is allowed for a certain conversion.\r
+ */\r
+#define ALT_E                   0x01\r
+#define ALT_O                   0x02\r
+#define LEGAL_ALT(x)            { if (alt_format & ~(x)) return (0); }\r
+#define TM_YEAR_BASE   (1900)\r
+\r
+static int conv_num(const char * *, int *, int, int);\r
+\r
+static const char *day[7] = {\r
+    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",\r
+    "Friday", "Saturday"\r
+};\r
+\r
+static const char *abday[7] = {\r
+    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"\r
+};\r
+\r
+static const char *mon[12] = {\r
+    "January", "February", "March", "April", "May", "June", "July",\r
+    "August", "September", "October", "November", "December"\r
+};\r
+\r
+static const char *abmon[12] = {\r
+    "Jan", "Feb", "Mar", "Apr", "May", "Jun",\r
+    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"\r
+};\r
+\r
+static const char *am_pm[2] = {\r
+    "AM", "PM"\r
+};\r
+\r
+\r
+static int arg_strcasecmp(const char *s1, const char *s2)\r
+{\r
+    const unsigned char *us1 = (const unsigned char *)s1;\r
+    const unsigned char *us2 = (const unsigned char *)s2;\r
+    while (tolower(*us1) == tolower(*us2++))\r
+        if (*us1++ == '\0')\r
+            return 0;\r
+\r
+    return tolower(*us1) - tolower(*--us2);\r
+}\r
+\r
+\r
+static int arg_strncasecmp(const char *s1, const char *s2, size_t n)\r
+{\r
+    if (n != 0)\r
+    {\r
+        const unsigned char *us1 = (const unsigned char *)s1;\r
+        const unsigned char *us2 = (const unsigned char *)s2;\r
+        do\r
+        {\r
+            if (tolower(*us1) != tolower(*us2++))\r
+                return tolower(*us1) - tolower(*--us2);\r
+\r
+            if (*us1++ == '\0')\r
+                break;\r
+        } while (--n != 0);\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+char * arg_strptime(const char *buf, const char *fmt, struct tm *tm)\r
+{\r
+    char c;\r
+    const char *bp;\r
+    size_t len = 0;\r
+    int alt_format, i, split_year = 0;\r
+\r
+    bp = buf;\r
+\r
+    while ((c = *fmt) != '\0') {\r
+        /* Clear `alternate' modifier prior to new conversion. */\r
+        alt_format = 0;\r
+\r
+        /* Eat up white-space. */\r
+        if (isspace(c)) {\r
+            while (isspace(*bp))\r
+                bp++;\r
+\r
+            fmt++;\r
+            continue;\r
+        }\r
+\r
+        if ((c = *fmt++) != '%')\r
+            goto literal;\r
+\r
+\r
+again:\r
+        switch (c = *fmt++)\r
+        {\r
+        case '%': /* "%%" is converted to "%". */\r
+literal:\r
+            if (c != *bp++)\r
+                return (0);\r
+            break;\r
+\r
+        /*\r
+         * "Alternative" modifiers. Just set the appropriate flag\r
+         * and start over again.\r
+         */\r
+        case 'E': /* "%E?" alternative conversion modifier. */\r
+            LEGAL_ALT(0);\r
+            alt_format |= ALT_E;\r
+            goto again;\r
+\r
+        case 'O': /* "%O?" alternative conversion modifier. */\r
+            LEGAL_ALT(0);\r
+            alt_format |= ALT_O;\r
+            goto again;\r
+\r
+        /*\r
+         * "Complex" conversion rules, implemented through recursion.\r
+         */\r
+        case 'c': /* Date and time, using the locale's format. */\r
+            LEGAL_ALT(ALT_E);\r
+            bp = arg_strptime(bp, "%x %X", tm);\r
+            if (!bp)\r
+                return (0);\r
+            break;\r
+\r
+        case 'D': /* The date as "%m/%d/%y". */\r
+            LEGAL_ALT(0);\r
+            bp = arg_strptime(bp, "%m/%d/%y", tm);\r
+            if (!bp)\r
+                return (0);\r
+            break;\r
+\r
+        case 'R': /* The time as "%H:%M". */\r
+            LEGAL_ALT(0);\r
+            bp = arg_strptime(bp, "%H:%M", tm);\r
+            if (!bp)\r
+                return (0);\r
+            break;\r
+\r
+        case 'r': /* The time in 12-hour clock representation. */\r
+            LEGAL_ALT(0);\r
+            bp = arg_strptime(bp, "%I:%M:%S %p", tm);\r
+            if (!bp)\r
+                return (0);\r
+            break;\r
+\r
+        case 'T': /* The time as "%H:%M:%S". */\r
+            LEGAL_ALT(0);\r
+            bp = arg_strptime(bp, "%H:%M:%S", tm);\r
+            if (!bp)\r
+                return (0);\r
+            break;\r
+\r
+        case 'X': /* The time, using the locale's format. */\r
+            LEGAL_ALT(ALT_E);\r
+            bp = arg_strptime(bp, "%H:%M:%S", tm);\r
+            if (!bp)\r
+                return (0);\r
+            break;\r
+\r
+        case 'x': /* The date, using the locale's format. */\r
+            LEGAL_ALT(ALT_E);\r
+            bp = arg_strptime(bp, "%m/%d/%y", tm);\r
+            if (!bp)\r
+                return (0);\r
+            break;\r
+\r
+        /*\r
+         * "Elementary" conversion rules.\r
+         */\r
+        case 'A': /* The day of week, using the locale's form. */\r
+        case 'a':\r
+            LEGAL_ALT(0);\r
+            for (i = 0; i < 7; i++) {\r
+                /* Full name. */\r
+                len = strlen(day[i]);\r
+                if (arg_strncasecmp(day[i], bp, len) == 0)\r
+                    break;\r
+\r
+                /* Abbreviated name. */\r
+                len = strlen(abday[i]);\r
+                if (arg_strncasecmp(abday[i], bp, len) == 0)\r
+                    break;\r
+            }\r
+\r
+            /* Nothing matched. */\r
+            if (i == 7)\r
+                return (0);\r
+\r
+            tm->tm_wday = i;\r
+            bp += len;\r
+            break;\r
+\r
+        case 'B': /* The month, using the locale's form. */\r
+        case 'b':\r
+        case 'h':\r
+            LEGAL_ALT(0);\r
+            for (i = 0; i < 12; i++) {\r
+                /* Full name. */\r
+                len = strlen(mon[i]);\r
+                if (arg_strncasecmp(mon[i], bp, len) == 0)\r
+                    break;\r
+\r
+                /* Abbreviated name. */\r
+                len = strlen(abmon[i]);\r
+                if (arg_strncasecmp(abmon[i], bp, len) == 0)\r
+                    break;\r
+            }\r
+\r
+            /* Nothing matched. */\r
+            if (i == 12)\r
+                return (0);\r
+\r
+            tm->tm_mon = i;\r
+            bp += len;\r
+            break;\r
+\r
+        case 'C': /* The century number. */\r
+            LEGAL_ALT(ALT_E);\r
+            if (!(conv_num(&bp, &i, 0, 99)))\r
+                return (0);\r
+\r
+            if (split_year) {\r
+                tm->tm_year = (tm->tm_year % 100) + (i * 100);\r
+            } else {\r
+                tm->tm_year = i * 100;\r
+                split_year = 1;\r
+            }\r
+            break;\r
+\r
+        case 'd': /* The day of month. */\r
+        case 'e':\r
+            LEGAL_ALT(ALT_O);\r
+            if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))\r
+                return (0);\r
+            break;\r
+\r
+        case 'k': /* The hour (24-hour clock representation). */\r
+            LEGAL_ALT(0);\r
+        /* FALLTHROUGH */\r
+        case 'H':\r
+            LEGAL_ALT(ALT_O);\r
+            if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))\r
+                return (0);\r
+            break;\r
+\r
+        case 'l': /* The hour (12-hour clock representation). */\r
+            LEGAL_ALT(0);\r
+        /* FALLTHROUGH */\r
+        case 'I':\r
+            LEGAL_ALT(ALT_O);\r
+            if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))\r
+                return (0);\r
+            if (tm->tm_hour == 12)\r
+                tm->tm_hour = 0;\r
+            break;\r
+\r
+        case 'j': /* The day of year. */\r
+            LEGAL_ALT(0);\r
+            if (!(conv_num(&bp, &i, 1, 366)))\r
+                return (0);\r
+            tm->tm_yday = i - 1;\r
+            break;\r
+\r
+        case 'M': /* The minute. */\r
+            LEGAL_ALT(ALT_O);\r
+            if (!(conv_num(&bp, &tm->tm_min, 0, 59)))\r
+                return (0);\r
+            break;\r
+\r
+        case 'm': /* The month. */\r
+            LEGAL_ALT(ALT_O);\r
+            if (!(conv_num(&bp, &i, 1, 12)))\r
+                return (0);\r
+            tm->tm_mon = i - 1;\r
+            break;\r
+\r
+        case 'p': /* The locale's equivalent of AM/PM. */\r
+            LEGAL_ALT(0);\r
+            /* AM? */\r
+            if (arg_strcasecmp(am_pm[0], bp) == 0) {\r
+                if (tm->tm_hour > 11)\r
+                    return (0);\r
+\r
+                bp += strlen(am_pm[0]);\r
+                break;\r
+            }\r
+            /* PM? */\r
+            else if (arg_strcasecmp(am_pm[1], bp) == 0) {\r
+                if (tm->tm_hour > 11)\r
+                    return (0);\r
+\r
+                tm->tm_hour += 12;\r
+                bp += strlen(am_pm[1]);\r
+                break;\r
+            }\r
+\r
+            /* Nothing matched. */\r
+            return (0);\r
+\r
+        case 'S': /* The seconds. */\r
+            LEGAL_ALT(ALT_O);\r
+            if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))\r
+                return (0);\r
+            break;\r
+\r
+        case 'U': /* The week of year, beginning on sunday. */\r
+        case 'W': /* The week of year, beginning on monday. */\r
+            LEGAL_ALT(ALT_O);\r
+            /*\r
+             * XXX This is bogus, as we can not assume any valid\r
+             * information present in the tm structure at this\r
+             * point to calculate a real value, so just check the\r
+             * range for now.\r
+             */\r
+            if (!(conv_num(&bp, &i, 0, 53)))\r
+                return (0);\r
+            break;\r
+\r
+        case 'w': /* The day of week, beginning on sunday. */\r
+            LEGAL_ALT(ALT_O);\r
+            if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))\r
+                return (0);\r
+            break;\r
+\r
+        case 'Y': /* The year. */\r
+            LEGAL_ALT(ALT_E);\r
+            if (!(conv_num(&bp, &i, 0, 9999)))\r
+                return (0);\r
+\r
+            tm->tm_year = i - TM_YEAR_BASE;\r
+            break;\r
+\r
+        case 'y': /* The year within 100 years of the epoch. */\r
+            LEGAL_ALT(ALT_E | ALT_O);\r
+            if (!(conv_num(&bp, &i, 0, 99)))\r
+                return (0);\r
+\r
+            if (split_year) {\r
+                tm->tm_year = ((tm->tm_year / 100) * 100) + i;\r
+                break;\r
+            }\r
+            split_year = 1;\r
+            if (i <= 68)\r
+                tm->tm_year = i + 2000 - TM_YEAR_BASE;\r
+            else\r
+                tm->tm_year = i + 1900 - TM_YEAR_BASE;\r
+            break;\r
+\r
+        /*\r
+         * Miscellaneous conversions.\r
+         */\r
+        case 'n': /* Any kind of white-space. */\r
+        case 't':\r
+            LEGAL_ALT(0);\r
+            while (isspace(*bp))\r
+                bp++;\r
+            break;\r
+\r
+\r
+        default: /* Unknown/unsupported conversion. */\r
+            return (0);\r
+        }\r
+\r
+\r
+    }\r
+\r
+    /* LINTED functional specification */\r
+    return ((char *)bp);\r
+}\r
+\r
+\r
+static int conv_num(const char * *buf, int *dest, int llim, int ulim)\r
+{\r
+    int result = 0;\r
+\r
+    /* The limit also determines the number of valid digits. */\r
+    int rulim = ulim;\r
+\r
+    if (**buf < '0' || **buf > '9')\r
+        return (0);\r
+\r
+    do {\r
+        result *= 10;\r
+        result += *(*buf)++ - '0';\r
+        rulim /= 10;\r
+    } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');\r
+\r
+    if (result < llim || result > ulim)\r
+        return (0);\r
+\r
+    *dest = result;\r
+    return (1);\r
+}\r
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *     * Redistributions of source code must retain the above copyright\r
+ *       notice, this list of conditions and the following disclaimer.\r
+ *     * Redistributions in binary form must reproduce the above copyright\r
+ *       notice, this list of conditions and the following disclaimer in the\r
+ *       documentation and/or other materials provided with the distribution.\r
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors\r
+ *       may be used to endorse or promote products derived from this software\r
+ *       without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include <stdlib.h>\r
+\r
+#include "argtable3.h"\r
+\r
+\r
+static void arg_dbl_resetfn(struct arg_dbl *parent)\r
+{\r
+    ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+    parent->count = 0;\r
+}\r
+\r
+\r
+static int arg_dbl_scanfn(struct arg_dbl *parent, const char *argval)\r
+{\r
+    int errorcode = 0;\r
+\r
+    if (parent->count == parent->hdr.maxcount)\r
+    {\r
+        /* maximum number of arguments exceeded */\r
+        errorcode = EMAXCOUNT;\r
+    }\r
+    else if (!argval)\r
+    {\r
+        /* a valid argument with no argument value was given. */\r
+        /* This happens when an optional argument value was invoked. */\r
+        /* leave parent argument value unaltered but still count the argument. */\r
+        parent->count++;\r
+    }\r
+    else\r
+    {\r
+        double val;\r
+        char *end;\r
+\r
+        /* extract double from argval into val */\r
+        val = strtod(argval, &end);\r
+\r
+        /* if success then store result in parent->dval[] array otherwise return error*/\r
+        if (*end == 0)\r
+            parent->dval[parent->count++] = val;\r
+        else\r
+            errorcode = EBADDOUBLE;\r
+    }\r
+\r
+    ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+    return errorcode;\r
+}\r
+\r
+\r
+static int arg_dbl_checkfn(struct arg_dbl *parent)\r
+{\r
+    int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;\r
+    \r
+    ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+    return errorcode;\r
+}\r
+\r
+\r
+static void arg_dbl_errorfn(\r
+    struct arg_dbl *parent,\r
+    FILE *fp,\r
+    int errorcode,\r
+    const char *argval,\r
+    const char *progname)\r
+{\r
+    const char *shortopts = parent->hdr.shortopts;\r
+    const char *longopts  = parent->hdr.longopts;\r
+    const char *datatype  = parent->hdr.datatype;\r
+\r
+    /* make argval NULL safe */\r
+    argval = argval ? argval : "";\r
+\r
+    fprintf(fp, "%s: ", progname);\r
+    switch(errorcode)\r
+    {\r
+    case EMINCOUNT:\r
+        fputs("missing option ", fp);\r
+        arg_print_option(fp, shortopts, longopts, datatype, "\n");\r
+        break;\r
+\r
+    case EMAXCOUNT:\r
+        fputs("excess option ", fp);\r
+        arg_print_option(fp, shortopts, longopts, argval, "\n");\r
+        break;\r
+\r
+    case EBADDOUBLE:\r
+        fprintf(fp, "invalid argument \"%s\" to option ", argval);\r
+        arg_print_option(fp, shortopts, longopts, datatype, "\n");\r
+        break;\r
+    }\r
+}\r
+\r
+\r
+struct arg_dbl * arg_dbl0(\r
+    const char * shortopts,\r
+    const char * longopts,\r
+    const char *datatype,\r
+    const char *glossary)\r
+{\r
+    return arg_dbln(shortopts, longopts, datatype, 0, 1, glossary);\r
+}\r
+\r
+\r
+struct arg_dbl * arg_dbl1(\r
+    const char * shortopts,\r
+    const char * longopts,\r
+    const char *datatype,\r
+    const char *glossary)\r
+{\r
+    return arg_dbln(shortopts, longopts, datatype, 1, 1, glossary);\r
+}\r
+\r
+\r
+struct arg_dbl * arg_dbln(\r
+    const char * shortopts,\r
+    const char * longopts,\r
+    const char *datatype,\r
+    int mincount,\r
+    int maxcount,\r
+    const char *glossary)\r
+{\r
+    size_t nbytes;\r
+    struct arg_dbl *result;\r
+\r
+    /* foolproof things by ensuring maxcount is not less than mincount */\r
+    maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+    nbytes = sizeof(struct arg_dbl)     /* storage for struct arg_dbl */\r
+             + (maxcount + 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */\r
+\r
+    result = (struct arg_dbl *)malloc(nbytes);\r
+    if (result)\r
+    {\r
+        size_t addr;\r
+        size_t rem;\r
+\r
+        /* init the arg_hdr struct */\r
+        result->hdr.flag      = ARG_HASVALUE;\r
+        result->hdr.shortopts = shortopts;\r
+        result->hdr.longopts  = longopts;\r
+        result->hdr.datatype  = datatype ? datatype : "<double>";\r
+        result->hdr.glossary  = glossary;\r
+        result->hdr.mincount  = mincount;\r
+        result->hdr.maxcount  = maxcount;\r
+        result->hdr.parent    = result;\r
+        result->hdr.resetfn   = (arg_resetfn *)arg_dbl_resetfn;\r
+        result->hdr.scanfn    = (arg_scanfn *)arg_dbl_scanfn;\r
+        result->hdr.checkfn   = (arg_checkfn *)arg_dbl_checkfn;\r
+        result->hdr.errorfn   = (arg_errorfn *)arg_dbl_errorfn;\r
+\r
+        /* Store the dval[maxcount] array on the first double boundary that\r
+         * immediately follows the arg_dbl struct. We do the memory alignment\r
+         * purely for SPARC and Motorola systems. They require floats and\r
+         * doubles to be aligned on natural boundaries.\r
+         */\r
+        addr = (size_t)(result + 1);\r
+        rem  = addr % sizeof(double);\r
+        result->dval  = (double *)(addr + sizeof(double) - rem);\r
+        ARG_TRACE(("addr=%p, dval=%p, sizeof(double)=%d rem=%d\n", addr, result->dval, (int)sizeof(double), (int)rem));\r
+\r
+        result->count = 0;\r
+    }\r
+    \r
+    ARG_TRACE(("arg_dbln() returns %p\n", result));\r
+    return result;\r
+}\r
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *     * Redistributions of source code must retain the above copyright\r
+ *       notice, this list of conditions and the following disclaimer.\r
+ *     * Redistributions in binary form must reproduce the above copyright\r
+ *       notice, this list of conditions and the following disclaimer in the\r
+ *       documentation and/or other materials provided with the distribution.\r
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors\r
+ *       may be used to endorse or promote products derived from this software\r
+ *       without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include <stdlib.h>\r
+\r
+#include "argtable3.h"\r
+\r
+\r
+static void arg_end_resetfn(struct arg_end *parent)\r
+{\r
+    ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+    parent->count = 0;\r
+}\r
+\r
+static void arg_end_errorfn(\r
+    void *parent,\r
+    FILE *fp,\r
+    int error,\r
+    const char *argval,\r
+    const char *progname)\r
+{\r
+    /* suppress unreferenced formal parameter warning */\r
+    (void)parent;\r
+\r
+    progname = progname ? progname : "";\r
+    argval = argval ? argval : "";\r
+\r
+    fprintf(fp, "%s: ", progname);\r
+    switch(error)\r
+    {\r
+    case ARG_ELIMIT:\r
+        fputs("too many errors to display", fp);\r
+        break;\r
+    case ARG_EMALLOC:\r
+        fputs("insufficent memory", fp);\r
+        break;\r
+    case ARG_ENOMATCH:\r
+        fprintf(fp, "unexpected argument \"%s\"", argval);\r
+        break;\r
+    case ARG_EMISSARG:\r
+        fprintf(fp, "option \"%s\" requires an argument", argval);\r
+        break;\r
+    case ARG_ELONGOPT:\r
+        fprintf(fp, "invalid option \"%s\"", argval);\r
+        break;\r
+    default:\r
+        fprintf(fp, "invalid option \"-%c\"", error);\r
+        break;\r
+    }\r
+    \r
+    fputc('\n', fp);\r
+}\r
+\r
+\r
+struct arg_end * arg_end(int maxcount)\r
+{\r
+    size_t nbytes;\r
+    struct arg_end *result;\r
+\r
+    nbytes = sizeof(struct arg_end)\r
+             + maxcount * sizeof(int)     /* storage for int error[maxcount] array*/\r
+             + maxcount * sizeof(void *)  /* storage for void* parent[maxcount] array */\r
+             + maxcount * sizeof(char *); /* storage for char* argval[maxcount] array */\r
+\r
+    result = (struct arg_end *)malloc(nbytes);\r
+    if (result)\r
+    {\r
+        /* init the arg_hdr struct */\r
+        result->hdr.flag      = ARG_TERMINATOR;\r
+        result->hdr.shortopts = NULL;\r
+        result->hdr.longopts  = NULL;\r
+        result->hdr.datatype  = NULL;\r
+        result->hdr.glossary  = NULL;\r
+        result->hdr.mincount  = 1;\r
+        result->hdr.maxcount  = maxcount;\r
+        result->hdr.parent    = result;\r
+        result->hdr.resetfn   = (arg_resetfn *)arg_end_resetfn;\r
+        result->hdr.scanfn    = NULL;\r
+        result->hdr.checkfn   = NULL;\r
+        result->hdr.errorfn   = (arg_errorfn *)arg_end_errorfn;\r
+\r
+        /* store error[maxcount] array immediately after struct arg_end */\r
+        result->error = (int *)(result + 1);\r
+\r
+        /* store parent[maxcount] array immediately after error[] array */\r
+        result->parent = (void * *)(result->error + maxcount );\r
+\r
+        /* store argval[maxcount] array immediately after parent[] array */\r
+        result->argval = (const char * *)(result->parent + maxcount );\r
+    }\r
+\r
+    ARG_TRACE(("arg_end(%d) returns %p\n", maxcount, result));\r
+    return result;\r
+}\r
+\r
+\r
+void arg_print_errors(FILE * fp, struct arg_end * end, const char * progname)\r
+{\r
+    int i;\r
+    ARG_TRACE(("arg_errors()\n"));\r
+    for (i = 0; i < end->count; i++)\r
+    {\r
+        struct arg_hdr *errorparent = (struct arg_hdr *)(end->parent[i]);\r
+        if (errorparent->errorfn)\r
+            errorparent->errorfn(end->parent[i],\r
+                                 fp,\r
+                                 end->error[i],\r
+                                 end->argval[i],\r
+                                 progname);\r
+    }\r
+}\r
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *     * Redistributions of source code must retain the above copyright\r
+ *       notice, this list of conditions and the following disclaimer.\r
+ *     * Redistributions in binary form must reproduce the above copyright\r
+ *       notice, this list of conditions and the following disclaimer in the\r
+ *       documentation and/or other materials provided with the distribution.\r
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors\r
+ *       may be used to endorse or promote products derived from this software\r
+ *       without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include <string.h>\r
+#include <stdlib.h>\r
+\r
+#include "argtable3.h"\r
+\r
+#ifdef WIN32\r
+# define FILESEPARATOR1 '\\'\r
+# define FILESEPARATOR2 '/'\r
+#else\r
+# define FILESEPARATOR1 '/'\r
+# define FILESEPARATOR2 '/'\r
+#endif\r
+\r
+\r
+static void arg_file_resetfn(struct arg_file *parent)\r
+{\r
+    ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+    parent->count = 0;\r
+}\r
+\r
+\r
+/* Returns ptr to the base filename within *filename */\r
+static const char * arg_basename(const char *filename)\r
+{\r
+    const char *result = NULL, *result1, *result2;\r
+\r
+    /* Find the last occurrence of eother file separator character. */\r
+    /* Two alternative file separator chars are supported as legal  */\r
+    /* file separators but not both together in the same filename.  */\r
+    result1 = (filename ? strrchr(filename, FILESEPARATOR1) : NULL);\r
+    result2 = (filename ? strrchr(filename, FILESEPARATOR2) : NULL);\r
+\r
+    if (result2)\r
+        result = result2 + 1;  /* using FILESEPARATOR2 (the alternative file separator) */\r
+\r
+    if (result1)\r
+        result = result1 + 1;  /* using FILESEPARATOR1 (the preferred file separator) */\r
+\r
+    if (!result)\r
+        result = filename;  /* neither file separator was found so basename is the whole filename */\r
+\r
+    /* special cases of "." and ".." are not considered basenames */\r
+    if (result && ( strcmp(".", result) == 0 || strcmp("..", result) == 0 ))\r
+        result = filename + strlen(filename);\r
+\r
+    return result;\r
+}\r
+\r
+\r
+/* Returns ptr to the file extension within *basename */\r
+static const char * arg_extension(const char *basename)\r
+{\r
+    /* find the last occurrence of '.' in basename */\r
+    const char *result = (basename ? strrchr(basename, '.') : NULL);\r
+\r
+    /* if no '.' was found then return pointer to end of basename */\r
+    if (basename && !result)\r
+        result = basename + strlen(basename);\r
+\r
+    /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */\r
+    if (basename && result == basename)\r
+        result = basename + strlen(basename);\r
+\r
+    /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */\r
+    if (basename && result && result[1] == '\0')\r
+        result = basename + strlen(basename);\r
+\r
+    return result;\r
+}\r
+\r
+\r
+static int arg_file_scanfn(struct arg_file *parent, const char *argval)\r
+{\r
+    int errorcode = 0;\r
+\r
+    if (parent->count == parent->hdr.maxcount)\r
+    {\r
+        /* maximum number of arguments exceeded */\r
+        errorcode = EMAXCOUNT;\r
+    }\r
+    else if (!argval)\r
+    {\r
+        /* a valid argument with no argument value was given. */\r
+        /* This happens when an optional argument value was invoked. */\r
+        /* leave parent arguiment value unaltered but still count the argument. */\r
+        parent->count++;\r
+    }\r
+    else\r
+    {\r
+        parent->filename[parent->count]  = argval;\r
+        parent->basename[parent->count]  = arg_basename(argval);\r
+        parent->extension[parent->count] =\r
+            arg_extension(parent->basename[parent->count]);                                /* only seek extensions within the basename (not the file path)*/\r
+        parent->count++;\r
+    }\r
+\r
+    ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+    return errorcode;\r
+}\r
+\r
+\r
+static int arg_file_checkfn(struct arg_file *parent)\r
+{\r
+    int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;\r
+    \r
+    ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+    return errorcode;\r
+}\r
+\r
+\r
+static void arg_file_errorfn(\r
+    struct arg_file *parent,\r
+    FILE *fp,\r
+    int errorcode,\r
+    const char *argval,\r
+    const char *progname)\r
+{\r
+    const char *shortopts = parent->hdr.shortopts;\r
+    const char *longopts  = parent->hdr.longopts;\r
+    const char *datatype  = parent->hdr.datatype;\r
+\r
+    /* make argval NULL safe */\r
+    argval = argval ? argval : "";\r
+\r
+    fprintf(fp, "%s: ", progname);\r
+    switch(errorcode)\r
+    {\r
+    case EMINCOUNT:\r
+        fputs("missing option ", fp);\r
+        arg_print_option(fp, shortopts, longopts, datatype, "\n");\r
+        break;\r
+\r
+    case EMAXCOUNT:\r
+        fputs("excess option ", fp);\r
+        arg_print_option(fp, shortopts, longopts, argval, "\n");\r
+        break;\r
+\r
+    default:\r
+        fprintf(fp, "unknown error at \"%s\"\n", argval);\r
+    }\r
+}\r
+\r
+\r
+struct arg_file * arg_file0(\r
+    const char * shortopts,\r
+    const char * longopts,\r
+    const char *datatype,\r
+    const char *glossary)\r
+{\r
+    return arg_filen(shortopts, longopts, datatype, 0, 1, glossary);\r
+}\r
+\r
+\r
+struct arg_file * arg_file1(\r
+    const char * shortopts,\r
+    const char * longopts,\r
+    const char *datatype,\r
+    const char *glossary)\r
+{\r
+    return arg_filen(shortopts, longopts, datatype, 1, 1, glossary);\r
+}\r
+\r
+\r
+struct arg_file * arg_filen(\r
+    const char * shortopts,\r
+    const char * longopts,\r
+    const char *datatype,\r
+    int mincount,\r
+    int maxcount,\r
+    const char *glossary)\r
+{\r
+    size_t nbytes;\r
+    struct arg_file *result;\r
+\r
+    /* foolproof things by ensuring maxcount is not less than mincount */\r
+    maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+    nbytes = sizeof(struct arg_file)      /* storage for struct arg_file */\r
+             + sizeof(char *) * maxcount  /* storage for filename[maxcount] array */\r
+             + sizeof(char *) * maxcount  /* storage for basename[maxcount] array */\r
+             + sizeof(char *) * maxcount; /* storage for extension[maxcount] array */\r
+\r
+    result = (struct arg_file *)malloc(nbytes);\r
+    if (result)\r
+    {\r
+        int i;\r
+\r
+        /* init the arg_hdr struct */\r
+        result->hdr.flag      = ARG_HASVALUE;\r
+        result->hdr.shortopts = shortopts;\r
+        result->hdr.longopts  = longopts;\r
+        result->hdr.glossary  = glossary;\r
+        result->hdr.datatype  = datatype ? datatype : "<file>";\r
+        result->hdr.mincount  = mincount;\r
+        result->hdr.maxcount  = maxcount;\r
+        result->hdr.parent    = result;\r
+        result->hdr.resetfn   = (arg_resetfn *)arg_file_resetfn;\r
+        result->hdr.scanfn    = (arg_scanfn *)arg_file_scanfn;\r
+        result->hdr.checkfn   = (arg_checkfn *)arg_file_checkfn;\r
+        result->hdr.errorfn   = (arg_errorfn *)arg_file_errorfn;\r
+\r
+        /* store the filename,basename,extension arrays immediately after the arg_file struct */\r
+        result->filename  = (const char * *)(result + 1);\r
+        result->basename  = result->filename + maxcount;\r
+        result->extension = result->basename + maxcount;\r
+        result->count = 0;\r
+\r
+        /* foolproof the string pointers by initialising them with empty strings */\r
+        for (i = 0; i < maxcount; i++)\r
+        {\r
+            result->filename[i] = "";\r
+            result->basename[i] = "";\r
+            result->extension[i] = "";\r
+        }\r
+    }\r
+    \r
+    ARG_TRACE(("arg_filen() returns %p\n", result));\r
+    return result;\r
+}\r
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *     * Redistributions of source code must retain the above copyright\r
+ *       notice, this list of conditions and the following disclaimer.\r
+ *     * Redistributions in binary form must reproduce the above copyright\r
+ *       notice, this list of conditions and the following disclaimer in the\r
+ *       documentation and/or other materials provided with the distribution.\r
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors\r
+ *       may be used to endorse or promote products derived from this software\r
+ *       without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include <stdlib.h>\r
+#include <limits.h>\r
+#include <ctype.h>\r
+\r
+#include "argtable3.h"\r
+\r
+\r
+static void arg_int_resetfn(struct arg_int *parent)\r
+{\r
+    ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+    parent->count = 0;\r
+}\r
+\r
+\r
+/* strtol0x() is like strtol() except that the numeric string is    */\r
+/* expected to be prefixed by "0X" where X is a user supplied char. */\r
+/* The string may optionally be prefixed by white space and + or -  */\r
+/* as in +0X123 or -0X123.                                          */\r
+/* Once the prefix has been scanned, the remainder of the numeric   */\r
+/* string is converted using strtol() with the given base.          */\r
+/* eg: to parse hex str="-0X12324", specify X='X' and base=16.      */\r
+/* eg: to parse oct str="+0o12324", specify X='O' and base=8.       */\r
+/* eg: to parse bin str="-0B01010", specify X='B' and base=2.       */\r
+/* Failure of conversion is indicated by result where *endptr==str. */\r
+static long int strtol0X(const char * str,\r
+                         const char * *endptr,\r
+                         char X,\r
+                         int base)\r
+{\r
+    long int val;               /* stores result */\r
+    int s = 1;                    /* sign is +1 or -1 */\r
+    const char *ptr = str;        /* ptr to current position in str */\r
+\r
+    /* skip leading whitespace */\r
+    while (isspace(*ptr))\r
+        ptr++;\r
+    /* printf("1) %s\n",ptr); */\r
+\r
+    /* scan optional sign character */\r
+    switch (*ptr)\r
+    {\r
+    case '+':\r
+        ptr++;\r
+        s = 1;\r
+        break;\r
+    case '-':\r
+        ptr++;\r
+        s = -1;\r
+        break;\r
+    default:\r
+        s = 1;\r
+        break;\r
+    }\r
+    /* printf("2) %s\n",ptr); */\r
+\r
+    /* '0X' prefix */\r
+    if ((*ptr++) != '0')\r
+    {\r
+        /* printf("failed to detect '0'\n"); */\r
+        *endptr = str;\r
+        return 0;\r
+    }\r
+    /* printf("3) %s\n",ptr); */\r
+    if (toupper(*ptr++) != toupper(X))\r
+    {\r
+        /* printf("failed to detect '%c'\n",X); */\r
+        *endptr = str;\r
+        return 0;\r
+    }\r
+    /* printf("4) %s\n",ptr); */\r
+\r
+    /* attempt conversion on remainder of string using strtol() */\r
+    val = strtol(ptr, (char * *)endptr, base);\r
+    if (*endptr == ptr)\r
+    {\r
+        /* conversion failed */\r
+        *endptr = str;\r
+        return 0;\r
+    }\r
+\r
+    /* success */\r
+    return s * val;\r
+}\r
+\r
+\r
+/* Returns 1 if str matches suffix (case insensitive).    */\r
+/* Str may contain trailing whitespace, but nothing else. */\r
+static int detectsuffix(const char *str, const char *suffix)\r
+{\r
+    /* scan pairwise through strings until mismatch detected */\r
+    while( toupper(*str) == toupper(*suffix) )\r
+    {\r
+        /* printf("'%c' '%c'\n", *str, *suffix); */\r
+\r
+        /* return 1 (success) if match persists until the string terminator */\r
+        if (*str == '\0')\r
+            return 1;\r
+\r
+        /* next chars */\r
+        str++;\r
+        suffix++;\r
+    }\r
+    /* printf("'%c' '%c' mismatch\n", *str, *suffix); */\r
+\r
+    /* return 0 (fail) if the matching did not consume the entire suffix */\r
+    if (*suffix != 0)\r
+        return 0;   /* failed to consume entire suffix */\r
+\r
+    /* skip any remaining whitespace in str */\r
+    while (isspace(*str))\r
+        str++;\r
+\r
+    /* return 1 (success) if we have reached end of str else return 0 (fail) */\r
+    return (*str == '\0') ? 1 : 0;\r
+}\r
+\r
+\r
+static int arg_int_scanfn(struct arg_int *parent, const char *argval)\r
+{\r
+    int errorcode = 0;\r
+\r
+    if (parent->count == parent->hdr.maxcount)\r
+    {\r
+        /* maximum number of arguments exceeded */\r
+        errorcode = EMAXCOUNT;\r
+    }\r
+    else if (!argval)\r
+    {\r
+        /* a valid argument with no argument value was given. */\r
+        /* This happens when an optional argument value was invoked. */\r
+        /* leave parent arguiment value unaltered but still count the argument. */\r
+        parent->count++;\r
+    }\r
+    else\r
+    {\r
+        long int val;\r
+        const char *end;\r
+\r
+        /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */\r
+        val = strtol0X(argval, &end, 'X', 16);\r
+        if (end == argval)\r
+        {\r
+            /* hex failed, attempt octal conversion (eg +0o123) */\r
+            val = strtol0X(argval, &end, 'O', 8);\r
+            if (end == argval)\r
+            {\r
+                /* octal failed, attempt binary conversion (eg +0B101) */\r
+                val = strtol0X(argval, &end, 'B', 2);\r
+                if (end == argval)\r
+                {\r
+                    /* binary failed, attempt decimal conversion with no prefix (eg 1234) */\r
+                    val = strtol(argval, (char * *)&end, 10);\r
+                    if (end == argval)\r
+                    {\r
+                        /* all supported number formats failed */\r
+                        return EBADINT;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        /* Safety check for integer overflow. WARNING: this check    */\r
+        /* achieves nothing on machines where size(int)==size(long). */\r
+        if ( val > INT_MAX || val < INT_MIN )\r
+            errorcode = EOVERFLOW;\r
+\r
+        /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */\r
+        /* We need to be mindful of integer overflows when using such big numbers.   */\r
+        if (detectsuffix(end, "KB"))             /* kilobytes */\r
+        {\r
+            if ( val > (INT_MAX / 1024) || val < (INT_MIN / 1024) )\r
+                errorcode = EOVERFLOW;          /* Overflow would occur if we proceed */\r
+            else\r
+                val *= 1024;                    /* 1KB = 1024 */\r
+        }\r
+        else if (detectsuffix(end, "MB"))        /* megabytes */\r
+        {\r
+            if ( val > (INT_MAX / 1048576) || val < (INT_MIN / 1048576) )\r
+                errorcode = EOVERFLOW;          /* Overflow would occur if we proceed */\r
+            else\r
+                val *= 1048576;                 /* 1MB = 1024*1024 */\r
+        }\r
+        else if (detectsuffix(end, "GB"))        /* gigabytes */\r
+        {\r
+            if ( val > (INT_MAX / 1073741824) || val < (INT_MIN / 1073741824) )\r
+                errorcode = EOVERFLOW;          /* Overflow would occur if we proceed */\r
+            else\r
+                val *= 1073741824;              /* 1GB = 1024*1024*1024 */\r
+        }\r
+        else if (!detectsuffix(end, ""))\r
+            errorcode = EBADINT;                /* invalid suffix detected */\r
+\r
+        /* if success then store result in parent->ival[] array */\r
+        if (errorcode == 0)\r
+            parent->ival[parent->count++] = val;\r
+    }\r
+\r
+    /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */\r
+    return errorcode;\r
+}\r
+\r
+\r
+static int arg_int_checkfn(struct arg_int *parent)\r
+{\r
+    int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;\r
+    /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/\r
+    return errorcode;\r
+}\r
+\r
+\r
+static void arg_int_errorfn(\r
+    struct arg_int *parent,\r
+    FILE *fp,\r
+    int errorcode,\r
+    const char *argval,\r
+    const char *progname)\r
+{\r
+    const char *shortopts = parent->hdr.shortopts;\r
+    const char *longopts  = parent->hdr.longopts;\r
+    const char *datatype  = parent->hdr.datatype;\r
+\r
+    /* make argval NULL safe */\r
+    argval = argval ? argval : "";\r
+\r
+    fprintf(fp, "%s: ", progname);\r
+    switch(errorcode)\r
+    {\r
+    case EMINCOUNT:\r
+        fputs("missing option ", fp);\r
+        arg_print_option(fp, shortopts, longopts, datatype, "\n");\r
+        break;\r
+\r
+    case EMAXCOUNT:\r
+        fputs("excess option ", fp);\r
+        arg_print_option(fp, shortopts, longopts, argval, "\n");\r
+        break;\r
+\r
+    case EBADINT:\r
+        fprintf(fp, "invalid argument \"%s\" to option ", argval);\r
+        arg_print_option(fp, shortopts, longopts, datatype, "\n");\r
+        break;\r
+\r
+    case EOVERFLOW:\r
+        fputs("integer overflow at option ", fp);\r
+        arg_print_option(fp, shortopts, longopts, datatype, " ");\r
+        fprintf(fp, "(%s is too large)\n", argval);\r
+        break;\r
+    }\r
+}\r
+\r
+\r
+struct arg_int * arg_int0(\r
+    const char *shortopts,\r
+    const char *longopts,\r
+    const char *datatype,\r
+    const char *glossary)\r
+{\r
+    return arg_intn(shortopts, longopts, datatype, 0, 1, glossary);\r
+}\r
+\r
+\r
+struct arg_int * arg_int1(\r
+    const char *shortopts,\r
+    const char *longopts,\r
+    const char *datatype,\r
+    const char *glossary)\r
+{\r
+    return arg_intn(shortopts, longopts, datatype, 1, 1, glossary);\r
+}\r
+\r
+\r
+struct arg_int * arg_intn(\r
+    const char *shortopts,\r
+    const char *longopts,\r
+    const char *datatype,\r
+    int mincount,\r
+    int maxcount,\r
+    const char *glossary)\r
+{\r
+    size_t nbytes;\r
+    struct arg_int *result;\r
+\r
+    /* foolproof things by ensuring maxcount is not less than mincount */\r
+    maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+    nbytes = sizeof(struct arg_int)    /* storage for struct arg_int */\r
+             + maxcount * sizeof(int); /* storage for ival[maxcount] array */\r
+\r
+    result = (struct arg_int *)malloc(nbytes);\r
+    if (result)\r
+    {\r
+        /* init the arg_hdr struct */\r
+        result->hdr.flag      = ARG_HASVALUE;\r
+        result->hdr.shortopts = shortopts;\r
+        result->hdr.longopts  = longopts;\r
+        result->hdr.datatype  = datatype ? datatype : "<int>";\r
+        result->hdr.glossary  = glossary;\r
+        result->hdr.mincount  = mincount;\r
+        result->hdr.maxcount  = maxcount;\r
+        result->hdr.parent    = result;\r
+        result->hdr.resetfn   = (arg_resetfn *)arg_int_resetfn;\r
+        result->hdr.scanfn    = (arg_scanfn *)arg_int_scanfn;\r
+        result->hdr.checkfn   = (arg_checkfn *)arg_int_checkfn;\r
+        result->hdr.errorfn   = (arg_errorfn *)arg_int_errorfn;\r
+\r
+        /* store the ival[maxcount] array immediately after the arg_int struct */\r
+        result->ival  = (int *)(result + 1);\r
+        result->count = 0;\r
+    }\r
+    \r
+    ARG_TRACE(("arg_intn() returns %p\n", result));\r
+    return result;\r
+}\r
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *     * Redistributions of source code must retain the above copyright\r
+ *       notice, this list of conditions and the following disclaimer.\r
+ *     * Redistributions in binary form must reproduce the above copyright\r
+ *       notice, this list of conditions and the following disclaimer in the\r
+ *       documentation and/or other materials provided with the distribution.\r
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors\r
+ *       may be used to endorse or promote products derived from this software\r
+ *       without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include <stdlib.h>\r
+\r
+#include "argtable3.h"\r
+\r
+\r
+static void arg_lit_resetfn(struct arg_lit *parent)\r
+{\r
+    ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+    parent->count = 0;\r
+}\r
+\r
+\r
+static int arg_lit_scanfn(struct arg_lit *parent, const char *argval)\r
+{\r
+    int errorcode = 0;\r
+    if (parent->count < parent->hdr.maxcount )\r
+        parent->count++;\r
+    else\r
+        errorcode = EMAXCOUNT;\r
+\r
+    ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__, parent, argval,\r
+               errorcode));\r
+    return errorcode;\r
+}\r
+\r
+\r
+static int arg_lit_checkfn(struct arg_lit *parent)\r
+{\r
+    int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;\r
+    ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+    return errorcode;\r
+}\r
+\r
+\r
+static void arg_lit_errorfn(\r
+    struct arg_lit *parent,\r
+    FILE *fp,\r
+    int errorcode,\r
+    const char *argval,\r
+    const char *progname)\r
+{\r
+    const char *shortopts = parent->hdr.shortopts;\r
+    const char *longopts  = parent->hdr.longopts;\r
+    const char *datatype  = parent->hdr.datatype;\r
+\r
+    switch(errorcode)\r
+    {\r
+    case EMINCOUNT:\r
+        fprintf(fp, "%s: missing option ", progname);\r
+        arg_print_option(fp, shortopts, longopts, datatype, "\n");\r
+        fprintf(fp, "\n");\r
+        break;\r
+\r
+    case EMAXCOUNT:\r
+        fprintf(fp, "%s: extraneous option ", progname);\r
+        arg_print_option(fp, shortopts, longopts, datatype, "\n");\r
+        break;\r
+    }\r
+\r
+    ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, fp,\r
+               errorcode, argval, progname));\r
+}\r
+\r
+\r
+struct arg_lit * arg_lit0(\r
+    const char * shortopts,\r
+    const char * longopts,\r
+    const char * glossary)\r
+{\r
+    return arg_litn(shortopts, longopts, 0, 1, glossary);\r
+}\r
+\r
+\r
+struct arg_lit * arg_lit1(\r
+    const char *shortopts,\r
+    const char *longopts,\r
+    const char *glossary)\r
+{\r
+    return arg_litn(shortopts, longopts, 1, 1, glossary);\r
+}\r
+\r
+\r
+struct arg_lit * arg_litn(\r
+    const char *shortopts,\r
+    const char *longopts,\r
+    int mincount,\r
+    int maxcount,\r
+    const char *glossary)\r
+{\r
+    struct arg_lit *result;\r
+\r
+    /* foolproof things by ensuring maxcount is not less than mincount */\r
+    maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+    result = (struct arg_lit *)malloc(sizeof(struct arg_lit));\r
+    if (result)\r
+    {\r
+        /* init the arg_hdr struct */\r
+        result->hdr.flag      = 0;\r
+        result->hdr.shortopts = shortopts;\r
+        result->hdr.longopts  = longopts;\r
+        result->hdr.datatype  = NULL;\r
+        result->hdr.glossary  = glossary;\r
+        result->hdr.mincount  = mincount;\r
+        result->hdr.maxcount  = maxcount;\r
+        result->hdr.parent    = result;\r
+        result->hdr.resetfn   = (arg_resetfn *)arg_lit_resetfn;\r
+        result->hdr.scanfn    = (arg_scanfn *)arg_lit_scanfn;\r
+        result->hdr.checkfn   = (arg_checkfn *)arg_lit_checkfn;\r
+        result->hdr.errorfn   = (arg_errorfn *)arg_lit_errorfn;\r
+\r
+        /* init local variables */\r
+        result->count = 0;\r
+    }\r
+    \r
+    ARG_TRACE(("arg_litn() returns %p\n", result));\r
+    return result;\r
+}\r
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *     * Redistributions of source code must retain the above copyright\r
+ *       notice, this list of conditions and the following disclaimer.\r
+ *     * Redistributions in binary form must reproduce the above copyright\r
+ *       notice, this list of conditions and the following disclaimer in the\r
+ *       documentation and/or other materials provided with the distribution.\r
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors\r
+ *       may be used to endorse or promote products derived from this software\r
+ *       without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include <stdlib.h>\r
+\r
+#include "argtable3.h"\r
+\r
+struct arg_rem *arg_rem(const char *datatype, const char *glossary)\r
+{\r
+    struct arg_rem *result = (struct arg_rem *)malloc(sizeof(struct arg_rem));\r
+    if (result)\r
+    {\r
+        result->hdr.flag = 0;\r
+        result->hdr.shortopts = NULL;\r
+        result->hdr.longopts = NULL;\r
+        result->hdr.datatype = datatype;\r
+        result->hdr.glossary = glossary;\r
+        result->hdr.mincount = 1;\r
+        result->hdr.maxcount = 1;\r
+        result->hdr.parent = result;\r
+        result->hdr.resetfn = NULL;\r
+        result->hdr.scanfn = NULL;\r
+        result->hdr.checkfn = NULL;\r
+        result->hdr.errorfn = NULL;\r
+    }\r
+\r
+    ARG_TRACE(("arg_rem() returns %p\n", result));\r
+    return result;\r
+}\r
+\r
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *     * Redistributions of source code must retain the above copyright\r
+ *       notice, this list of conditions and the following disclaimer.\r
+ *     * Redistributions in binary form must reproduce the above copyright\r
+ *       notice, this list of conditions and the following disclaimer in the\r
+ *       documentation and/or other materials provided with the distribution.\r
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors\r
+ *       may be used to endorse or promote products derived from this software\r
+ *       without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "argtable3.h"\r
+\r
+\r
+#ifndef _TREX_H_\r
+#define _TREX_H_\r
+/***************************************************************\r
+       T-Rex a tiny regular expression library\r
+\r
+       Copyright (C) 2003-2006 Alberto Demichelis\r
+\r
+       This software is provided 'as-is', without any express\r
+       or implied warranty. In no event will the authors be held\r
+       liable for any damages arising from the use of this software.\r
+\r
+       Permission is granted to anyone to use this software for\r
+       any purpose, including commercial applications, and to alter\r
+       it and redistribute it freely, subject to the following restrictions:\r
+\r
+               1. The origin of this software must not be misrepresented;\r
+               you must not claim that you wrote the original software.\r
+               If you use this software in a product, an acknowledgment\r
+               in the product documentation would be appreciated but\r
+               is not required.\r
+\r
+               2. Altered source versions must be plainly marked as such,\r
+               and must not be misrepresented as being the original software.\r
+\r
+               3. This notice may not be removed or altered from any\r
+               source distribution.\r
+\r
+****************************************************************/\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#ifdef _UNICODE\r
+#define TRexChar unsigned short\r
+#define MAX_CHAR 0xFFFF\r
+#define _TREXC(c) L##c\r
+#define trex_strlen wcslen\r
+#define trex_printf wprintf\r
+#else\r
+#define TRexChar char\r
+#define MAX_CHAR 0xFF\r
+#define _TREXC(c) (c)\r
+#define trex_strlen strlen\r
+#define trex_printf printf\r
+#endif\r
+\r
+#ifndef TREX_API\r
+#define TREX_API extern\r
+#endif\r
+\r
+#define TRex_True 1\r
+#define TRex_False 0\r
+\r
+#define TREX_ICASE ARG_REX_ICASE\r
+\r
+typedef unsigned int TRexBool;\r
+typedef struct TRex TRex;\r
+\r
+typedef struct {\r
+       const TRexChar *begin;\r
+       int len;\r
+} TRexMatch;\r
+\r
+TREX_API TRex *trex_compile(const TRexChar *pattern, const TRexChar **error, int flags);\r
+TREX_API void trex_free(TRex *exp);\r
+TREX_API TRexBool trex_match(TRex* exp, const TRexChar* text);\r
+TREX_API TRexBool trex_search(TRex* exp, const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end);\r
+TREX_API TRexBool trex_searchrange(TRex* exp, const TRexChar* text_begin, const TRexChar* text_end, const TRexChar** out_begin, const TRexChar** out_end);\r
+TREX_API int trex_getsubexpcount(TRex* exp);\r
+TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif\r
+\r
+\r
+\r
+struct privhdr\r
+{\r
+    const char *pattern;\r
+    int flags;\r
+};\r
+\r
+\r
+static void arg_rex_resetfn(struct arg_rex *parent)\r
+{\r
+    ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+    parent->count = 0;\r
+}\r
+\r
+static int arg_rex_scanfn(struct arg_rex *parent, const char *argval)\r
+{\r
+    int errorcode = 0;\r
+    const TRexChar *error = NULL;\r
+    TRex *rex = NULL;\r
+    TRexBool is_match = TRex_False;\r
+\r
+    if (parent->count == parent->hdr.maxcount )\r
+    {\r
+        /* maximum number of arguments exceeded */\r
+        errorcode = EMAXCOUNT;\r
+    }\r
+    else if (!argval)\r
+    {\r
+        /* a valid argument with no argument value was given. */\r
+        /* This happens when an optional argument value was invoked. */\r
+        /* leave parent argument value unaltered but still count the argument. */\r
+        parent->count++;\r
+    }\r
+    else\r
+    {\r
+        struct privhdr *priv = (struct privhdr *)parent->hdr.priv;\r
+\r
+        /* test the current argument value for a match with the regular expression */\r
+        /* if a match is detected, record the argument value in the arg_rex struct */\r
+\r
+        rex = trex_compile(priv->pattern, &error, priv->flags);\r
+        is_match = trex_match(rex, argval);\r
+        if (!is_match)\r
+            errorcode = EREGNOMATCH;\r
+        else\r
+            parent->sval[parent->count++] = argval;\r
+\r
+        trex_free(rex);\r
+    }\r
+\r
+    ARG_TRACE(("%s:scanfn(%p) returns %d\n",__FILE__,parent,errorcode));\r
+    return errorcode;\r
+}\r
+\r
+static int arg_rex_checkfn(struct arg_rex *parent)\r
+{\r
+    int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;\r
+    //struct privhdr *priv = (struct privhdr*)parent->hdr.priv;\r
+\r
+    /* free the regex "program" we constructed in resetfn */\r
+    //regfree(&(priv->regex));\r
+\r
+    /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/\r
+    return errorcode;\r
+}\r
+\r
+static void arg_rex_errorfn(struct arg_rex *parent,\r
+                    FILE *fp,\r
+                    int errorcode,\r
+                    const char *argval,\r
+                    const char *progname)\r
+{\r
+    const char *shortopts = parent->hdr.shortopts;\r
+    const char *longopts  = parent->hdr.longopts;\r
+    const char *datatype  = parent->hdr.datatype;\r
+\r
+    /* make argval NULL safe */\r
+    argval = argval ? argval : "";\r
+\r
+    fprintf(fp, "%s: ", progname);\r
+    switch(errorcode)\r
+    {\r
+    case EMINCOUNT:\r
+        fputs("missing option ", fp);\r
+        arg_print_option(fp, shortopts, longopts, datatype, "\n");\r
+        break;\r
+\r
+    case EMAXCOUNT:\r
+        fputs("excess option ", fp);\r
+        arg_print_option(fp, shortopts, longopts, argval, "\n");\r
+        break;\r
+\r
+    case EREGNOMATCH:\r
+        fputs("illegal value  ", fp);\r
+        arg_print_option(fp, shortopts, longopts, argval, "\n");\r
+        break;\r
+\r
+    default:\r
+    {\r
+        //char errbuff[256];\r
+        //regerror(errorcode, NULL, errbuff, sizeof(errbuff));\r
+        //printf("%s\n", errbuff);\r
+    }\r
+    break;\r
+    }\r
+}\r
+\r
+\r
+struct arg_rex * arg_rex0(const char * shortopts,\r
+                          const char * longopts,\r
+                          const char * pattern,\r
+                          const char *datatype,\r
+                          int flags,\r
+                          const char *glossary)\r
+{\r
+    return arg_rexn(shortopts,\r
+                    longopts,\r
+                    pattern,\r
+                    datatype,\r
+                    0,\r
+                    1,\r
+                    flags,\r
+                    glossary);\r
+}\r
+\r
+struct arg_rex * arg_rex1(const char * shortopts,\r
+                          const char * longopts,\r
+                          const char * pattern,\r
+                          const char *datatype,\r
+                          int flags,\r
+                          const char *glossary)\r
+{\r
+    return arg_rexn(shortopts,\r
+                    longopts,\r
+                    pattern,\r
+                    datatype,\r
+                    1,\r
+                    1,\r
+                    flags,\r
+                    glossary);\r
+}\r
+\r
+\r
+struct arg_rex * arg_rexn(const char * shortopts,\r
+                          const char * longopts,\r
+                          const char * pattern,\r
+                          const char *datatype,\r
+                          int mincount,\r
+                          int maxcount,\r
+                          int flags,\r
+                          const char *glossary)\r
+{\r
+    size_t nbytes;\r
+    struct arg_rex *result;\r
+    struct privhdr *priv;\r
+    int i;\r
+    const TRexChar *error = NULL;\r
+    TRex *rex = NULL;\r
+\r
+    if (!pattern)\r
+    {\r
+        printf(\r
+            "argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n");\r
+        printf("argtable: Bad argument table.\n");\r
+        return NULL;\r
+    }\r
+\r
+    /* foolproof things by ensuring maxcount is not less than mincount */\r
+    maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+    nbytes = sizeof(struct arg_rex)       /* storage for struct arg_rex */\r
+             + sizeof(struct privhdr)     /* storage for private arg_rex data */\r
+             + maxcount * sizeof(char *);  /* storage for sval[maxcount] array */\r
+\r
+    result = (struct arg_rex *)malloc(nbytes);\r
+    if (result == NULL)\r
+        return result;\r
+\r
+    /* init the arg_hdr struct */\r
+    result->hdr.flag      = ARG_HASVALUE;\r
+    result->hdr.shortopts = shortopts;\r
+    result->hdr.longopts  = longopts;\r
+    result->hdr.datatype  = datatype ? datatype : pattern;\r
+    result->hdr.glossary  = glossary;\r
+    result->hdr.mincount  = mincount;\r
+    result->hdr.maxcount  = maxcount;\r
+    result->hdr.parent    = result;\r
+    result->hdr.resetfn   = (arg_resetfn *)arg_rex_resetfn;\r
+    result->hdr.scanfn    = (arg_scanfn *)arg_rex_scanfn;\r
+    result->hdr.checkfn   = (arg_checkfn *)arg_rex_checkfn;\r
+    result->hdr.errorfn   = (arg_errorfn *)arg_rex_errorfn;\r
+\r
+    /* store the arg_rex_priv struct immediately after the arg_rex struct */\r
+    result->hdr.priv  = result + 1;\r
+    priv = (struct privhdr *)(result->hdr.priv);\r
+    priv->pattern = pattern;\r
+    priv->flags = flags;\r
+\r
+    /* store the sval[maxcount] array immediately after the arg_rex_priv struct */\r
+    result->sval  = (const char * *)(priv + 1);\r
+    result->count = 0;\r
+\r
+    /* foolproof the string pointers by initializing them to reference empty strings */\r
+    for (i = 0; i < maxcount; i++)\r
+        result->sval[i] = "";\r
+\r
+    /* here we construct and destroy a regex representation of the regular\r
+     * expression for no other reason than to force any regex errors to be\r
+     * trapped now rather than later. If we don't, then errors may go undetected\r
+     * until an argument is actually parsed.\r
+     */\r
+\r
+    rex = trex_compile(priv->pattern, &error, priv->flags);\r
+    if (rex == NULL)\r
+    {\r
+        ARG_LOG(("argtable: %s \"%s\"\n", error ? error : _TREXC("undefined"), priv->pattern));\r
+        ARG_LOG(("argtable: Bad argument table.\n"));\r
+    }\r
+\r
+    trex_free(rex);\r
+\r
+    ARG_TRACE(("arg_rexn() returns %p\n", result));\r
+    return result;\r
+}\r
+\r
+\r
+\r
+/* see copyright notice in trex.h */\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <ctype.h>\r
+#include <setjmp.h>\r
+\r
+#ifdef _UINCODE\r
+#define scisprint iswprint\r
+#define scstrlen wcslen\r
+#define scprintf wprintf\r
+#define _SC(x) L(x)\r
+#else\r
+#define scisprint isprint\r
+#define scstrlen strlen\r
+#define scprintf printf\r
+#define _SC(x) (x)\r
+#endif\r
+\r
+#ifdef _DEBUG\r
+#include <stdio.h>\r
+\r
+static const TRexChar *g_nnames[] =\r
+{\r
+       _SC("NONE"),_SC("OP_GREEDY"),   _SC("OP_OR"),\r
+       _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"),       _SC("OP_CLASS"),\r
+       _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),\r
+       _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")\r
+};\r
+\r
+#endif\r
+#define OP_GREEDY              (MAX_CHAR+1) // * + ? {n}\r
+#define OP_OR                  (MAX_CHAR+2)\r
+#define OP_EXPR                        (MAX_CHAR+3) //parentesis ()\r
+#define OP_NOCAPEXPR   (MAX_CHAR+4) //parentesis (?:)\r
+#define OP_DOT                 (MAX_CHAR+5)\r
+#define OP_CLASS               (MAX_CHAR+6)\r
+#define OP_CCLASS              (MAX_CHAR+7)\r
+#define OP_NCLASS              (MAX_CHAR+8) //negates class the [^\r
+#define OP_RANGE               (MAX_CHAR+9)\r
+#define OP_CHAR                        (MAX_CHAR+10)\r
+#define OP_EOL                 (MAX_CHAR+11)\r
+#define OP_BOL                 (MAX_CHAR+12)\r
+#define OP_WB                  (MAX_CHAR+13)\r
+\r
+#define TREX_SYMBOL_ANY_CHAR ('.')\r
+#define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')\r
+#define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')\r
+#define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')\r
+#define TREX_SYMBOL_BRANCH ('|')\r
+#define TREX_SYMBOL_END_OF_STRING ('$')\r
+#define TREX_SYMBOL_BEGINNING_OF_STRING ('^')\r
+#define TREX_SYMBOL_ESCAPE_CHAR ('\\')\r
+\r
+\r
+typedef int TRexNodeType;\r
+\r
+typedef struct tagTRexNode{\r
+       TRexNodeType type;\r
+       int left;\r
+       int right;\r
+       int next;\r
+}TRexNode;\r
+\r
+struct TRex{\r
+       const TRexChar *_eol;\r
+       const TRexChar *_bol;\r
+       const TRexChar *_p;\r
+       int _first;\r
+       int _op;\r
+       TRexNode *_nodes;\r
+       int _nallocated;\r
+       int _nsize;\r
+       int _nsubexpr;\r
+       TRexMatch *_matches;\r
+       int _currsubexp;\r
+       void *_jmpbuf;\r
+       const TRexChar **_error;\r
+       int _flags;\r
+};\r
+\r
+static int trex_list(TRex *exp);\r
+\r
+static int trex_newnode(TRex *exp, TRexNodeType type)\r
+{\r
+       TRexNode n;\r
+       int newid;\r
+       n.type = type;\r
+       n.next = n.right = n.left = -1;\r
+       if(type == OP_EXPR)\r
+               n.right = exp->_nsubexpr++;\r
+       if(exp->_nallocated < (exp->_nsize + 1)) {\r
+               exp->_nallocated *= 2;\r
+               exp->_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode));\r
+       }\r
+       exp->_nodes[exp->_nsize++] = n;\r
+       newid = exp->_nsize - 1;\r
+       return (int)newid;\r
+}\r
+\r
+static void trex_error(TRex *exp,const TRexChar *error)\r
+{\r
+       if(exp->_error) *exp->_error = error;\r
+       longjmp(*((jmp_buf*)exp->_jmpbuf),-1);\r
+}\r
+\r
+static void trex_expect(TRex *exp, int n){\r
+       if((*exp->_p) != n)\r
+               trex_error(exp, _SC("expected paren"));\r
+       exp->_p++;\r
+}\r
+\r
+static TRexChar trex_escapechar(TRex *exp)\r
+{\r
+       if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){\r
+               exp->_p++;\r
+               switch(*exp->_p) {\r
+               case 'v': exp->_p++; return '\v';\r
+               case 'n': exp->_p++; return '\n';\r
+               case 't': exp->_p++; return '\t';\r
+               case 'r': exp->_p++; return '\r';\r
+               case 'f': exp->_p++; return '\f';\r
+               default: return (*exp->_p++);\r
+               }\r
+       } else if(!scisprint(*exp->_p)) trex_error(exp,_SC("letter expected"));\r
+       return (*exp->_p++);\r
+}\r
+\r
+static int trex_charclass(TRex *exp,int classid)\r
+{\r
+       int n = trex_newnode(exp,OP_CCLASS);\r
+       exp->_nodes[n].left = classid;\r
+       return n;\r
+}\r
+\r
+static int trex_charnode(TRex *exp,TRexBool isclass)\r
+{\r
+       TRexChar t;\r
+       if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {\r
+               exp->_p++;\r
+               switch(*exp->_p) {\r
+                       case 'n': exp->_p++; return trex_newnode(exp,'\n');\r
+                       case 't': exp->_p++; return trex_newnode(exp,'\t');\r
+                       case 'r': exp->_p++; return trex_newnode(exp,'\r');\r
+                       case 'f': exp->_p++; return trex_newnode(exp,'\f');\r
+                       case 'v': exp->_p++; return trex_newnode(exp,'\v');\r
+                       case 'a': case 'A': case 'w': case 'W': case 's': case 'S':\r
+                       case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':\r
+                       case 'p': case 'P': case 'l': case 'u':\r
+                               {\r
+                               t = *exp->_p; exp->_p++;\r
+                               return trex_charclass(exp,t);\r
+                               }\r
+                       case 'b':\r
+                       case 'B':\r
+                               if(!isclass) {\r
+                                       int node = trex_newnode(exp,OP_WB);\r
+                                       exp->_nodes[node].left = *exp->_p;\r
+                                       exp->_p++;\r
+                                       return node;\r
+                               } //else default\r
+                       default:\r
+                               t = *exp->_p; exp->_p++;\r
+                               return trex_newnode(exp,t);\r
+               }\r
+       }\r
+       else if(!scisprint(*exp->_p)) {\r
+\r
+               trex_error(exp,_SC("letter expected"));\r
+       }\r
+       t = *exp->_p; exp->_p++;\r
+       return trex_newnode(exp,t);\r
+}\r
+static int trex_class(TRex *exp)\r
+{\r
+       int ret = -1;\r
+       int first = -1,chain;\r
+       if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){\r
+               ret = trex_newnode(exp,OP_NCLASS);\r
+               exp->_p++;\r
+       }else ret = trex_newnode(exp,OP_CLASS);\r
+\r
+       if(*exp->_p == ']') trex_error(exp,_SC("empty class"));\r
+       chain = ret;\r
+       while(*exp->_p != ']' && exp->_p != exp->_eol) {\r
+               if(*exp->_p == '-' && first != -1){\r
+                       int r,t;\r
+                       if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range"));\r
+                       r = trex_newnode(exp,OP_RANGE);\r
+                       if(first>*exp->_p) trex_error(exp,_SC("invalid range"));\r
+                       if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges"));\r
+                       exp->_nodes[r].left = exp->_nodes[first].type;\r
+                       t = trex_escapechar(exp);\r
+                       exp->_nodes[r].right = t;\r
+            exp->_nodes[chain].next = r;\r
+                       chain = r;\r
+                       first = -1;\r
+               }\r
+               else{\r
+                       if(first!=-1){\r
+                               int c = first;\r
+                               exp->_nodes[chain].next = c;\r
+                               chain = c;\r
+                               first = trex_charnode(exp,TRex_True);\r
+                       }\r
+                       else{\r
+                               first = trex_charnode(exp,TRex_True);\r
+                       }\r
+               }\r
+       }\r
+       if(first!=-1){\r
+               int c = first;\r
+               exp->_nodes[chain].next = c;\r
+               chain = c;\r
+               first = -1;\r
+       }\r
+       /* hack? */\r
+       exp->_nodes[ret].left = exp->_nodes[ret].next;\r
+       exp->_nodes[ret].next = -1;\r
+       return ret;\r
+}\r
+\r
+static int trex_parsenumber(TRex *exp)\r
+{\r
+       int ret = *exp->_p-'0';\r
+       int positions = 10;\r
+       exp->_p++;\r
+       while(isdigit(*exp->_p)) {\r
+               ret = ret*10+(*exp->_p++-'0');\r
+               if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant"));\r
+               positions *= 10;\r
+       };\r
+       return ret;\r
+}\r
+\r
+static int trex_element(TRex *exp)\r
+{\r
+       int ret = -1;\r
+       switch(*exp->_p)\r
+       {\r
+       case '(': {\r
+               int expr,newn;\r
+               exp->_p++;\r
+\r
+\r
+               if(*exp->_p =='?') {\r
+                       exp->_p++;\r
+                       trex_expect(exp,':');\r
+                       expr = trex_newnode(exp,OP_NOCAPEXPR);\r
+               }\r
+               else\r
+                       expr = trex_newnode(exp,OP_EXPR);\r
+               newn = trex_list(exp);\r
+               exp->_nodes[expr].left = newn;\r
+               ret = expr;\r
+               trex_expect(exp,')');\r
+                         }\r
+                         break;\r
+       case '[':\r
+               exp->_p++;\r
+               ret = trex_class(exp);\r
+               trex_expect(exp,']');\r
+               break;\r
+       case TREX_SYMBOL_END_OF_STRING: exp->_p++; ret = trex_newnode(exp,OP_EOL);break;\r
+       case TREX_SYMBOL_ANY_CHAR: exp->_p++; ret = trex_newnode(exp,OP_DOT);break;\r
+       default:\r
+               ret = trex_charnode(exp,TRex_False);\r
+               break;\r
+       }\r
+\r
+       {\r
+               TRexBool isgreedy = TRex_False;\r
+               unsigned short p0 = 0, p1 = 0;\r
+               switch(*exp->_p){\r
+                       case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;\r
+                       case TREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;\r
+                       case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = TRex_True; break;\r
+                       case '{':\r
+                               exp->_p++;\r
+                               if(!isdigit(*exp->_p)) trex_error(exp,_SC("number expected"));\r
+                               p0 = (unsigned short)trex_parsenumber(exp);\r
+                               /*******************************/\r
+                               switch(*exp->_p) {\r
+                       case '}':\r
+                               p1 = p0; exp->_p++;\r
+                               break;\r
+                       case ',':\r
+                               exp->_p++;\r
+                               p1 = 0xFFFF;\r
+                               if(isdigit(*exp->_p)){\r
+                                       p1 = (unsigned short)trex_parsenumber(exp);\r
+                               }\r
+                               trex_expect(exp,'}');\r
+                               break;\r
+                       default:\r
+                               trex_error(exp,_SC(", or } expected"));\r
+               }\r
+               /*******************************/\r
+               isgreedy = TRex_True;\r
+               break;\r
+\r
+               }\r
+               if(isgreedy) {\r
+                       int nnode = trex_newnode(exp,OP_GREEDY);\r
+                       exp->_nodes[nnode].left = ret;\r
+                       exp->_nodes[nnode].right = ((p0)<<16)|p1;\r
+                       ret = nnode;\r
+               }\r
+       }\r
+       if((*exp->_p != TREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != TREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != TREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) {\r
+               int nnode = trex_element(exp);\r
+               exp->_nodes[ret].next = nnode;\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+static int trex_list(TRex *exp)\r
+{\r
+       int ret=-1,e;\r
+       if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {\r
+               exp->_p++;\r
+               ret = trex_newnode(exp,OP_BOL);\r
+       }\r
+       e = trex_element(exp);\r
+       if(ret != -1) {\r
+               exp->_nodes[ret].next = e;\r
+       }\r
+       else ret = e;\r
+\r
+       if(*exp->_p == TREX_SYMBOL_BRANCH) {\r
+               int temp,tright;\r
+               exp->_p++;\r
+               temp = trex_newnode(exp,OP_OR);\r
+               exp->_nodes[temp].left = ret;\r
+               tright = trex_list(exp);\r
+               exp->_nodes[temp].right = tright;\r
+               ret = temp;\r
+       }\r
+       return ret;\r
+}\r
+\r
+static TRexBool trex_matchcclass(int cclass,TRexChar c)\r
+{\r
+       switch(cclass) {\r
+       case 'a': return isalpha(c)?TRex_True:TRex_False;\r
+       case 'A': return !isalpha(c)?TRex_True:TRex_False;\r
+       case 'w': return (isalnum(c) || c == '_')?TRex_True:TRex_False;\r
+       case 'W': return (!isalnum(c) && c != '_')?TRex_True:TRex_False;\r
+       case 's': return isspace(c)?TRex_True:TRex_False;\r
+       case 'S': return !isspace(c)?TRex_True:TRex_False;\r
+       case 'd': return isdigit(c)?TRex_True:TRex_False;\r
+       case 'D': return !isdigit(c)?TRex_True:TRex_False;\r
+       case 'x': return isxdigit(c)?TRex_True:TRex_False;\r
+       case 'X': return !isxdigit(c)?TRex_True:TRex_False;\r
+       case 'c': return iscntrl(c)?TRex_True:TRex_False;\r
+       case 'C': return !iscntrl(c)?TRex_True:TRex_False;\r
+       case 'p': return ispunct(c)?TRex_True:TRex_False;\r
+       case 'P': return !ispunct(c)?TRex_True:TRex_False;\r
+       case 'l': return islower(c)?TRex_True:TRex_False;\r
+       case 'u': return isupper(c)?TRex_True:TRex_False;\r
+       }\r
+       return TRex_False; /*cannot happen*/\r
+}\r
+\r
+static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c)\r
+{\r
+       do {\r
+               switch(node->type) {\r
+                       case OP_RANGE:\r
+                               if (exp->_flags & TREX_ICASE)\r
+                               {\r
+                                       if(c >= toupper(node->left) && c <= toupper(node->right)) return TRex_True;\r
+                                       if(c >= tolower(node->left) && c <= tolower(node->right)) return TRex_True;\r
+                               }\r
+                               else\r
+                               {\r
+                                       if(c >= node->left && c <= node->right) return TRex_True;\r
+                               }\r
+                               break;\r
+                       case OP_CCLASS:\r
+                               if(trex_matchcclass(node->left,c)) return TRex_True;\r
+                               break;\r
+                       default:\r
+                               if (exp->_flags & TREX_ICASE)\r
+                               {\r
+                                       if (c == tolower(node->type) || c == toupper(node->type)) return TRex_True;\r
+                               }\r
+                               else\r
+                               {\r
+                                       if(c == node->type)return TRex_True;\r
+                               }\r
+\r
+               }\r
+       } while((node->next != -1) && (node = &exp->_nodes[node->next]));\r
+       return TRex_False;\r
+}\r
+\r
+static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next)\r
+{\r
+\r
+       TRexNodeType type = node->type;\r
+       switch(type) {\r
+       case OP_GREEDY: {\r
+               //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;\r
+               TRexNode *greedystop = NULL;\r
+               int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;\r
+               const TRexChar *s=str, *good = str;\r
+\r
+               if(node->next != -1) {\r
+                       greedystop = &exp->_nodes[node->next];\r
+               }\r
+               else {\r
+                       greedystop = next;\r
+               }\r
+\r
+               while((nmaches == 0xFFFF || nmaches < p1)) {\r
+\r
+                       const TRexChar *stop;\r
+                       if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))\r
+                               break;\r
+                       nmaches++;\r
+                       good=s;\r
+                       if(greedystop) {\r
+                               //checks that 0 matches satisfy the expression(if so skips)\r
+                               //if not would always stop(for instance if is a '?')\r
+                               if(greedystop->type != OP_GREEDY ||\r
+                               (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))\r
+                               {\r
+                                       TRexNode *gnext = NULL;\r
+                                       if(greedystop->next != -1) {\r
+                                               gnext = &exp->_nodes[greedystop->next];\r
+                                       }else if(next && next->next != -1){\r
+                                               gnext = &exp->_nodes[next->next];\r
+                                       }\r
+                                       stop = trex_matchnode(exp,greedystop,s,gnext);\r
+                                       if(stop) {\r
+                                               //if satisfied stop it\r
+                                               if(p0 == p1 && p0 == nmaches) break;\r
+                                               else if(nmaches >= p0 && p1 == 0xFFFF) break;\r
+                                               else if(nmaches >= p0 && nmaches <= p1) break;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       if(s >= exp->_eol)\r
+                               break;\r
+               }\r
+               if(p0 == p1 && p0 == nmaches) return good;\r
+               else if(nmaches >= p0 && p1 == 0xFFFF) return good;\r
+               else if(nmaches >= p0 && nmaches <= p1) return good;\r
+               return NULL;\r
+       }\r
+       case OP_OR: {\r
+                       const TRexChar *asd = str;\r
+                       TRexNode *temp=&exp->_nodes[node->left];\r
+                       while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {\r
+                               if(temp->next != -1)\r
+                                       temp = &exp->_nodes[temp->next];\r
+                               else\r
+                                       return asd;\r
+                       }\r
+                       asd = str;\r
+                       temp = &exp->_nodes[node->right];\r
+                       while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {\r
+                               if(temp->next != -1)\r
+                                       temp = &exp->_nodes[temp->next];\r
+                               else\r
+                                       return asd;\r
+                       }\r
+                       return NULL;\r
+                       break;\r
+       }\r
+       case OP_EXPR:\r
+       case OP_NOCAPEXPR:{\r
+                       TRexNode *n = &exp->_nodes[node->left];\r
+                       const TRexChar *cur = str;\r
+                       int capture = -1;\r
+                       if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {\r
+                               capture = exp->_currsubexp;\r
+                               exp->_matches[capture].begin = cur;\r
+                               exp->_currsubexp++;\r
+                       }\r
+\r
+                       do {\r
+                               TRexNode *subnext = NULL;\r
+                               if(n->next != -1) {\r
+                                       subnext = &exp->_nodes[n->next];\r
+                               }else {\r
+                                       subnext = next;\r
+                               }\r
+                               if(!(cur = trex_matchnode(exp,n,cur,subnext))) {\r
+                                       if(capture != -1){\r
+                                               exp->_matches[capture].begin = 0;\r
+                                               exp->_matches[capture].len = 0;\r
+                                       }\r
+                                       return NULL;\r
+                               }\r
+                       } while((n->next != -1) && (n = &exp->_nodes[n->next]));\r
+\r
+                       if(capture != -1)\r
+                               exp->_matches[capture].len = cur - exp->_matches[capture].begin;\r
+                       return cur;\r
+       }\r
+       case OP_WB:\r
+               if((str == exp->_bol && !isspace(*str))\r
+                || ((str == exp->_eol && !isspace(*(str-1))))\r
+                || ((!isspace(*str) && isspace(*(str+1))))\r
+                || ((isspace(*str) && !isspace(*(str+1)))) ) {\r
+                       return (node->left == 'b')?str:NULL;\r
+               }\r
+               return (node->left == 'b')?NULL:str;\r
+       case OP_BOL:\r
+               if(str == exp->_bol) return str;\r
+               return NULL;\r
+       case OP_EOL:\r
+               if(str == exp->_eol) return str;\r
+               return NULL;\r
+       case OP_DOT:\r
+               str++;\r
+               return str;\r
+       case OP_NCLASS:\r
+       case OP_CLASS:\r
+               if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) {\r
+                        str++;\r
+                       return str;\r
+               }\r
+               return NULL;\r
+       case OP_CCLASS:\r
+               if(trex_matchcclass(node->left,*str)) {\r
+                        str++;\r
+                       return str;\r
+               }\r
+               return NULL;\r
+       default: /* char */\r
+               if (exp->_flags & TREX_ICASE)\r
+               {\r
+                       if(*str != tolower(node->type) && *str != toupper(node->type)) return NULL;\r
+               }\r
+               else\r
+               {\r
+                       if (*str != node->type) return NULL;\r
+               }\r
+               str++;\r
+               return str;\r
+       }\r
+       return NULL;\r
+}\r
+\r
+/* public api */\r
+TRex *trex_compile(const TRexChar *pattern,const TRexChar **error,int flags)\r
+{\r
+       TRex *exp = (TRex *)malloc(sizeof(TRex));\r
+       exp->_eol = exp->_bol = NULL;\r
+       exp->_p = pattern;\r
+       exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);\r
+       exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode));\r
+       exp->_nsize = 0;\r
+       exp->_matches = 0;\r
+       exp->_nsubexpr = 0;\r
+       exp->_first = trex_newnode(exp,OP_EXPR);\r
+       exp->_error = error;\r
+       exp->_jmpbuf = malloc(sizeof(jmp_buf));\r
+       exp->_flags = flags;\r
+       if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {\r
+               int res = trex_list(exp);\r
+               exp->_nodes[exp->_first].left = res;\r
+               if(*exp->_p!='\0')\r
+                       trex_error(exp,_SC("unexpected character"));\r
+#ifdef _DEBUG\r
+               {\r
+                       int nsize,i;\r
+                       TRexNode *t;\r
+                       nsize = exp->_nsize;\r
+                       t = &exp->_nodes[0];\r
+                       scprintf(_SC("\n"));\r
+                       for(i = 0;i < nsize; i++) {\r
+                               if(exp->_nodes[i].type>MAX_CHAR)\r
+                                       scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);\r
+                               else\r
+                                       scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);\r
+                               scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);\r
+                       }\r
+                       scprintf(_SC("\n"));\r
+               }\r
+#endif\r
+               exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch));\r
+               memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch));\r
+       }\r
+       else{\r
+               trex_free(exp);\r
+               return NULL;\r
+       }\r
+       return exp;\r
+}\r
+\r
+void trex_free(TRex *exp)\r
+{\r
+       if(exp) {\r
+               if(exp->_nodes) free(exp->_nodes);\r
+               if(exp->_jmpbuf) free(exp->_jmpbuf);\r
+               if(exp->_matches) free(exp->_matches);\r
+               free(exp);\r
+       }\r
+}\r
+\r
+TRexBool trex_match(TRex* exp,const TRexChar* text)\r
+{\r
+       const TRexChar* res = NULL;\r
+       exp->_bol = text;\r
+       exp->_eol = text + scstrlen(text);\r
+       exp->_currsubexp = 0;\r
+       res = trex_matchnode(exp,exp->_nodes,text,NULL);\r
+       if(res == NULL || res != exp->_eol)\r
+               return TRex_False;\r
+       return TRex_True;\r
+}\r
+\r
+TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)\r
+{\r
+       const TRexChar *cur = NULL;\r
+       int node = exp->_first;\r
+       if(text_begin >= text_end) return TRex_False;\r
+       exp->_bol = text_begin;\r
+       exp->_eol = text_end;\r
+       do {\r
+               cur = text_begin;\r
+               while(node != -1) {\r
+                       exp->_currsubexp = 0;\r
+                       cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL);\r
+                       if(!cur)\r
+                               break;\r
+                       node = exp->_nodes[node].next;\r
+               }\r
+               text_begin++;\r
+       } while(cur == NULL && text_begin != text_end);\r
+\r
+       if(cur == NULL)\r
+               return TRex_False;\r
+\r
+       --text_begin;\r
+\r
+       if(out_begin) *out_begin = text_begin;\r
+       if(out_end) *out_end = cur;\r
+       return TRex_True;\r
+}\r
+\r
+TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)\r
+{\r
+       return trex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);\r
+}\r
+\r
+int trex_getsubexpcount(TRex* exp)\r
+{\r
+       return exp->_nsubexpr;\r
+}\r
+\r
+TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp)\r
+{\r
+       if( n<0 || n >= exp->_nsubexpr) return TRex_False;\r
+       *subexp = exp->_matches[n];\r
+       return TRex_True;\r
+}\r
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *     * Redistributions of source code must retain the above copyright\r
+ *       notice, this list of conditions and the following disclaimer.\r
+ *     * Redistributions in binary form must reproduce the above copyright\r
+ *       notice, this list of conditions and the following disclaimer in the\r
+ *       documentation and/or other materials provided with the distribution.\r
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors\r
+ *       may be used to endorse or promote products derived from this software\r
+ *       without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include <stdlib.h>\r
+\r
+#include "argtable3.h"\r
+\r
+\r
+static void arg_str_resetfn(struct arg_str *parent)\r
+{\r
+    ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+    parent->count = 0;\r
+}\r
+\r
+\r
+static int arg_str_scanfn(struct arg_str *parent, const char *argval)\r
+{\r
+    int errorcode = 0;\r
+\r
+    if (parent->count == parent->hdr.maxcount)\r
+    {\r
+        /* maximum number of arguments exceeded */\r
+        errorcode = EMAXCOUNT;\r
+    }\r
+    else if (!argval)\r
+    {\r
+        /* a valid argument with no argument value was given. */\r
+        /* This happens when an optional argument value was invoked. */\r
+        /* leave parent arguiment value unaltered but still count the argument. */\r
+        parent->count++;\r
+    }\r
+    else\r
+    {\r
+        parent->sval[parent->count++] = argval;\r
+    }\r
+\r
+    ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+    return errorcode;\r
+}\r
+\r
+\r
+static int arg_str_checkfn(struct arg_str *parent)\r
+{\r
+    int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;\r
+    \r
+    ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+    return errorcode;\r
+}\r
+\r
+\r
+static void arg_str_errorfn(\r
+    struct arg_str *parent,\r
+    FILE *fp,\r
+    int errorcode,\r
+    const char *argval,\r
+    const char *progname)\r
+{\r
+    const char *shortopts = parent->hdr.shortopts;\r
+    const char *longopts  = parent->hdr.longopts;\r
+    const char *datatype  = parent->hdr.datatype;\r
+\r
+    /* make argval NULL safe */\r
+    argval = argval ? argval : "";\r
+\r
+    fprintf(fp, "%s: ", progname);\r
+    switch(errorcode)\r
+    {\r
+    case EMINCOUNT:\r
+        fputs("missing option ", fp);\r
+        arg_print_option(fp, shortopts, longopts, datatype, "\n");\r
+        break;\r
+\r
+    case EMAXCOUNT:\r
+        fputs("excess option ", fp);\r
+        arg_print_option(fp, shortopts, longopts, argval, "\n");\r
+        break;\r
+    }\r
+}\r
+\r
+\r
+struct arg_str * arg_str0(\r
+    const char *shortopts,\r
+    const char *longopts,\r
+    const char *datatype,\r
+    const char *glossary)\r
+{\r
+    return arg_strn(shortopts, longopts, datatype, 0, 1, glossary);\r
+}\r
+\r
+\r
+struct arg_str * arg_str1(\r
+    const char *shortopts,\r
+    const char *longopts,\r
+    const char *datatype,\r
+    const char *glossary)\r
+{\r
+    return arg_strn(shortopts, longopts, datatype, 1, 1, glossary);\r
+}\r
+\r
+\r
+struct arg_str * arg_strn(\r
+    const char *shortopts,\r
+    const char *longopts,\r
+    const char *datatype,\r
+    int mincount,\r
+    int maxcount,\r
+    const char *glossary)\r
+{\r
+    size_t nbytes;\r
+    struct arg_str *result;\r
+\r
+    /* should not allow this stupid error */\r
+    /* we should return an error code warning this logic error */\r
+    /* foolproof things by ensuring maxcount is not less than mincount */\r
+    maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+    nbytes = sizeof(struct arg_str)     /* storage for struct arg_str */\r
+             + maxcount * sizeof(char *); /* storage for sval[maxcount] array */\r
+\r
+    result = (struct arg_str *)malloc(nbytes);\r
+    if (result)\r
+    {\r
+        int i;\r
+\r
+        /* init the arg_hdr struct */\r
+        result->hdr.flag      = ARG_HASVALUE;\r
+        result->hdr.shortopts = shortopts;\r
+        result->hdr.longopts  = longopts;\r
+        result->hdr.datatype  = datatype ? datatype : "<string>";\r
+        result->hdr.glossary  = glossary;\r
+        result->hdr.mincount  = mincount;\r
+        result->hdr.maxcount  = maxcount;\r
+        result->hdr.parent    = result;\r
+        result->hdr.resetfn   = (arg_resetfn *)arg_str_resetfn;\r
+        result->hdr.scanfn    = (arg_scanfn *)arg_str_scanfn;\r
+        result->hdr.checkfn   = (arg_checkfn *)arg_str_checkfn;\r
+        result->hdr.errorfn   = (arg_errorfn *)arg_str_errorfn;\r
+\r
+        /* store the sval[maxcount] array immediately after the arg_str struct */\r
+        result->sval  = (const char * *)(result + 1);\r
+        result->count = 0;\r
+\r
+        /* foolproof the string pointers by initialising them to reference empty strings */\r
+        for (i = 0; i < maxcount; i++)\r
+            result->sval[i] = "";\r
+    }\r
+    \r
+    ARG_TRACE(("arg_strn() returns %p\n", result));\r
+    return result;\r
+}\r
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *     * Redistributions of source code must retain the above copyright\r
+ *       notice, this list of conditions and the following disclaimer.\r
+ *     * Redistributions in binary form must reproduce the above copyright\r
+ *       notice, this list of conditions and the following disclaimer in the\r
+ *       documentation and/or other materials provided with the distribution.\r
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors\r
+ *       may be used to endorse or promote products derived from this software\r
+ *       without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <ctype.h>\r
+\r
+#include "argtable3.h"\r
+\r
+static\r
+void arg_register_error(struct arg_end *end,\r
+                        void *parent,\r
+                        int error,\r
+                        const char *argval)\r
+{\r
+    /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */\r
+    if (end->count < end->hdr.maxcount)\r
+    {\r
+        end->error[end->count] = error;\r
+        end->parent[end->count] = parent;\r
+        end->argval[end->count] = argval;\r
+        end->count++;\r
+    }\r
+    else\r
+    {\r
+        end->error[end->hdr.maxcount - 1]  = ARG_ELIMIT;\r
+        end->parent[end->hdr.maxcount - 1] = end;\r
+        end->argval[end->hdr.maxcount - 1] = NULL;\r
+    }\r
+}\r
+\r
+\r
+/*\r
+ * Return index of first table entry with a matching short option\r
+ * or -1 if no match was found.\r
+ */\r
+static\r
+int find_shortoption(struct arg_hdr * *table, char shortopt)\r
+{\r
+    int tabindex;\r
+    for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)\r
+    {\r
+        if (table[tabindex]->shortopts &&\r
+            strchr(table[tabindex]->shortopts, shortopt))\r
+            return tabindex;\r
+    }\r
+    return -1;\r
+}\r
+\r
+\r
+struct longoptions\r
+{\r
+    int getoptval;\r
+    int noptions;\r
+    struct option *options;\r
+};\r
+\r
+#if 0\r
+static\r
+void dump_longoptions(struct longoptions * longoptions)\r
+{\r
+    int i;\r
+    printf("getoptval = %d\n", longoptions->getoptval);\r
+    printf("noptions  = %d\n", longoptions->noptions);\r
+    for (i = 0; i < longoptions->noptions; i++)\r
+    {\r
+        printf("options[%d].name    = \"%s\"\n",\r
+               i,\r
+               longoptions->options[i].name);\r
+        printf("options[%d].has_arg = %d\n", i, longoptions->options[i].has_arg);\r
+        printf("options[%d].flag    = %p\n", i, longoptions->options[i].flag);\r
+        printf("options[%d].val     = %d\n", i, longoptions->options[i].val);\r
+    }\r
+}\r
+#endif\r
+\r
+static\r
+struct longoptions * alloc_longoptions(struct arg_hdr * *table)\r
+{\r
+    struct longoptions *result;\r
+    size_t nbytes;\r
+    int noptions = 1;\r
+    size_t longoptlen = 0;\r
+    int tabindex;\r
+\r
+    /*\r
+     * Determine the total number of option structs required\r
+     * by counting the number of comma separated long options\r
+     * in all table entries and return the count in noptions.\r
+     * note: noptions starts at 1 not 0 because we getoptlong\r
+     * requires a NULL option entry to terminate the option array.\r
+     * While we are at it, count the number of chars required\r
+     * to store private copies of all the longoption strings\r
+     * and return that count in logoptlen.\r
+     */\r
+    tabindex = 0;\r
+    do\r
+    {\r
+        const char *longopts = table[tabindex]->longopts;\r
+        longoptlen += (longopts ? strlen(longopts) : 0) + 1;\r
+        while (longopts)\r
+        {\r
+            noptions++;\r
+            longopts = strchr(longopts + 1, ',');\r
+        }\r
+    } while(!(table[tabindex++]->flag & ARG_TERMINATOR));\r
+    /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/\r
+\r
+\r
+    /* allocate storage for return data structure as: */\r
+    /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */\r
+    nbytes = sizeof(struct longoptions)\r
+             + sizeof(struct option) * noptions\r
+             + longoptlen;\r
+    result = (struct longoptions *)malloc(nbytes);\r
+    if (result)\r
+    {\r
+        int option_index = 0;\r
+        char *store;\r
+\r
+        result->getoptval = 0;\r
+        result->noptions = noptions;\r
+        result->options = (struct option *)(result + 1);\r
+        store = (char *)(result->options + noptions);\r
+\r
+        for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)\r
+        {\r
+            const char *longopts = table[tabindex]->longopts;\r
+\r
+            while(longopts && *longopts)\r
+            {\r
+                char *storestart = store;\r
+\r
+                /* copy progressive longopt strings into the store */\r
+                while (*longopts != 0 && *longopts != ',')\r
+                    *store++ = *longopts++;\r
+                *store++ = 0;\r
+                if (*longopts == ',')\r
+                    longopts++;\r
+                /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/\r
+\r
+                result->options[option_index].name    = storestart;\r
+                result->options[option_index].flag    = &(result->getoptval);\r
+                result->options[option_index].val     = tabindex;\r
+                if (table[tabindex]->flag & ARG_HASOPTVALUE)\r
+                    result->options[option_index].has_arg = 2;\r
+                else if (table[tabindex]->flag & ARG_HASVALUE)\r
+                    result->options[option_index].has_arg = 1;\r
+                else\r
+                    result->options[option_index].has_arg = 0;\r
+\r
+                option_index++;\r
+            }\r
+        }\r
+        /* terminate the options array with a zero-filled entry */\r
+        result->options[option_index].name    = 0;\r
+        result->options[option_index].has_arg = 0;\r
+        result->options[option_index].flag    = 0;\r
+        result->options[option_index].val     = 0;\r
+    }\r
+\r
+    /*dump_longoptions(result);*/\r
+    return result;\r
+}\r
+\r
+static\r
+char * alloc_shortoptions(struct arg_hdr * *table)\r
+{\r
+    char *result;\r
+    size_t len = 2;\r
+    int tabindex;\r
+\r
+    /* determine the total number of option chars required */\r
+    for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)\r
+    {\r
+        struct arg_hdr *hdr = table[tabindex];\r
+        len += 3 * (hdr->shortopts ? strlen(hdr->shortopts) : 0);\r
+    }\r
+\r
+    result = malloc(len);\r
+    if (result)\r
+    {\r
+        char *res = result;\r
+\r
+        /* add a leading ':' so getopt return codes distinguish    */\r
+        /* unrecognised option and options missing argument values */\r
+        *res++ = ':';\r
+\r
+        for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)\r
+        {\r
+            struct arg_hdr *hdr = table[tabindex];\r
+            const char *shortopts = hdr->shortopts;\r
+            while(shortopts && *shortopts)\r
+            {\r
+                *res++ = *shortopts++;\r
+                if (hdr->flag & ARG_HASVALUE)\r
+                    *res++ = ':';\r
+                if (hdr->flag & ARG_HASOPTVALUE)\r
+                    *res++ = ':';\r
+            }\r
+        }\r
+        /* null terminate the string */\r
+        *res = 0;\r
+    }\r
+\r
+    /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/\r
+    return result;\r
+}\r
+\r
+\r
+/* return index of the table terminator entry */\r
+static\r
+int arg_endindex(struct arg_hdr * *table)\r
+{\r
+    int tabindex = 0;\r
+    while (!(table[tabindex]->flag & ARG_TERMINATOR))\r
+        tabindex++;\r
+    return tabindex;\r
+}\r
+\r
+\r
+static\r
+void arg_parse_tagged(int argc,\r
+                      char * *argv,\r
+                      struct arg_hdr * *table,\r
+                      struct arg_end *endtable)\r
+{\r
+    struct longoptions *longoptions;\r
+    char *shortoptions;\r
+    int copt;\r
+\r
+    /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/\r
+\r
+    /* allocate short and long option arrays for the given opttable[].   */\r
+    /* if the allocs fail then put an error msg in the last table entry. */\r
+    longoptions  = alloc_longoptions(table);\r
+    shortoptions = alloc_shortoptions(table);\r
+    if (!longoptions || !shortoptions)\r
+    {\r
+        /* one or both memory allocs failed */\r
+        arg_register_error(endtable, endtable, ARG_EMALLOC, NULL);\r
+        /* free anything that was allocated (this is null safe) */\r
+        free(shortoptions);\r
+        free(longoptions);\r
+        return;\r
+    }\r
+\r
+    /*dump_longoptions(longoptions);*/\r
+\r
+    /* reset getopts internal option-index to zero, and disable error reporting */\r
+    optind = 0;\r
+    opterr = 0;\r
+\r
+    /* fetch and process args using getopt_long */\r
+    while( (copt =\r
+                getopt_long(argc, argv, shortoptions, longoptions->options,\r
+                            NULL)) != -1)\r
+    {\r
+        /*\r
+           printf("optarg='%s'\n",optarg);\r
+           printf("optind=%d\n",optind);\r
+           printf("copt=%c\n",(char)copt);\r
+           printf("optopt=%c (%d)\n",optopt, (int)(optopt));\r
+         */\r
+        switch(copt)\r
+        {\r
+        case 0:\r
+        {\r
+            int tabindex = longoptions->getoptval;\r
+            void *parent  = table[tabindex]->parent;\r
+            /*printf("long option detected from argtable[%d]\n", tabindex);*/\r
+            if (optarg && optarg[0] == 0 &&\r
+                (table[tabindex]->flag & ARG_HASVALUE))\r
+            {\r
+                /* printf(": long option %s requires an argument\n",argv[optind-1]); */\r
+                arg_register_error(endtable, endtable, ARG_EMISSARG,\r
+                                   argv[optind - 1]);\r
+                /* continue to scan the (empty) argument value to enforce argument count checking */\r
+            }\r
+            if (table[tabindex]->scanfn)\r
+            {\r
+                int errorcode = table[tabindex]->scanfn(parent, optarg);\r
+                if (errorcode != 0)\r
+                    arg_register_error(endtable, parent, errorcode, optarg);\r
+            }\r
+        }\r
+        break;\r
+\r
+        case '?':\r
+            /*\r
+             * getopt_long() found an unrecognised short option.\r
+             * if it was a short option its value is in optopt\r
+             * if it was a long option then optopt=0\r
+             */\r
+            switch (optopt)\r
+            {\r
+            case 0:\r
+                /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/\r
+                arg_register_error(endtable, endtable, ARG_ELONGOPT,\r
+                                   argv[optind - 1]);\r
+                break;\r
+            default:\r
+                /*printf("?* unrecognised short option '%c'\n",optopt);*/\r
+                arg_register_error(endtable, endtable, optopt, NULL);\r
+                break;\r
+            }\r
+            break;\r
+\r
+        case ':':\r
+            /*\r
+             * getopt_long() found an option with its argument missing.\r
+             */\r
+            /*printf(": option %s requires an argument\n",argv[optind-1]); */\r
+            arg_register_error(endtable, endtable, ARG_EMISSARG,\r
+                               argv[optind - 1]);\r
+            break;\r
+\r
+        default:\r
+        {\r
+            /* getopt_long() found a valid short option */\r
+            int tabindex = find_shortoption(table, (char)copt);\r
+            /*printf("short option detected from argtable[%d]\n", tabindex);*/\r
+            if (tabindex == -1)\r
+            {\r
+                /* should never get here - but handle it just in case */\r
+                /*printf("unrecognised short option %d\n",copt);*/\r
+                arg_register_error(endtable, endtable, copt, NULL);\r
+            }\r
+            else\r
+            {\r
+                if (table[tabindex]->scanfn)\r
+                {\r
+                    void *parent  = table[tabindex]->parent;\r
+                    int errorcode = table[tabindex]->scanfn(parent, optarg);\r
+                    if (errorcode != 0)\r
+                        arg_register_error(endtable, parent, errorcode, optarg);\r
+                }\r
+            }\r
+            break;\r
+        }\r
+        }\r
+    }\r
+\r
+    free(shortoptions);\r
+    free(longoptions);\r
+}\r
+\r
+\r
+static\r
+void arg_parse_untagged(int argc,\r
+                        char * *argv,\r
+                        struct arg_hdr * *table,\r
+                        struct arg_end *endtable)\r
+{\r
+    int tabindex = 0;\r
+    int errorlast = 0;\r
+    const char *optarglast = NULL;\r
+    void *parentlast = NULL;\r
+\r
+    /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/\r
+    while (!(table[tabindex]->flag & ARG_TERMINATOR))\r
+    {\r
+        void *parent;\r
+        int errorcode;\r
+\r
+        /* if we have exhausted our argv[optind] entries then we have finished */\r
+        if (optind >= argc)\r
+        {\r
+            /*printf("arg_parse_untagged(): argv[] exhausted\n");*/\r
+            return;\r
+        }\r
+\r
+        /* skip table entries with non-null long or short options (they are not untagged entries) */\r
+        if (table[tabindex]->longopts || table[tabindex]->shortopts)\r
+        {\r
+            /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/\r
+            tabindex++;\r
+            continue;\r
+        }\r
+\r
+        /* skip table entries with NULL scanfn */\r
+        if (!(table[tabindex]->scanfn))\r
+        {\r
+            /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/\r
+            tabindex++;\r
+            continue;\r
+        }\r
+\r
+        /* attempt to scan the current argv[optind] with the current     */\r
+        /* table[tabindex] entry. If it succeeds then keep it, otherwise */\r
+        /* try again with the next table[] entry.                        */\r
+        parent = table[tabindex]->parent;\r
+        errorcode = table[tabindex]->scanfn(parent, argv[optind]);\r
+        if (errorcode == 0)\r
+        {\r
+            /* success, move onto next argv[optind] but stay with same table[tabindex] */\r
+            /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/\r
+            optind++;\r
+\r
+            /* clear the last tentative error */\r
+            errorlast = 0;\r
+        }\r
+        else\r
+        {\r
+            /* failure, try same argv[optind] with next table[tabindex] entry */\r
+            /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/\r
+            tabindex++;\r
+\r
+            /* remember this as a tentative error we may wish to reinstate later */\r
+            errorlast = errorcode;\r
+            optarglast = argv[optind];\r
+            parentlast = parent;\r
+        }\r
+\r
+    }\r
+\r
+    /* if a tenative error still remains at this point then register it as a proper error */\r
+    if (errorlast)\r
+    {\r
+        arg_register_error(endtable, parentlast, errorlast, optarglast);\r
+        optind++;\r
+    }\r
+\r
+    /* only get here when not all argv[] entries were consumed */\r
+    /* register an error for each unused argv[] entry */\r
+    while (optind < argc)\r
+    {\r
+        /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/\r
+        arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind++]);\r
+    }\r
+\r
+    return;\r
+}\r
+\r
+\r
+static\r
+void arg_parse_check(struct arg_hdr * *table, struct arg_end *endtable)\r
+{\r
+    int tabindex = 0;\r
+    /* printf("arg_parse_check()\n"); */\r
+    do\r
+    {\r
+        if (table[tabindex]->checkfn)\r
+        {\r
+            void *parent  = table[tabindex]->parent;\r
+            int errorcode = table[tabindex]->checkfn(parent);\r
+            if (errorcode != 0)\r
+                arg_register_error(endtable, parent, errorcode, NULL);\r
+        }\r
+    } while(!(table[tabindex++]->flag & ARG_TERMINATOR));\r
+}\r
+\r
+\r
+static\r
+void arg_reset(void * *argtable)\r
+{\r
+    struct arg_hdr * *table = (struct arg_hdr * *)argtable;\r
+    int tabindex = 0;\r
+    /*printf("arg_reset(%p)\n",argtable);*/\r
+    do\r
+    {\r
+        if (table[tabindex]->resetfn)\r
+            table[tabindex]->resetfn(table[tabindex]->parent);\r
+    } while(!(table[tabindex++]->flag & ARG_TERMINATOR));\r
+}\r
+\r
+\r
+int arg_parse(int argc, char * *argv, void * *argtable)\r
+{\r
+    struct arg_hdr * *table = (struct arg_hdr * *)argtable;\r
+    struct arg_end *endtable;\r
+    int endindex;\r
+    char * *argvcopy = NULL;\r
+\r
+    /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/\r
+\r
+    /* reset any argtable data from previous invocations */\r
+    arg_reset(argtable);\r
+\r
+    /* locate the first end-of-table marker within the array */\r
+    endindex = arg_endindex(table);\r
+    endtable = (struct arg_end *)table[endindex];\r
+\r
+    /* Special case of argc==0.  This can occur on Texas Instruments DSP. */\r
+    /* Failure to trap this case results in an unwanted NULL result from  */\r
+    /* the malloc for argvcopy (next code block).                         */\r
+    if (argc == 0)\r
+    {\r
+        /* We must still perform post-parse checks despite the absence of command line arguments */\r
+        arg_parse_check(table, endtable);\r
+\r
+        /* Now we are finished */\r
+        return endtable->count;\r
+    }\r
+\r
+    argvcopy = (char **)malloc(sizeof(char *) * (argc + 1));\r
+    if (argvcopy)\r
+    {\r
+        int i;\r
+\r
+        /*\r
+           Fill in the local copy of argv[]. We need a local copy\r
+           because getopt rearranges argv[] which adversely affects\r
+           susbsequent parsing attempts.\r
+         */\r
+        for (i = 0; i < argc; i++)\r
+            argvcopy[i] = argv[i];\r
+\r
+        argvcopy[argc] = NULL;\r
+        \r
+        /* parse the command line (local copy) for tagged options */\r
+        arg_parse_tagged(argc, argvcopy, table, endtable);\r
+\r
+        /* parse the command line (local copy) for untagged options */\r
+        arg_parse_untagged(argc, argvcopy, table, endtable);\r
+\r
+        /* if no errors so far then perform post-parse checks otherwise dont bother */\r
+        if (endtable->count == 0)\r
+            arg_parse_check(table, endtable);\r
+\r
+        /* release the local copt of argv[] */\r
+        free(argvcopy);\r
+    }\r
+    else\r
+    {\r
+        /* memory alloc failed */\r
+        arg_register_error(endtable, endtable, ARG_EMALLOC, NULL);\r
+    }\r
+\r
+    return endtable->count;\r
+}\r
+\r
+\r
+/*\r
+ * Concatenate contents of src[] string onto *pdest[] string.\r
+ * The *pdest pointer is altered to point to the end of the\r
+ * target string and *pndest is decremented by the same number\r
+ * of chars.\r
+ * Does not append more than *pndest chars into *pdest[]\r
+ * so as to prevent buffer overruns.\r
+ * Its something like strncat() but more efficient for repeated\r
+ * calls on the same destination string.\r
+ * Example of use:\r
+ *   char dest[30] = "good"\r
+ *   size_t ndest = sizeof(dest);\r
+ *   char *pdest = dest;\r
+ *   arg_char(&pdest,"bye ",&ndest);\r
+ *   arg_char(&pdest,"cruel ",&ndest);\r
+ *   arg_char(&pdest,"world!",&ndest);\r
+ * Results in:\r
+ *   dest[] == "goodbye cruel world!"\r
+ *   ndest  == 10\r
+ */\r
+static\r
+void arg_cat(char * *pdest, const char *src, size_t *pndest)\r
+{\r
+    char *dest = *pdest;\r
+    char *end  = dest + *pndest;\r
+\r
+    /*locate null terminator of dest string */\r
+    while(dest < end && *dest != 0)\r
+        dest++;\r
+\r
+    /* concat src string to dest string */\r
+    while(dest < end && *src != 0)\r
+        *dest++ = *src++;\r
+\r
+    /* null terminate dest string */\r
+    *dest = 0;\r
+\r
+    /* update *pdest and *pndest */\r
+    *pndest = end - dest;\r
+    *pdest  = dest;\r
+}\r
+\r
+\r
+static\r
+void arg_cat_option(char *dest,\r
+                    size_t ndest,\r
+                    const char *shortopts,\r
+                    const char *longopts,\r
+                    const char *datatype,\r
+                    int optvalue)\r
+{\r
+    if (shortopts)\r
+    {\r
+        char option[3];\r
+\r
+        /* note: option array[] is initialiazed dynamically here to satisfy   */\r
+        /* a deficiency in the watcom compiler wrt static array initializers. */\r
+        option[0] = '-';\r
+        option[1] = shortopts[0];\r
+        option[2] = 0;\r
+\r
+        arg_cat(&dest, option, &ndest);\r
+        if (datatype)\r
+        {\r
+            arg_cat(&dest, " ", &ndest);\r
+            if (optvalue)\r
+            {\r
+                arg_cat(&dest, "[", &ndest);\r
+                arg_cat(&dest, datatype, &ndest);\r
+                arg_cat(&dest, "]", &ndest);\r
+            }\r
+            else\r
+                arg_cat(&dest, datatype, &ndest);\r
+        }\r
+    }\r
+    else if (longopts)\r
+    {\r
+        size_t ncspn;\r
+\r
+        /* add "--" tag prefix */\r
+        arg_cat(&dest, "--", &ndest);\r
+\r
+        /* add comma separated option tag */\r
+        ncspn = strcspn(longopts, ",");\r
+        strncat(dest, longopts, (ncspn < ndest) ? ncspn : ndest);\r
+\r
+        if (datatype)\r
+        {\r
+            arg_cat(&dest, "=", &ndest);\r
+            if (optvalue)\r
+            {\r
+                arg_cat(&dest, "[", &ndest);\r
+                arg_cat(&dest, datatype, &ndest);\r
+                arg_cat(&dest, "]", &ndest);\r
+            }\r
+            else\r
+                arg_cat(&dest, datatype, &ndest);\r
+        }\r
+    }\r
+    else if (datatype)\r
+    {\r
+        if (optvalue)\r
+        {\r
+            arg_cat(&dest, "[", &ndest);\r
+            arg_cat(&dest, datatype, &ndest);\r
+            arg_cat(&dest, "]", &ndest);\r
+        }\r
+        else\r
+            arg_cat(&dest, datatype, &ndest);\r
+    }\r
+}\r
+\r
+static\r
+void arg_cat_optionv(char *dest,\r
+                     size_t ndest,\r
+                     const char *shortopts,\r
+                     const char *longopts,\r
+                     const char *datatype,\r
+                     int optvalue,\r
+                     const char *separator)\r
+{\r
+    separator = separator ? separator : "";\r
+\r
+    if (shortopts)\r
+    {\r
+        const char *c = shortopts;\r
+        while(*c)\r
+        {\r
+            /* "-a|-b|-c" */\r
+            char shortopt[3];\r
+\r
+            /* note: shortopt array[] is initialiazed dynamically here to satisfy */\r
+            /* a deficiency in the watcom compiler wrt static array initializers. */\r
+            shortopt[0] = '-';\r
+            shortopt[1] = *c;\r
+            shortopt[2] = 0;\r
+\r
+            arg_cat(&dest, shortopt, &ndest);\r
+            if (*++c)\r
+                arg_cat(&dest, separator, &ndest);\r
+        }\r
+    }\r
+\r
+    /* put separator between long opts and short opts */\r
+    if (shortopts && longopts)\r
+        arg_cat(&dest, separator, &ndest);\r
+\r
+    if (longopts)\r
+    {\r
+        const char *c = longopts;\r
+        while(*c)\r
+        {\r
+            size_t ncspn;\r
+\r
+            /* add "--" tag prefix */\r
+            arg_cat(&dest, "--", &ndest);\r
+\r
+            /* add comma separated option tag */\r
+            ncspn = strcspn(c, ",");\r
+            strncat(dest, c, (ncspn < ndest) ? ncspn : ndest);\r
+            c += ncspn;\r
+\r
+            /* add given separator in place of comma */\r
+            if (*c == ',')\r
+            {\r
+                arg_cat(&dest, separator, &ndest);\r
+                c++;\r
+            }\r
+        }\r
+    }\r
+\r
+    if (datatype)\r
+    {\r
+        if (longopts)\r
+            arg_cat(&dest, "=", &ndest);\r
+        else if (shortopts)\r
+            arg_cat(&dest, " ", &ndest);\r
+\r
+        if (optvalue)\r
+        {\r
+            arg_cat(&dest, "[", &ndest);\r
+            arg_cat(&dest, datatype, &ndest);\r
+            arg_cat(&dest, "]", &ndest);\r
+        }\r
+        else\r
+            arg_cat(&dest, datatype, &ndest);\r
+    }\r
+}\r
+\r
+\r
+/* this function should be deprecated because it doesnt consider optional argument values (ARG_HASOPTVALUE) */\r
+void arg_print_option(FILE *fp,\r
+                      const char *shortopts,\r
+                      const char *longopts,\r
+                      const char *datatype,\r
+                      const char *suffix)\r
+{\r
+    char syntax[200] = "";\r
+    suffix = suffix ? suffix : "";\r
+\r
+    /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */\r
+    arg_cat_optionv(syntax,\r
+                    sizeof(syntax),\r
+                    shortopts,\r
+                    longopts,\r
+                    datatype,\r
+                    0,\r
+                    "|");\r
+\r
+    fputs(syntax, fp);\r
+    fputs(suffix, fp);\r
+}\r
+\r
+\r
+/*\r
+ * Print a GNU style [OPTION] string in which all short options that\r
+ * do not take argument values are presented in abbreviated form, as\r
+ * in: -xvfsd, or -xvf[sd], or [-xvsfd]\r
+ */\r
+static\r
+void arg_print_gnuswitch(FILE *fp, struct arg_hdr * *table)\r
+{\r
+    int tabindex;\r
+    char *format1 = " -%c";\r
+    char *format2 = " [-%c";\r
+    char *suffix = "";\r
+\r
+    /* print all mandatory switches that are without argument values */\r
+    for(tabindex = 0;\r
+        table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);\r
+        tabindex++)\r
+    {\r
+        /* skip optional options */\r
+        if (table[tabindex]->mincount < 1)\r
+            continue;\r
+\r
+        /* skip non-short options */\r
+        if (table[tabindex]->shortopts == NULL)\r
+            continue;\r
+\r
+        /* skip options that take argument values */\r
+        if (table[tabindex]->flag & ARG_HASVALUE)\r
+            continue;\r
+\r
+        /* print the short option (only the first short option char, ignore multiple choices)*/\r
+        fprintf(fp, format1, table[tabindex]->shortopts[0]);\r
+        format1 = "%c";\r
+        format2 = "[%c";\r
+    }\r
+\r
+    /* print all optional switches that are without argument values */\r
+    for(tabindex = 0;\r
+        table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);\r
+        tabindex++)\r
+    {\r
+        /* skip mandatory args */\r
+        if (table[tabindex]->mincount > 0)\r
+            continue;\r
+\r
+        /* skip args without short options */\r
+        if (table[tabindex]->shortopts == NULL)\r
+            continue;\r
+\r
+        /* skip args with values */\r
+        if (table[tabindex]->flag & ARG_HASVALUE)\r
+            continue;\r
+\r
+        /* print first short option */\r
+        fprintf(fp, format2, table[tabindex]->shortopts[0]);\r
+        format2 = "%c";\r
+        suffix = "]";\r
+    }\r
+\r
+    fprintf(fp, "%s", suffix);\r
+}\r
+\r
+\r
+void arg_print_syntax(FILE *fp, void * *argtable, const char *suffix)\r
+{\r
+    struct arg_hdr * *table = (struct arg_hdr * *)argtable;\r
+    int i, tabindex;\r
+\r
+    /* print GNU style [OPTION] string */\r
+    arg_print_gnuswitch(fp, table);\r
+\r
+    /* print remaining options in abbreviated style */\r
+    for(tabindex = 0;\r
+        table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);\r
+        tabindex++)\r
+    {\r
+        char syntax[200] = "";\r
+        const char *shortopts, *longopts, *datatype;\r
+\r
+        /* skip short options without arg values (they were printed by arg_print_gnu_switch) */\r
+        if (table[tabindex]->shortopts &&\r
+            !(table[tabindex]->flag & ARG_HASVALUE))\r
+            continue;\r
+\r
+        shortopts = table[tabindex]->shortopts;\r
+        longopts  = table[tabindex]->longopts;\r
+        datatype  = table[tabindex]->datatype;\r
+        arg_cat_option(syntax,\r
+                       sizeof(syntax),\r
+                       shortopts,\r
+                       longopts,\r
+                       datatype,\r
+                       table[tabindex]->flag & ARG_HASOPTVALUE);\r
+\r
+        if (strlen(syntax) > 0)\r
+        {\r
+            /* print mandatory instances of this option */\r
+            for (i = 0; i < table[tabindex]->mincount; i++)\r
+                fprintf(fp, " %s", syntax);\r
+\r
+            /* print optional instances enclosed in "[..]" */\r
+            switch ( table[tabindex]->maxcount - table[tabindex]->mincount )\r
+            {\r
+            case 0:\r
+                break;\r
+            case 1:\r
+                fprintf(fp, " [%s]", syntax);\r
+                break;\r
+            case 2:\r
+                fprintf(fp, " [%s] [%s]", syntax, syntax);\r
+                break;\r
+            default:\r
+                fprintf(fp, " [%s]...", syntax);\r
+                break;\r
+            }\r
+        }\r
+    }\r
+\r
+    if (suffix)\r
+        fprintf(fp, "%s", suffix);\r
+}\r
+\r
+\r
+void arg_print_syntaxv(FILE *fp, void * *argtable, const char *suffix)\r
+{\r
+    struct arg_hdr * *table = (struct arg_hdr * *)argtable;\r
+    int i, tabindex;\r
+\r
+    /* print remaining options in abbreviated style */\r
+    for(tabindex = 0;\r
+        table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);\r
+        tabindex++)\r
+    {\r
+        char syntax[200] = "";\r
+        const char *shortopts, *longopts, *datatype;\r
+\r
+        shortopts = table[tabindex]->shortopts;\r
+        longopts  = table[tabindex]->longopts;\r
+        datatype  = table[tabindex]->datatype;\r
+        arg_cat_optionv(syntax,\r
+                        sizeof(syntax),\r
+                        shortopts,\r
+                        longopts,\r
+                        datatype,\r
+                        table[tabindex]->flag & ARG_HASOPTVALUE,\r
+                        "|");\r
+\r
+        /* print mandatory options */\r
+        for (i = 0; i < table[tabindex]->mincount; i++)\r
+            fprintf(fp, " %s", syntax);\r
+\r
+        /* print optional args enclosed in "[..]" */\r
+        switch ( table[tabindex]->maxcount - table[tabindex]->mincount )\r
+        {\r
+        case 0:\r
+            break;\r
+        case 1:\r
+            fprintf(fp, " [%s]", syntax);\r
+            break;\r
+        case 2:\r
+            fprintf(fp, " [%s] [%s]", syntax, syntax);\r
+            break;\r
+        default:\r
+            fprintf(fp, " [%s]...", syntax);\r
+            break;\r
+        }\r
+    }\r
+\r
+    if (suffix)\r
+        fprintf(fp, "%s", suffix);\r
+}\r
+\r
+\r
+void arg_print_glossary(FILE *fp, void * *argtable, const char *format)\r
+{\r
+    struct arg_hdr * *table = (struct arg_hdr * *)argtable;\r
+    int tabindex;\r
+\r
+    format = format ? format : "  %-20s %s\n";\r
+    for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)\r
+    {\r
+        if (table[tabindex]->glossary)\r
+        {\r
+            char syntax[200] = "";\r
+            const char *shortopts = table[tabindex]->shortopts;\r
+            const char *longopts  = table[tabindex]->longopts;\r
+            const char *datatype  = table[tabindex]->datatype;\r
+            const char *glossary  = table[tabindex]->glossary;\r
+            arg_cat_optionv(syntax,\r
+                            sizeof(syntax),\r
+                            shortopts,\r
+                            longopts,\r
+                            datatype,\r
+                            table[tabindex]->flag & ARG_HASOPTVALUE,\r
+                            ", ");\r
+            fprintf(fp, format, syntax, glossary);\r
+        }\r
+    }\r
+}\r
+\r
+\r
+/**\r
+ * Print a piece of text formatted, which means in a column with a\r
+ * left and a right margin. The lines are wrapped at whitspaces next\r
+ * to right margin. The function does not indent the first line, but\r
+ * only the following ones.\r
+ *\r
+ * Example:\r
+ * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." )\r
+ * will result in the following output:\r
+ *\r
+ * Some\r
+ * text\r
+ * that\r
+ * doesn'\r
+ * t fit.\r
+ *\r
+ * Too long lines will be wrapped in the middle of a word.\r
+ *\r
+ * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." )\r
+ * will result in the following output:\r
+ *\r
+ * Some\r
+ *   text\r
+ *   that\r
+ *   doesn'\r
+ *   t fit.\r
+ *\r
+ * As you see, the first line is not indented. This enables output of\r
+ * lines, which start in a line where output already happened.\r
+ *\r
+ * Author: Uli Fouquet\r
+ */\r
+static\r
+void arg_print_formatted( FILE *fp,\r
+                          const unsigned lmargin,\r
+                          const unsigned rmargin,\r
+                          const char *text )\r
+{\r
+    const unsigned textlen = strlen( text );\r
+    unsigned line_start = 0;\r
+    unsigned line_end = textlen + 1;\r
+    const unsigned colwidth = (rmargin - lmargin) + 1;\r
+\r
+    /* Someone doesn't like us... */\r
+    if ( line_end < line_start )\r
+    { fprintf( fp, "%s\n", text ); }\r
+\r
+    while (line_end - 1 > line_start )\r
+    {\r
+        /* Eat leading whitespaces. This is essential because while\r
+           wrapping lines, there will often be a whitespace at beginning\r
+           of line */\r
+        while ( isspace(*(text + line_start)) )\r
+        { line_start++; }\r
+\r
+        if ((line_end - line_start) > colwidth )\r
+        { line_end = line_start + colwidth; }\r
+\r
+        /* Find last whitespace, that fits into line */\r
+        while ( ( line_end > line_start )\r
+                && ( line_end - line_start > colwidth )\r
+                && !isspace(*(text + line_end)))\r
+        { line_end--; }\r
+\r
+        /* Do not print trailing whitespace. If this text\r
+           has got only one line, line_end now points to the\r
+           last char due to initialization. */\r
+        line_end--;\r
+\r
+        /* Output line of text */\r
+        while ( line_start < line_end )\r
+        {\r
+            fputc(*(text + line_start), fp );\r
+            line_start++;\r
+        }\r
+        fputc( '\n', fp );\r
+\r
+        /* Initialize another line */\r
+        if ( line_end + 1 < textlen )\r
+        {\r
+            unsigned i;\r
+\r
+            for (i = 0; i < lmargin; i++ )\r
+            { fputc( ' ', fp ); }\r
+\r
+            line_end = textlen;\r
+        }\r
+\r
+        /* If we have to print another line, get also the last char. */\r
+        line_end++;\r
+\r
+    } /* lines of text */\r
+}\r
+\r
+/**\r
+ * Prints the glossary in strict GNU format.\r
+ * Differences to arg_print_glossary() are:\r
+ *   - wraps lines after 80 chars\r
+ *   - indents lines without shortops\r
+ *   - does not accept formatstrings\r
+ *\r
+ * Contributed by Uli Fouquet\r
+ */\r
+void arg_print_glossary_gnu(FILE *fp, void * *argtable )\r
+{\r
+    struct arg_hdr * *table = (struct arg_hdr * *)argtable;\r
+    int tabindex;\r
+\r
+    for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)\r
+    {\r
+        if (table[tabindex]->glossary)\r
+        {\r
+            char syntax[200] = "";\r
+            const char *shortopts = table[tabindex]->shortopts;\r
+            const char *longopts  = table[tabindex]->longopts;\r
+            const char *datatype  = table[tabindex]->datatype;\r
+            const char *glossary  = table[tabindex]->glossary;\r
+\r
+            if ( !shortopts && longopts )\r
+            {\r
+                /* Indent trailing line by 4 spaces... */\r
+                memset( syntax, ' ', 4 );\r
+                *(syntax + 4) = '\0';\r
+            }\r
+\r
+            arg_cat_optionv(syntax,\r
+                            sizeof(syntax),\r
+                            shortopts,\r
+                            longopts,\r
+                            datatype,\r
+                            table[tabindex]->flag & ARG_HASOPTVALUE,\r
+                            ", ");\r
+\r
+            /* If syntax fits not into column, print glossary in new line... */\r
+            if ( strlen(syntax) > 25 )\r
+            {\r
+                fprintf( fp, "  %-25s %s\n", syntax, "" );\r
+                *syntax = '\0';\r
+            }\r
+\r
+            fprintf( fp, "  %-25s ", syntax );\r
+            arg_print_formatted( fp, 28, 79, glossary );\r
+        }\r
+    } /* for each table entry */\r
+\r
+    fputc( '\n', fp );\r
+}\r
+\r
+\r
+/**\r
+ * Checks the argtable[] array for NULL entries and returns 1\r
+ * if any are found, zero otherwise.\r
+ */\r
+int arg_nullcheck(void * *argtable)\r
+{\r
+    struct arg_hdr * *table = (struct arg_hdr * *)argtable;\r
+    int tabindex;\r
+    /*printf("arg_nullcheck(%p)\n",argtable);*/\r
+\r
+    if (!table)\r
+        return 1;\r
+\r
+    tabindex = 0;\r
+    do\r
+    {\r
+        /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/\r
+        if (!table[tabindex])\r
+            return 1;\r
+    } while(!(table[tabindex++]->flag & ARG_TERMINATOR));\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+/*\r
+ * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design.\r
+ * The flaw results in memory leak in the (very rare) case that an intermediate\r
+ * entry in the argtable array failed its memory allocation while others following\r
+ * that entry were still allocated ok. Those subsequent allocations will not be\r
+ * deallocated by arg_free().\r
+ * Despite the unlikeliness of the problem occurring, and the even unlikelier event\r
+ * that it has any deliterious effect, it is fixed regardless by replacing arg_free()\r
+ * with the newer arg_freetable() function.\r
+ * We still keep arg_free() for backwards compatibility.\r
+ */\r
+void arg_free(void * *argtable)\r
+{\r
+    struct arg_hdr * *table = (struct arg_hdr * *)argtable;\r
+    int tabindex = 0;\r
+    int flag;\r
+    /*printf("arg_free(%p)\n",argtable);*/\r
+    do\r
+    {\r
+        /*\r
+           if we encounter a NULL entry then somewhat incorrectly we presume\r
+           we have come to the end of the array. It isnt strictly true because\r
+           an intermediate entry could be NULL with other non-NULL entries to follow.\r
+           The subsequent argtable entries would then not be freed as they should.\r
+         */\r
+        if (table[tabindex] == NULL)\r
+            break;\r
+\r
+        flag = table[tabindex]->flag;\r
+        free(table[tabindex]);\r
+        table[tabindex++] = NULL;\r
+\r
+    } while(!(flag & ARG_TERMINATOR));\r
+}\r
+\r
+/* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */\r
+void arg_freetable(void * *argtable, size_t n)\r
+{\r
+    struct arg_hdr * *table = (struct arg_hdr * *)argtable;\r
+    size_t tabindex = 0;\r
+    /*printf("arg_freetable(%p)\n",argtable);*/\r
+    for (tabindex = 0; tabindex < n; tabindex++)\r
+    {\r
+        if (table[tabindex] == NULL)\r
+            continue;\r
+\r
+        free(table[tabindex]);\r
+        table[tabindex] = NULL;\r
+    };\r
+}\r
+\r
diff --git a/src/argtable3.h b/src/argtable3.h
new file mode 100755 (executable)
index 0000000..1107de2
--- /dev/null
@@ -0,0 +1,305 @@
+/*******************************************************************************
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ * <sheitmann@users.sourceforge.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of STEWART HEITMANN nor the  names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       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 STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#ifndef ARGTABLE3
+#define ARGTABLE3
+
+#include <stdio.h>      /* FILE */
+#include <time.h>       /* struct tm */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ARG_REX_ICASE 1
+    
+/* bit masks for arg_hdr.flag */
+enum
+{
+    ARG_TERMINATOR=0x1,
+    ARG_HASVALUE=0x2,
+    ARG_HASOPTVALUE=0x4
+};
+
+typedef void (arg_resetfn)(void *parent);
+typedef int  (arg_scanfn)(void *parent, const char *argval);
+typedef int  (arg_checkfn)(void *parent);
+typedef void (arg_errorfn)(void *parent, FILE *fp, int error, const char *argval, const char *progname);
+
+
+/*
+* The arg_hdr struct defines properties that are common to all arg_xxx structs.
+* The argtable library requires each arg_xxx struct to have an arg_hdr
+* struct as its first data member.
+* The argtable library functions then use this data to identify the
+* properties of the command line option, such as its option tags,
+* datatype string, and glossary strings, and so on.
+* Moreover, the arg_hdr struct contains pointers to custom functions that
+* are provided by each arg_xxx struct which perform the tasks of parsing
+* that particular arg_xxx arguments, performing post-parse checks, and
+* reporting errors.
+* These functions are private to the individual arg_xxx source code
+* and are the pointer to them are initiliased by that arg_xxx struct's
+* constructor function. The user could alter them after construction
+* if desired, but the original intention is for them to be set by the
+* constructor and left unaltered.
+*/
+struct arg_hdr
+{
+    char         flag;        /* Modifier flags: ARG_TERMINATOR, ARG_HASVALUE. */
+    const char  *shortopts;   /* String defining the short options */
+    const char  *longopts;    /* String defiing the long options */
+    const char  *datatype;    /* Description of the argument data type */
+    const char  *glossary;    /* Description of the option as shown by arg_print_glossary function */
+    int          mincount;    /* Minimum number of occurences of this option accepted */
+    int          maxcount;    /* Maximum number of occurences if this option accepted */
+    void        *parent;      /* Pointer to parent arg_xxx struct */
+    arg_resetfn *resetfn;     /* Pointer to parent arg_xxx reset function */
+    arg_scanfn  *scanfn;      /* Pointer to parent arg_xxx scan function */
+    arg_checkfn *checkfn;     /* Pointer to parent arg_xxx check function */
+    arg_errorfn *errorfn;     /* Pointer to parent arg_xxx error function */
+    void        *priv;        /* Pointer to private header data for use by arg_xxx functions */
+};
+
+struct arg_rem
+{
+    struct arg_hdr hdr;      /* The mandatory argtable header struct */
+};
+
+struct arg_lit
+{
+    struct arg_hdr hdr;      /* The mandatory argtable header struct */
+    int count;               /* Number of matching command line args */
+};
+
+struct arg_int
+{
+    struct arg_hdr hdr;      /* The mandatory argtable header struct */
+    int count;               /* Number of matching command line args */
+    int *ival;               /* Array of parsed argument values */
+};
+
+struct arg_dbl
+{
+    struct arg_hdr hdr;      /* The mandatory argtable header struct */
+    int count;               /* Number of matching command line args */
+    double *dval;            /* Array of parsed argument values */
+};
+
+struct arg_str
+{
+    struct arg_hdr hdr;      /* The mandatory argtable header struct */
+    int count;               /* Number of matching command line args */
+    const char **sval;       /* Array of parsed argument values */
+};
+
+struct arg_rex
+{
+    struct arg_hdr hdr;      /* The mandatory argtable header struct */
+    int count;               /* Number of matching command line args */
+    const char **sval;       /* Array of parsed argument values */
+};
+
+struct arg_file
+{
+    struct arg_hdr hdr;      /* The mandatory argtable header struct */
+    int count;               /* Number of matching command line args*/
+    const char **filename;   /* Array of parsed filenames  (eg: /home/foo.bar) */
+    const char **basename;   /* Array of parsed basenames  (eg: foo.bar) */
+    const char **extension;  /* Array of parsed extensions (eg: .bar) */
+};
+
+struct arg_date
+{
+    struct arg_hdr hdr;      /* The mandatory argtable header struct */
+    const char *format;      /* strptime format string used to parse the date */
+    int count;               /* Number of matching command line args */
+    struct tm *tmval;        /* Array of parsed time values */
+};
+
+enum {ARG_ELIMIT=1, ARG_EMALLOC, ARG_ENOMATCH, ARG_ELONGOPT, ARG_EMISSARG};
+struct arg_end
+{
+    struct arg_hdr hdr;      /* The mandatory argtable header struct */
+    int count;               /* Number of errors encountered */
+    int *error;              /* Array of error codes */
+    void **parent;           /* Array of pointers to offending arg_xxx struct */
+    const char **argval;     /* Array of pointers to offending argv[] string */
+};
+
+
+/**** arg_xxx constructor functions *********************************/
+
+struct arg_rem* arg_rem(const char* datatype, const char* glossary);
+
+struct arg_lit* arg_lit0(const char* shortopts,
+    const char* longopts,
+    const char* glossary);
+struct arg_lit* arg_lit1(const char* shortopts,
+    const char* longopts,
+    const char *glossary);
+struct arg_lit* arg_litn(const char* shortopts,
+    const char* longopts,
+    int mincount,
+    int maxcount,
+    const char *glossary);
+
+struct arg_key* arg_key0(const char* keyword,
+    int flags,
+    const char* glossary);
+struct arg_key* arg_key1(const char* keyword,
+    int flags,
+    const char* glossary);
+struct arg_key* arg_keyn(const char* keyword,
+    int flags,
+    int mincount,
+    int maxcount,
+    const char* glossary);
+
+struct arg_int* arg_int0(const char* shortopts,
+    const char* longopts,
+    const char* datatype,
+    const char* glossary);
+struct arg_int* arg_int1(const char* shortopts,
+    const char* longopts,
+    const char* datatype,
+    const char *glossary);
+struct arg_int* arg_intn(const char* shortopts,
+    const char* longopts,
+    const char *datatype,
+    int mincount,
+    int maxcount,
+    const char *glossary);
+
+struct arg_dbl* arg_dbl0(const char* shortopts,
+    const char* longopts,
+    const char* datatype,
+    const char* glossary);
+struct arg_dbl* arg_dbl1(const char* shortopts,
+    const char* longopts,
+    const char* datatype,
+    const char *glossary);
+struct arg_dbl* arg_dbln(const char* shortopts,
+    const char* longopts,
+    const char *datatype,
+    int mincount,
+    int maxcount,
+    const char *glossary);
+
+struct arg_str* arg_str0(const char* shortopts,
+    const char* longopts,
+    const char* datatype,
+    const char* glossary);
+struct arg_str* arg_str1(const char* shortopts,
+    const char* longopts,                    
+    const char* datatype,
+    const char *glossary);
+struct arg_str* arg_strn(const char* shortopts,
+    const char* longopts,
+    const char* datatype,
+    int mincount,
+    int maxcount,
+    const char *glossary);
+
+struct arg_rex* arg_rex0(const char* shortopts,
+    const char* longopts,
+    const char* pattern,
+    const char* datatype,
+    int flags,
+    const char* glossary);
+struct arg_rex* arg_rex1(const char* shortopts,
+    const char* longopts,
+    const char* pattern,
+    const char* datatype,
+    int flags,
+    const char *glossary);
+struct arg_rex* arg_rexn(const char* shortopts,
+    const char* longopts,
+    const char* pattern,
+    const char* datatype,
+    int mincount,
+    int maxcount,
+    int flags,
+    const char *glossary);
+
+struct arg_file* arg_file0(const char* shortopts,
+    const char* longopts,
+    const char* datatype,
+    const char* glossary);
+struct arg_file* arg_file1(const char* shortopts,
+    const char* longopts,
+    const char* datatype,
+    const char *glossary);
+struct arg_file* arg_filen(const char* shortopts,
+    const char* longopts,
+    const char* datatype,
+    int mincount,
+    int maxcount,
+    const char *glossary);
+
+struct arg_date* arg_date0(const char* shortopts,
+    const char* longopts,
+    const char* format,
+    const char* datatype,
+    const char* glossary);
+struct arg_date* arg_date1(const char* shortopts,
+    const char* longopts,
+    const char* format,
+    const char* datatype,
+    const char *glossary);
+struct arg_date* arg_daten(const char* shortopts,
+    const char* longopts,
+    const char* format,
+    const char* datatype,
+    int mincount,
+    int maxcount,
+    const char *glossary);
+
+struct arg_end* arg_end(int maxerrors);
+
+
+/**** other functions *******************************************/
+int arg_nullcheck(void **argtable);
+int arg_parse(int argc, char **argv, void **argtable);
+void arg_print_option(FILE *fp, const char *shortopts, const char *longopts, const char *datatype, const char *suffix);
+void arg_print_syntax(FILE *fp, void **argtable, const char *suffix);
+void arg_print_syntaxv(FILE *fp, void **argtable, const char *suffix);
+void arg_print_glossary(FILE *fp, void **argtable, const char *format);
+void arg_print_glossary_gnu(FILE *fp, void **argtable);
+void arg_print_errors(FILE* fp, struct arg_end* end, const char* progname);
+void arg_freetable(void **argtable, size_t n);
+
+/**** deprecated functions, for back-compatibility only ********/
+void arg_free(void **argtable);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/char.c b/src/char.c
new file mode 100644 (file)
index 0000000..f9d1259
--- /dev/null
@@ -0,0 +1,154 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file char.c
+
+       @brief Character lookup utility functions
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+#include <stdlib.h>
+
+#include "char.h"
+
+
+/// Create this lookup table using char_lookup.c
+static unsigned char smart_char_type[256] = {
+ 16,  0,  0,  0,  0,  0,  0,  0,  0,  1, 16,  0,  0, 16,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  2,  2,  2,  2,  2,  2,
+  2,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  2,  2,
+  2,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  2,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
+};
+
+
+static int CHAR_ALPHANUMERIC = CHAR_ALPHA | CHAR_DIGIT;
+
+static int CHAR_WHITESPACE_OR_PUNCTUATION = CHAR_WHITESPACE | CHAR_PUNCTUATION;
+
+static int CHAR_WHITESPACE_OR_LINE_ENDING = CHAR_WHITESPACE | CHAR_LINE_ENDING;
+
+static int CHAR_WHITESPACE_OR_LINE_ENDING_OR_PUNCTUATION = CHAR_WHITESPACE | CHAR_LINE_ENDING | CHAR_PUNCTUATION;
+
+
+// Is character whitespace?
+int char_is_whitespace(char c) {
+       return smart_char_type[(unsigned char) c] & CHAR_WHITESPACE;
+}
+
+// Is character a newline, return, or EOF?
+int char_is_line_ending(char c) {
+       return smart_char_type[(unsigned char) c] & CHAR_LINE_ENDING;
+}
+
+// Is character part of Windows line ending ('\r\n')?
+int char_is_windows_line_ending(char * c) {
+       if (*c == '\n')
+               return (*(c - 1) == '\r') ? 1 : 0;
+
+       if (*c == '\r')
+               return (*(c + 1) == '\n') ? 1 : 0;
+
+       return 0;
+}
+
+#ifdef TEST
+void Test_char_is_windows_line_ending(CuTest* tc) {
+       char * test = "\r\n\n";
+       
+       CuAssertIntEquals(tc, 1, char_is_windows_line_ending(&test[0]));
+       CuAssertIntEquals(tc, 1, char_is_windows_line_ending(&test[1]));
+       CuAssertIntEquals(tc, 0, char_is_windows_line_ending(&test[2]));
+}
+#endif
+
+// Is character punctuation?
+int char_is_punctuation(char c) {
+       return smart_char_type[(unsigned char) c] & CHAR_PUNCTUATION;   
+}
+
+// Is character alpha?
+int char_is_alpha(char c) {
+       return smart_char_type[(unsigned char) c] & CHAR_ALPHA; 
+}
+
+// Is character digit?
+int char_is_digit(char c) {
+       return smart_char_type[(unsigned char) c] & CHAR_DIGIT; 
+}
+
+// Is character alphanumeric?
+int char_is_alphanumeric(char c) {
+       return smart_char_type[(unsigned char) c] & CHAR_ALPHANUMERIC;  
+}
+
+// Is character either whitespace or line ending?
+int char_is_whitespace_or_line_ending(char c) {
+       return smart_char_type[(unsigned char) c] & CHAR_WHITESPACE_OR_LINE_ENDING;
+}
+
+// Is character either whitespace or punctuation?
+int char_is_whitespace_or_punctuation(char c) {
+       return smart_char_type[(unsigned char) c] & CHAR_WHITESPACE_OR_PUNCTUATION;
+}
+
+// Is character either whitespace or line ending or punctuation?
+int char_is_whitespace_or_line_ending_or_punctuation(char c) {
+       return smart_char_type[(unsigned char) c] & CHAR_WHITESPACE_OR_LINE_ENDING_OR_PUNCTUATION;      
+}
diff --git a/src/char.h b/src/char.h
new file mode 100644 (file)
index 0000000..acd50af
--- /dev/null
@@ -0,0 +1,107 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file char.h
+
+       @brief Character lookup utility functions
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+
+#ifndef CHAR_SMART_STRING_H
+#define CHAR_SMART_STRING_H
+
+#ifdef TEST
+#include "CuTest.h"
+#endif
+
+/// Define character types
+enum char_types {
+       CHAR_WHITESPACE                 = 1 << 0,       //!< ' ','\t'
+       CHAR_PUNCTUATION                = 1 << 1,       //!< .!?,;:"'`~(){}[]#$%+-=<>&@\/^*_|
+       CHAR_ALPHA                              = 1 << 2,       //!< a-zA-Z
+       CHAR_DIGIT                              = 1 << 3,       //!< 0-9
+       CHAR_LINE_ENDING                = 1 << 4,       //!< \n,\r,\0
+};
+
+
+// Is character whitespace?
+int char_is_whitespace(char c);
+
+// Is character a newline, return, or EOF?
+int char_is_line_ending(char c);
+
+// Is character part of Windows line ending ('\r\n')?
+int char_is_windows_line_ending(char * c);
+
+// Is character punctuation?
+int char_is_punctuation(char c);
+
+// Is character alpha?
+int char_is_alpha(char c);
+
+// Is character digit?
+int char_is_digit(char c);
+
+// Is character alphanumeric?
+int char_is_alphanumeric(char c);
+
+// Is character either whitespace or line ending?
+int char_is_whitespace_or_line_ending(char c);
+
+// Is character either whitespace or punctuation?
+int char_is_whitespace_or_punctuation(char c);
+
+// Is character either whitespace or line ending or punctuation?
+int char_is_whitespace_or_line_ending_or_punctuation(char c);
+
+// Is byte a UTF-8 continuation byte
+#define char_is_continuation_byte(x) ((x & 0xC0) == 0x80)
+
+#endif
+
diff --git a/src/char_lookup.c b/src/char_lookup.c
new file mode 100644 (file)
index 0000000..200e682
--- /dev/null
@@ -0,0 +1,157 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file char_lookup.c
+
+       @brief Create lookup table for char.c
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "char.h"
+
+// Shortcuts to assign values to characters in lookup table
+#define punctuation(x) table[x] |= CHAR_PUNCTUATION
+#define whitespace(x)  table[x] |= CHAR_WHITESPACE
+#define alpha(x)               table[x] |= CHAR_ALPHA
+#define digit(x)               table[x] |= CHAR_DIGIT
+#define line_ending(x) table[x] |= CHAR_LINE_ENDING
+
+
+int main( int argc, char** argv ) {
+       unsigned char table[256] = {0};
+
+       // Define punctuation
+       // TODO: Need to go through extended ASCII codes for 
+       // additional whitespace characters
+       punctuation('.');
+       punctuation('!');
+       punctuation('?');
+
+       punctuation(',');
+       punctuation(';');
+       punctuation(':');
+
+       punctuation('"');
+       punctuation('\'');
+       punctuation('`');
+       punctuation('~');
+
+       punctuation('(');
+       punctuation(')');
+       punctuation('{');
+       punctuation('}');
+       punctuation('[');
+       punctuation(']');
+
+       punctuation('#');
+       punctuation('$');
+       punctuation('%');
+       punctuation('+');
+       punctuation('-');
+       punctuation('=');
+       punctuation('<');
+       punctuation('>');
+
+       punctuation('&');
+       punctuation('@');
+       punctuation('\\');
+       punctuation('/');
+       punctuation('^');
+
+       punctuation('*');
+       punctuation('_');
+
+       punctuation('|');
+
+
+       // Define whitespace
+       // TODO: Need to go through extended ASCII codes for 
+       // additional whitespace characters
+       whitespace(' ');
+       whitespace('\t');
+
+
+       // Define line endings
+       line_ending('\n');
+       line_ending('\r');
+       line_ending('\0');              // Count EOF as line ending
+
+
+       // Define digits
+       for (char i = '0'; i <= '9'; ++i)
+       {
+               digit(i);
+       }
+
+       // Define alpha
+       // TODO: Need to go through extended ASCII codes for 
+       // additional alpha characters
+       for (char i = 'a'; i <= 'z'; ++i)
+       {
+               alpha(i);
+       }
+       for (char i = 'A'; i <= 'Z'; ++i)
+       {
+               alpha(i);
+       }
+
+       // Print output as 16 x 16 table
+       for (int i = 0; i < 16; ++i)
+       {
+               for (int j = 0; j < 16; ++j)
+               {
+                       fprintf(stdout, "%3d,", table[i * 16 + j]);
+               }
+
+               fprintf(stdout, "\n");
+       }
+}
index 93d86540a2171b017023b020bc5730f860a60b51..60f12db358fb6dc5dc7bfc957da6872bfa02bb94 100644 (file)
@@ -1,13 +1,15 @@
 /**
 
-       Smart String -- Library to abstract smart typing features from MMD Composer
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
 
        @file d_string.c
 
-       @brief Dynamic string -- refactoring of old GLibFacade
+       @brief Dynamic string -- refactoring of old GLibFacade.  Provides a string
+       "object" that can grow to accomodate any size content that is appended.
 
 
        @author Daniel Jalkut, modified by Fletcher T. Penney and Dan Lowe
+
        @bug    
 
 **/
 /*
 
        Copyright © 2011 Daniel Jalkut.
-       Modifications by Fletcher T. Penney, Copyright © 2011-2016 Fletcher T. Penney.
+       Modifications by Fletcher T. Penney, Copyright © 2011-2017 Fletcher T. Penney.
        Modifications by Dan Lowe, Copyright © 2011 Dan Lowe.
 
 
-       The `c-template` project is released under the MIT License.
+       The `MultiMarkdown 6` project is released under the MIT License..
        
        GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
        
@@ -54,6 +56,7 @@
 
 */
 
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -99,12 +102,18 @@ int asprintf( char **sptr, char *fmt, ... )
 
 /* DString */
 
-#define kStringBufferStartingSize 1024
-#define kStringBufferGrowthMultiplier 2
+#define kStringBufferStartingSize 1024                                 //!< Default size of string buffer capacity
+#define kStringBufferGrowthMultiplier 2                                        //!< Multiply capacity by this factor when more space is needed
+#define kStringBufferMaxIncrement 1024 * 1024 * 100            //!< Maximum growth increment when resizing (to limit exponential growth)
 
-DString* d_string_new(const char *startingString)
+
+/// Create a new dynamic string
+DString* d_string_new(const char * startingString)
 {
        DString* newString = malloc(sizeof(DString));
+       
+       if (!newString)
+               return NULL;
 
        if (startingString == NULL) startingString = "";
 
@@ -116,6 +125,12 @@ DString* d_string_new(const char *startingString)
        }
        
        newString->str = malloc(startingBufferSize);
+
+       if (!newString->str) {
+               free(newString);
+               return NULL;
+       }
+
        newString->currentStringBufferSize = startingBufferSize;
        strncpy(newString->str, startingString, startingStringSize);
        newString->str[startingStringSize] = '\0';
@@ -124,7 +139,9 @@ DString* d_string_new(const char *startingString)
        return newString;
 }
 
-char* d_string_free(DString* ripString, bool freeCharacterData)
+
+/// Free dynamic string
+char* d_string_free(DString * ripString, bool freeCharacterData)
 {      
        if (ripString == NULL)
                return NULL;
@@ -144,7 +161,9 @@ char* d_string_free(DString* ripString, bool freeCharacterData)
        return returnedString;
 }
 
-static void ensureStringBufferCanHold(DString* baseString, size_t newStringSize)
+
+/// Ensure that dynamic string has specified capacity
+static void ensureStringBufferCanHold(DString * baseString, size_t newStringSize)
 {
        size_t newBufferSizeNeeded = newStringSize + 1;
        if (newBufferSizeNeeded > baseString->currentStringBufferSize)
@@ -153,7 +172,11 @@ static void ensureStringBufferCanHold(DString* baseString, size_t newStringSize)
 
                while (newBufferSizeNeeded > newBufferSize)
                {
-                       newBufferSize *= kStringBufferGrowthMultiplier;
+                       if (newBufferSize > kStringBufferMaxIncrement) {
+                               newBufferSize += kStringBufferMaxIncrement;
+                       } else {
+                               newBufferSize *= kStringBufferGrowthMultiplier;
+                       }
                }
                
         char *temp;
@@ -161,7 +184,7 @@ static void ensureStringBufferCanHold(DString* baseString, size_t newStringSize)
         
         if (temp == NULL) {
             /* realloc failed */
-            fprintf(stderr, "error reallocating memory\n");
+            fprintf(stderr, "Error reallocating memory for d_string. Current buffer size %lu.\n",baseString->currentStringBufferSize);
 
             exit(1);
         }
@@ -170,11 +193,14 @@ static void ensureStringBufferCanHold(DString* baseString, size_t newStringSize)
        }
 }
 
-void d_string_append(DString* baseString, char* appendedString)
+
+/// Append null-terminated string to end of dynamic string
+void d_string_append(DString * baseString, const char * appendedString)
 {
-       if ((appendedString != NULL) && (strlen(appendedString) > 0))
+       size_t appendedStringLength = strlen(appendedString);
+
+       if ((appendedString != NULL) && (appendedStringLength > 0))
        {
-               size_t appendedStringLength = strlen(appendedString);
                size_t newStringLength = baseString->currentStringLength + appendedStringLength;
                ensureStringBufferCanHold(baseString, newStringLength);
 
@@ -184,7 +210,9 @@ void d_string_append(DString* baseString, char* appendedString)
        }
 }
 
-void d_string_append_c(DString* baseString, char appendedCharacter)
+
+/// Append single character to end of dynamic string
+void d_string_append_c(DString * baseString, char appendedCharacter)
 {      
        size_t newSizeNeeded = baseString->currentStringLength + 1;
        ensureStringBufferCanHold(baseString, newSizeNeeded);
@@ -194,7 +222,9 @@ void d_string_append_c(DString* baseString, char appendedCharacter)
        baseString->str[baseString->currentStringLength] = '\0';
 }
 
-void d_string_append_c_array(DString *baseString, const char * appendedChars, size_t bytes)
+
+/// Append array of characters to end of dynamic string
+void d_string_append_c_array(DString * baseString, const char * appendedChars, size_t bytes)
 {
        size_t newSizeNeeded = baseString->currentStringLength + bytes;
        ensureStringBufferCanHold(baseString, newSizeNeeded);
@@ -205,7 +235,9 @@ void d_string_append_c_array(DString *baseString, const char * appendedChars, si
        baseString->str[baseString->currentStringLength] = '\0';
 }
 
-void d_string_append_printf(DString* baseString, char* format, ...)
+
+/// Append to end of dynamic string using format specifier
+void d_string_append_printf(DString * baseString, const char * format, ...)
 {
        va_list args;
        va_start(args, format);
@@ -220,11 +252,14 @@ void d_string_append_printf(DString* baseString, char* format, ...)
        va_end(args);
 } 
 
-void d_string_prepend(DString* baseString, char* prependedString)
+
+/// Prepend null-terminated string to end of dynamic string
+void d_string_prepend(DString * baseString, const char * prependedString)
 {
-       if ((prependedString != NULL) && (strlen(prependedString) > 0))
+       size_t prependedStringLength = strlen(prependedString);
+
+       if ((prependedString != NULL) && (prependedStringLength > 0))
        {
-               size_t prependedStringLength = strlen(prependedString);
                size_t newStringLength = baseString->currentStringLength + prependedStringLength;
                ensureStringBufferCanHold(baseString, newStringLength);
 
@@ -235,14 +270,17 @@ void d_string_prepend(DString* baseString, char* prependedString)
        }
 }
 
-void d_string_insert(DString* baseString, size_t pos, const char * insertedString)
+
+/// Insert null-terminated string inside dynamic string
+void d_string_insert(DString * baseString, size_t pos, const char * insertedString)
 {
-       if ((insertedString != NULL) && (strlen(insertedString) > 0))
+       size_t insertedStringLength = strlen(insertedString);
+
+       if ((insertedString != NULL) && (insertedStringLength > 0))
        {
                if (pos > baseString->currentStringLength)
                        pos = baseString->currentStringLength;
                
-               size_t insertedStringLength = strlen(insertedString);
                size_t newStringLength = baseString->currentStringLength + insertedStringLength;
                ensureStringBufferCanHold(baseString, newStringLength);
                
@@ -254,7 +292,9 @@ void d_string_insert(DString* baseString, size_t pos, const char * insertedStrin
        }
 }
 
-void d_string_insert_c(DString* baseString, size_t pos, char insertedCharacter)
+
+/// Insert single character inside dynamic string
+void d_string_insert_c(DString * baseString, size_t pos, char insertedCharacter)
 {      
        if (pos > baseString->currentStringLength)
                pos = baseString->currentStringLength;
@@ -271,7 +311,8 @@ void d_string_insert_c(DString* baseString, size_t pos, char insertedCharacter)
 }
 
 
-void d_string_insert_printf(DString* baseString, size_t pos, char* format, ...)
+/// Insert inside dynamic string using format specifier
+void d_string_insert_printf(DString * baseString, size_t pos, const char * format, ...)
 {
        va_list args;
        va_start(args, format);
@@ -286,7 +327,9 @@ void d_string_insert_printf(DString* baseString, size_t pos, char* format, ...)
        va_end(args);
 }
 
-void d_string_erase(DString* baseString, size_t pos, size_t len)
+
+/// Erase portion of dynamic string
+void d_string_erase(DString * baseString, size_t pos, size_t len)
 {
        if ((pos > baseString->currentStringLength) || (len <= 0))
                return;
@@ -300,5 +343,28 @@ void d_string_erase(DString* baseString, size_t pos, size_t len)
                memmove(baseString->str + pos, baseString->str + pos + len, baseString->currentStringLength - pos - len);
                baseString->currentStringLength -= len;
        }
+       
        baseString->str[baseString->currentStringLength] = '\0';
 }
+
+/// Copy a portion of dynamic string
+char * d_string_copy_substring(DString * d, size_t start, size_t len) {
+       char * result;
+       
+       if (len == -1) {
+               len = d->currentStringLength - start;
+       } else {
+               if (start + len > d->currentStringLength) {
+                       fprintf(stderr, "d_string: Asked to copy invalid substring range.\n");
+                       fprintf(stderr, "start: %lu  len: %lu  string: %lu\n", start, len,
+                                       d->currentStringLength);
+                       return NULL;
+               }
+       }
+       
+       result = malloc(len + 1);
+       strncpy(result, &d->str[start], len);
+       result[len] = '\0';
+       
+       return result;
+}
index 79dfb67c902b9d691d03676d97b3f9aaf831320f..6ac2fbdd1323a4b7f42662cd937d4b32914f2af3 100644 (file)
@@ -1,13 +1,15 @@
 /**
 
-       Smart String -- Library to abstract smart typing features from MMD Composer
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
 
        @file d_string.h
 
-       @brief Dynamic string -- refactoring of old GLibFacade
+       @brief Dynamic string -- refactoring of old GLibFacade.  Provides a string
+       "object" that can grow to accomodate any size content that is appended.
 
 
        @author Daniel Jalkut, modified by Fletcher T. Penney and Dan Lowe
+
        @bug    
 
 **/
 /*
 
        Copyright © 2011 Daniel Jalkut.
-       Modifications by Fletcher T. Penney, Copyright © 2011-2016 Fletcher T. Penney.
+       Modifications by Fletcher T. Penney, Copyright © 2011-2017 Fletcher T. Penney.
        Modifications by Dan Lowe, Copyright © 2011 Dan Lowe.
 
 
-       The `c-template` project is released under the MIT License.
+       The `MultiMarkdown 6` project is released under the MIT License..
        
        GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
        
@@ -59,6 +61,7 @@
 #define D_STRING_SMART_STRING_H
 
 #include <stdbool.h>
+#include <stdlib.h>
 
 /* WE implement minimal mirror implementations of GLib's GString  
  * sufficient to cover the functionality required by MultiMarkdown.
  * GLib function prototype as guide for behavior.
  */
 
+
+/// Structure for dynamic string
 typedef struct 
 {      
-       /* Current UTF8 byte stream this string represents */
-       char* str;
-
-       /* Where in the str buffer will we add new characters */
-       /* or append new strings? */
-       unsigned long currentStringBufferSize;
-       unsigned long currentStringLength;
+       char * str;                                                             //!< Pointer to UTF-8 byte stream for string
+       unsigned long currentStringBufferSize;  //!< Size of buffer currently allocated
+       unsigned long currentStringLength;              //!< Size of current string
 } DString;
 
-DString* d_string_new(const char *startingString);
 
-char* d_string_free(DString* ripString, bool freeCharacterData);
+/// Create a new dynamic string
+DString * d_string_new(
+       const char * startingString                             //!< Initial contents for string                
+);
+
+
+/// Free dynamic string
+char * d_string_free(
+       DString * ripString,                                    //!< DString to be freed
+       bool freeCharacterData                                  //!< Should the underlying str be freed as well?
+);
+
+
+/// Append null-terminated string to end of dynamic string
+void d_string_append(
+       DString * baseString,                                   //!< DString to be appended
+       const char * appendedString                             //!< String to be appended
+);
+
+
+/// Append single character to end of dynamic string
+void d_string_append_c(
+       DString * baseString,                                   //!< DString to be appended
+       char appendedCharacter                                  //!< Character to append
+);
+
+
+/// Append array of characters to end of dynamic string
+void d_string_append_c_array(
+       DString * baseString,                                   //!< DString to be appended
+       const char * appendedChars,                             //!< String to be appended
+       size_t bytes                                                    //!< Number of bytes to append
+);
+
+
+/// Append to end of dynamic string using format specifier
+void d_string_append_printf(
+       DString * baseString,                                   //!< DString to be appended
+       const char * format,                                    //!< Format specifier for appending
+       ...                                                                             //!< Arguments for format specifier
+);
+
+
+/// Prepend null-terminated string to end of dynamic string
+void d_string_prepend(
+       DString * baseString,                                   //!< DString to be appended
+       const char * prependedString                    //!< String to be prepended
+);
+
+
+/// Insert null-terminated string inside dynamic string
+void d_string_insert(
+       DString * baseString,                                   //!< DString to be appended
+       size_t pos,                                                             //!< Offset at which to insert string
+       const char * insertedString                             //!< String to be inserted
+);
+
+
+/// Insert single character inside dynamic string
+void d_string_insert_c(
+       DString * baseString,                                   //!< DString to be appended
+       size_t pos,                                                             //!< Offset at which to insert string
+       char insertedCharacter                                  //!< Character to insert
+);
 
-void d_string_append_c(DString* baseString, char appendedCharacter);
-void d_string_append_c_array(DString *baseString, const char * appendedChars, size_t bytes);
-void d_string_append(DString* baseString, char *appendedString);
 
-void d_string_prepend(DString* baseString, char* prependedString);
+/// Insert inside dynamic string using format specifier
+void d_string_insert_printf(
+       DString * baseString,                                   //!< DString to be appended
+       size_t pos,                                                             //!< Offset at which to insert string
+       const char * format,                                    //!< Format specifier for appending
+       ...                                                                             //!< Arguments for format specifier
+);
 
-void d_string_append_printf(DString* baseString, char* format, ...);
 
-void d_string_insert(DString* baseString, size_t pos, const char * insertedString);
-void d_string_insert_c(DString* baseString, size_t pos, char insertedCharacter);
-void d_string_insert_printf(DString* baseString, size_t pos, char* format, ...);
+/// Erase portion of dynamic string
+void d_string_erase(
+       DString * baseString,                                   //!< DString to be appended
+       size_t pos,                                                             //!< Offset at which to erase portion of string
+       size_t len                                                              //!< Character to append
+);
 
-void d_string_erase(DString* baseString, size_t pos, size_t len);
+/// Copy a portion of dynamic string
+char * d_string_copy_substring(
+       DString * d,                                                    //!< DString to copy
+       size_t start,                                                   //!< Start position for copy
+       size_t len                                                              //!< How many characters(bytes) to copy
+);
 
 
 #endif
diff --git a/src/html.c b/src/html.c
new file mode 100644 (file)
index 0000000..431c119
--- /dev/null
@@ -0,0 +1,1113 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file html.c
+
+       @brief Convert token tree to HTML output.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "char.h"
+#include "d_string.h"
+#include "html.h"
+#include "libMultiMarkdown.h"
+#include "parser.h"
+#include "token.h"
+#include "scanners.h"
+#include "writer.h"
+
+
+#define LC(x) x
+
+
+#define print(x) d_string_append(out, x)
+#define print_char(x) d_string_append_c(out, x)
+#define printf(...) d_string_append_printf(out, __VA_ARGS__)
+//#define print_token(t) d_string_append_c_array(out, &(source[t->start + offset]), t->len)
+#define print_token(t) d_string_append_c_array(out, &(source[t->start]), t->len)
+#define print_localized(x) mmd_print_localized_char_html(out, x, scratch)
+
+// Use Knuth's pseudo random generator to obfuscate email addresses predictably
+long ran_num_next();
+
+void mmd_print_char_html(DString * out, char c, bool obfuscate) {
+       switch (c) {
+               case '"':
+                       print("&quot;");
+                       break;
+               case '&':
+                       print("&amp;");
+                       break;
+               case '<':
+                       print("&lt;");
+                       break;
+               case '>':
+                       print("&gt;");
+                       break;
+               default:
+                       if (obfuscate && ((int) c == (((int) c) & 127))) {
+                               if (ran_num_next() % 2 == 0)
+                                       printf("&#%d;", (int) c);
+                               else
+                                       printf("&#x%x;", (unsigned int) c);
+                       } else {
+                               print_char(c);
+                       }
+                       break;
+       }
+}
+
+
+void mmd_print_string_html(DString * out, const char * str, bool obfuscate) {
+       while (*str != '\0') {
+               mmd_print_char_html(out, *str, obfuscate);
+               str++;
+       }
+}
+
+
+void mmd_print_localized_char_html(DString * out, unsigned short type, scratch_pad * scratch) {
+       // TODO: Is smart typography enabled?  Which language?
+       int language = 0;
+
+       switch (type) {
+               case DASH_N:
+                       print("&#8211;");
+                       break;
+               case DASH_M:
+                       print("&#8212;");
+                       break;
+               case ELLIPSIS:
+                       print("&#8230;");
+                       break;
+               case APOSTROPHE:
+                       print("&#8217;");
+                       break;
+               case QUOTE_LEFT_SINGLE:
+                       switch (language) {
+                               case SWEDISH:
+                                       print( "&#8217;");
+                                       break;
+                               case FRENCH:
+                                       print("&#39;");
+                                       break;
+                               case GERMAN:
+                                       print("&#8218;");
+                                       break;
+                               case GERMANGUILL:
+                                       print("&#8250;");
+                                       break;
+                               default:
+                                       print("&#8216;");
+                               }
+                       break;
+               case QUOTE_RIGHT_SINGLE:
+                       switch (language) {
+                               case GERMAN:
+                                       print("&#8216;");
+                                       break;
+                               case GERMANGUILL:
+                                       print("&#8249;");
+                                       break;
+                               default:
+                                       print("&#8217;");
+                               }
+                       break;
+               case QUOTE_LEFT_DOUBLE:
+                       switch (language) {
+                               case DUTCH:
+                               case GERMAN:
+                                       print("&#8222;");
+                                       break;
+                               case GERMANGUILL:
+                                       print("&#187;");
+                                       break;
+                               case FRENCH:
+                                       print("&#171;");
+                                       break;
+                               case SWEDISH:
+                                       print( "&#8221;");
+                                       break;
+                               default:
+                                       print("&#8220;");
+                               }
+                       break;
+               case QUOTE_RIGHT_DOUBLE:
+                       switch (language) {
+                               case GERMAN:
+                                       print("&#8220;");
+                                       break;
+                               case GERMANGUILL:
+                                       print("&#171;");
+                                       break;
+                               case FRENCH:
+                                       print("&#187;");
+                                       break;
+                               case SWEDISH:
+                               case DUTCH:
+                               default:
+                                       print("&#8221;");
+                               }
+                       break;
+       }
+}
+
+
+void mmd_export_link_html(DString * out, const char * source, token * text, link * link, size_t offset, scratch_pad * scratch) {
+       attr * a = link->attributes;
+
+       if (link->url) {
+               print("<a href=\"");
+               mmd_print_string_html(out, link->url, false);
+               print("\"");
+       } else
+               print("<a href=\"\"");
+
+       if (link->title && link->title[0] != '\0') {
+               print(" title=\"");
+               mmd_print_string_html(out, link->title, false);
+               print("\"");
+       }
+
+       while (a) {
+               print(" ");
+               print(a->key);
+               print("=\"");
+               print(a->value);
+               print("\"");
+               a = a->next;
+       }
+
+       print(">");
+
+       mmd_export_token_tree_html(out, source, text->child, offset, scratch);
+
+       print("</a>");
+}
+
+
+void mmd_export_image_html(DString * out, const char * source, token * text, link * link, size_t offset, scratch_pad * scratch) {
+       attr * a = link->attributes;
+
+       if (link->url)
+               printf("<img src=\"%s\"", link->url);
+       else
+               print("<img src=\"\"");
+
+       if (text) {
+               print(" alt=\"");
+               print_token_tree_raw(out, source, text->child);
+               print("\"");
+       }
+
+       if (0 && link->label) {
+               // \todo: Need to decide on approach to id's
+               char * label = label_from_token(source, link->label);
+               printf(" id=\"%s\"", label);
+               free(label);
+       }
+
+       if (link->title && link->title[0] != '\0')
+               printf(" title=\"%s\"", link->title);
+
+       while (a) {
+               print(" ");
+               print(a->key);
+               print("=\"");
+               print(a->value);
+               print("\"");
+               a = a->next;
+       }
+
+       print(" />");
+}
+
+
+void mmd_export_token_html(DString * out, const char * source, token * t, size_t offset, scratch_pad * scratch) {
+       if (t == NULL)
+               return;
+
+       short temp_short;
+       link * temp_link = NULL;
+       char * temp_char = NULL;
+       bool temp_bool = 0;
+       token * temp_token = NULL;
+
+       switch (t->type) {
+               case AMPERSAND:
+               case AMPERSAND_LONG:
+                       print("&amp;");
+                       break;
+               case ANGLE_LEFT:
+                       print("&lt;");
+                       break;
+               case ANGLE_RIGHT:
+                       print("&gt;");
+                       break;
+               case APOSTROPHE:
+                       if (!(scratch->extensions & EXT_SMART)) {
+                               print_token(t);
+                       } else {
+                               print_localized(APOSTROPHE);
+                       }
+                       break;
+               case BACKTICK:
+                       if (t->mate == NULL)
+                               print_token(t);
+                       else if (t->mate->type == QUOTE_RIGHT_ALT)
+                               if (!(scratch->extensions & EXT_SMART)) {
+                                       print_token(t);
+                               } else {
+                                       print_localized(QUOTE_LEFT_DOUBLE);
+                               }
+                       else if (t->start < t->mate->start) {
+                               print("<code>");
+                       } else {
+                               print("</code>");
+                       }
+                       break;
+               case BLOCK_BLOCKQUOTE:
+                       pad(out, 2, scratch);
+                       print("<blockquote>\n");
+                       scratch->padded = 2;
+                       mmd_export_token_tree_html(out, source, t->child, t->start + offset, scratch);
+                       pad(out, 1, scratch);
+                       print("</blockquote>");
+                       scratch->padded = 0;
+                       break;
+               case BLOCK_CODE_FENCED:
+               case BLOCK_CODE_INDENTED:
+                       pad(out, 2, scratch);
+                       print("<pre><code>");
+                       mmd_export_token_tree_html_raw(out, source, t->child, t->start + offset, scratch);
+                       print("</code></pre>");
+                       scratch->padded = 0;
+                       break;
+               case BLOCK_EMPTY:
+                       break;
+               case BLOCK_H1:
+               case BLOCK_H2:
+               case BLOCK_H3:
+               case BLOCK_H4:
+               case BLOCK_H5:
+               case BLOCK_H6:
+                       pad(out, 2, scratch);
+                       temp_short = t->type - BLOCK_H1 + 1;
+                       if (scratch->extensions & EXT_NO_LABELS) {
+                               printf("<h%1d>", temp_short);
+                       } else {
+                               temp_char = label_from_token(source, t);
+                               printf("<h%1d id=\"%s\">", temp_short, temp_char);
+                               free(temp_char);
+                       }
+                       mmd_export_token_tree_html(out, source, t->child, t->start + offset, scratch);
+                       printf("</h%1d>", temp_short);
+                       scratch->padded = 0;
+                       break;
+               case BLOCK_HR:
+                       pad(out, 2, scratch);
+                       print("<hr />");
+                       scratch->padded = 0;
+                       break;
+               case BLOCK_HTML:
+                       pad(out, 2, scratch);
+                       print_token_raw(out, source, t);
+                       scratch->padded = 1;
+                       break;
+               case BLOCK_LIST_BULLETED_LOOSE:
+               case BLOCK_LIST_BULLETED:
+                       temp_short = scratch->list_is_tight;
+                       switch (t->type) {
+                               case BLOCK_LIST_BULLETED_LOOSE:
+                                       scratch->list_is_tight = false;
+                                       break;
+                               case BLOCK_LIST_BULLETED:
+                                       scratch->list_is_tight = true;
+                                       break;
+                       }
+                       pad(out, 2, scratch);
+                       print("<ul>");
+                       scratch->padded = 0;
+                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       pad(out, 1, scratch);
+                       print("</ul>");
+                       scratch->padded = 0;
+                       scratch->list_is_tight = temp_short;
+                       break;
+               case BLOCK_LIST_ENUMERATED_LOOSE:
+               case BLOCK_LIST_ENUMERATED:
+                       temp_short = scratch->list_is_tight;
+                       switch (t->type) {
+                               case BLOCK_LIST_ENUMERATED_LOOSE:
+                                       scratch->list_is_tight = false;
+                                       break;
+                               case BLOCK_LIST_ENUMERATED:
+                                       scratch->list_is_tight = true;
+                                       break;
+                       }
+                       pad(out, 2, scratch);
+                       print("<ol>");
+                       scratch->padded = 0;
+                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       pad(out, 1, scratch);
+                       print("</ol>");
+                       scratch->padded = 0;
+                       scratch->list_is_tight = temp_short;
+                       break;
+               case BLOCK_LIST_ITEM:
+                       pad(out, 1, scratch);
+                       print("<li>");
+                       scratch->padded = 2;
+                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       print("</li>");
+                       scratch->padded = 0;
+                       break;
+               case BLOCK_LIST_ITEM_TIGHT:
+                       pad(out, 1, scratch);
+                       print("<li>");
+
+                       if (!scratch->list_is_tight)
+                               print("<p>");
+
+                       scratch->padded = 2;
+                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+
+                       if (!scratch->list_is_tight)
+                               print("</p>");
+
+                       print("</li>");
+                       scratch->padded = 0;
+                       break;
+               case BLOCK_PARA:
+               case BLOCK_DEF_CITATION:
+               case BLOCK_DEF_FOOTNOTE:
+                       pad(out, 2, scratch);
+       
+                       if (!scratch->list_is_tight)
+                               print("<p>");
+
+                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+
+                       if (scratch->footnote_being_printed) {
+                               scratch->footnote_para_counter--;
+
+                               if (scratch->footnote_para_counter == 0) {
+                                       printf(" <a href=\"#fnref:%d\" title=\"%s\" class=\"reversefootnote\">&#160;&#8617;</a>", scratch->footnote_being_printed, LC("return to body"));
+                               }
+                       }
+
+                       if (scratch->citation_being_printed) {
+                               scratch->footnote_para_counter--;
+
+                               if (scratch->footnote_para_counter == 0) {
+                                       printf(" <a href=\"#cnref:%d\" title=\"%s\" class=\"reversecitation\">&#160;&#8617;</a>", scratch->citation_being_printed, LC("return to body"));
+                               }
+                       }
+
+                       if (!scratch->list_is_tight)
+                               print("</p>");
+                       scratch->padded = 0;
+                       break;
+               case BRACE_DOUBLE_LEFT:
+                       print("{{");
+                       break;
+               case BRACE_DOUBLE_RIGHT:
+                       print("}}");
+                       break;
+               case BRACKET_LEFT:
+                       print("[");                     
+                       break;
+               case BRACKET_CITATION_LEFT:
+                       print("[#");
+                       break;
+               case BRACKET_FOOTNOTE_LEFT:
+                       print("[^");
+                       break;
+               case BRACKET_IMAGE_LEFT:
+                       print("![");
+                       break;
+               case BRACKET_VARIABLE_LEFT:
+                       print("[\%");
+                       break;
+               case BRACKET_RIGHT:
+                       print("]");
+                       break;
+               case COLON:
+                       print(":");
+                       break;
+               case CRITIC_ADD_OPEN:
+                       print("{++");
+                       break;
+               case CRITIC_ADD_CLOSE:
+                       print("++}");
+                       break;
+               case CRITIC_COM_OPEN:
+                       print("{&gt;&gt;");
+                       break;
+               case CRITIC_COM_CLOSE:
+                       print("&lt;&lt;}");
+                       break;
+               case CRITIC_DEL_OPEN:
+                       print("{--");
+                       break;
+               case CRITIC_DEL_CLOSE:
+                       print("--}");
+                       break;
+               case CRITIC_HI_OPEN:
+                       print("{==");
+                       break;
+               case CRITIC_HI_CLOSE:
+                       print("==}");
+                       break;
+               case CRITIC_SUB_OPEN:
+                       print("{~~");
+                       break;
+               case CRITIC_SUB_DIV:
+                       print("~&gt;");
+                       break;
+               case CRITIC_SUB_CLOSE:
+                       print("~~}");
+                       break;
+               case DASH_M:
+                       if (!(scratch->extensions & EXT_SMART)) {
+                               print_token(t);
+                       } else {
+                               print_localized(DASH_M);
+                       }
+                       break;
+               case DASH_N:
+                       if (!(scratch->extensions & EXT_SMART)) {
+                               print_token(t);
+                       } else {
+                               print_localized(DASH_N);
+                       }
+                       break;
+               case DOC_START_TOKEN:
+                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       break;
+               case ELLIPSIS:
+                       if (!(scratch->extensions & EXT_SMART)) {
+                               print_token(t);
+                       } else {
+                               print_localized(ELLIPSIS);
+                       }
+                       break;
+               case EMPH_START:
+                       print("<em>");
+                       break;
+               case EMPH_STOP:
+                       print("</em>");
+                       break;
+               case ESCAPED_CHARACTER:
+                       mmd_print_char_html(out, source[t->start + 1], false);
+                       break;
+               case HASH1:
+               case HASH2:
+               case HASH3:
+               case HASH4:
+               case HASH5:
+               case HASH6:
+                       print_token(t);
+                       break;
+               case INDENT_SPACE:
+                       print_char(' ');
+                       break;
+               case INDENT_TAB:
+                       print_char('\t');
+                       break;
+               case LINE_LIST_BULLETED:
+               case LINE_LIST_ENUMERATED:
+                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       break;
+               case MARKER_BLOCKQUOTE:
+               case MARKER_H1:
+               case MARKER_H2:
+               case MARKER_H3:
+               case MARKER_H4:
+               case MARKER_H5:
+               case MARKER_H6:
+                       break;
+               case MARKER_LIST_BULLET:
+               case MARKER_LIST_ENUMERATOR:
+                       break;
+               case MATH_BRACKET_OPEN:
+                       if (t->mate) {
+                               print("<span class=\"math\">\\[");
+                       } else
+                               print("\\[");
+                       break;
+               case MATH_BRACKET_CLOSE:
+                       if (t->mate) {
+                               print("\\]</span>");
+                       } else
+                               print("\\]");
+                       break;
+               case MATH_DOLLAR_SINGLE:
+                       if (t->mate) {
+                               (t->start < t->mate->start) ? ( print("<span class=\"math\">\\(") ) : ( print("\\)</span>") );
+                       } else {
+                               print("$");
+                       }
+                       break;
+               case MATH_DOLLAR_DOUBLE:
+                       if (t->mate) {
+                               (t->start < t->mate->start) ? ( print("<span class=\"math\">\\[") ) : ( print("\\]</span>") );
+                       } else {
+                               print("$$");
+                       }
+                       break;
+               case MATH_PAREN_OPEN:
+                       if (t->mate) {
+                               print("<span class=\"math\">\\(");
+                       } else
+                               print("\\(");
+                       break;
+               case MATH_PAREN_CLOSE:
+                       if (t->mate) {
+                               print("\\)</span>");
+                       } else
+                               print("\\)");
+                       break;
+               case NON_INDENT_SPACE:
+                       print_char(' ');
+                       break;
+               case PAIR_BACKTICK:
+                       // Strip leading whitespace
+                       switch (t->child->next->type) {
+                               case TEXT_NL:
+                               case INDENT_TAB:
+                               case INDENT_SPACE:
+                               case NON_INDENT_SPACE:
+                                       t->child->next->type = TEXT_EMPTY;
+                                       break;
+                               case TEXT_PLAIN:
+                                       while (t->child->next->len && char_is_whitespace(source[t->child->next->start])) {
+                                               t->child->next->start++;
+                                               t->child->next->len--;
+                                       }
+                                       break;
+                       }
+
+                       // Strip trailing whitespace
+                       switch (t->child->mate->prev->type) {
+                               case TEXT_NL:
+                               case INDENT_TAB:
+                               case INDENT_SPACE:
+                               case NON_INDENT_SPACE:
+                                       t->child->mate->prev->type = TEXT_EMPTY;
+                                       break;
+                               case TEXT_PLAIN:
+                                       while (t->child->mate->prev->len && char_is_whitespace(source[t->child->mate->prev->start + t->child->mate->prev->len - 1])) {
+                                               t->child->mate->prev->len--;
+                                       }
+                                       break;
+                       }
+                       t->child->type = TEXT_EMPTY;
+                       t->child->mate->type = TEXT_EMPTY;
+                       print("<code>");
+                       mmd_export_token_tree_html_raw(out, source, t->child, offset, scratch);
+                       print("</code>");
+                       break;
+               case PAIR_ANGLE:
+                       temp_token = t;
+
+                       temp_char = url_accept(source, &temp_token, true);
+
+                       if (temp_char) {
+                               if (scan_email(temp_char))
+                                       temp_bool = true;
+                               else
+                                       temp_bool = false;
+                               print("<a href=\"");
+                               mmd_print_string_html(out, temp_char, temp_bool);
+                               print("\">");
+                               mmd_print_string_html(out, temp_char, temp_bool);
+                               print("</a>");
+                       } else if (scan_html(&source[t->start])) {
+                               print_token(t);
+                       } else {
+                               mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       }
+
+                       free(temp_char);
+                       break;
+               case PAIR_BRACES:
+                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       break;
+               case PAIR_BRACKET:
+               case PAIR_BRACKET_IMAGE:
+                       parse_brackets(source, scratch, t, &temp_link, &temp_short, &temp_bool);
+
+                       if (temp_link) {
+                               if (t->type == PAIR_BRACKET) {
+                                       // Link
+                                       mmd_export_link_html(out, source, t, temp_link, offset, scratch);
+                               } else {
+                                       // Image
+                                       mmd_export_image_html(out, source, t, temp_link, offset, scratch);
+                               }
+                               
+                               if (temp_bool) {
+                                       link_free(temp_link);
+                               }
+
+                               scratch->skip_token = temp_short;
+
+                               return;
+                       }
+
+                       // No links exist, so treat as normal
+                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       break;
+               case PAIR_BRACKET_CITATION:
+                       if (scratch->extensions & EXT_NOTES) {
+                               citation_from_bracket(source, scratch, t, &temp_short);
+
+                               if (temp_short < scratch->used_citations->size) {
+                                       // Re-using previous citation
+                                       printf("<a href=\"#cn:%d\" title=\"%s\" class=\"citation\">[%d]</a>",
+                                                  temp_short, LC("see citation"), temp_short);
+                               } else {
+                                       // This is a new citation
+                                       printf("<a href=\"#cn:%d\" id=\"cnref:%d\" title=\"%s\" class=\"citation\">[%d]</a>",
+                                                  temp_short, temp_short, LC("see citation"), temp_short);
+                               }
+                       } else {
+                               // Footnotes disabled
+                               mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       }
+                       break;
+               case PAIR_BRACKET_FOOTNOTE:
+                       if (scratch->extensions & EXT_NOTES) {
+                               footnote_from_bracket(source, scratch, t, &temp_short);
+
+                               if (temp_short < scratch->used_footnotes->size) {
+                                       // Re-using previous footnote
+                                       printf("<a href=\"#fn:%d\" title=\"%s\" class=\"footnote\">[%d]</a>",
+                                                  temp_short, LC("see footnote"), temp_short);
+                               } else {
+                                       // This is a new footnote
+                                       printf("<a href=\"#fn:%d\" id=\"fnref:%d\" title=\"%s\" class=\"footnote\">[%d]</a>",
+                                                  temp_short, temp_short, LC("see footnote"), temp_short);
+                               }
+                       } else {
+                               // Footnotes disabled
+                               mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       }
+                       break;
+               case PAIR_CRITIC_ADD:
+                       // Ignore if we're rejecting
+                       if (scratch->extensions & EXT_CRITIC_REJECT)
+                               break;
+                       if (scratch->extensions & EXT_CRITIC) {
+                               t->child->type = TEXT_EMPTY;
+                               t->child->mate->type = TEXT_EMPTY;
+                               if (scratch->extensions & EXT_CRITIC_ACCEPT) {
+                                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                               } else {
+                                       print("<ins>");
+                                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                                       print("</ins>");
+                               }
+                       } else {
+                               mmd_export_token_tree_html(out, source, t->child, offset, scratch);                             
+                       }
+                       break;
+               case PAIR_CRITIC_DEL:
+                       // Ignore if we're accepting
+                       if (scratch->extensions & EXT_CRITIC_ACCEPT)
+                               break;
+                       if (scratch->extensions & EXT_CRITIC) {
+                               t->child->type = TEXT_EMPTY;
+                               t->child->mate->type = TEXT_EMPTY;
+                               if (scratch->extensions & EXT_CRITIC_REJECT) {
+                                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                               } else {
+                                       print("<del>");
+                                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                                       print("</del>");
+                               }
+                       } else {
+                               mmd_export_token_tree_html(out, source, t->child, offset, scratch);                             
+                       }
+                       break;
+               case PAIR_CRITIC_COM:
+                       // Ignore if we're rejecting or accepting
+                       if ((scratch->extensions & EXT_CRITIC_REJECT) ||
+                               (scratch->extensions & EXT_CRITIC_ACCEPT))
+                               break;
+                       if (scratch->extensions & EXT_CRITIC) {
+                               t->child->type = TEXT_EMPTY;
+                               t->child->mate->type = TEXT_EMPTY;
+                               print("<span class=\"critic comment\">");
+                               mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                               print("</span>");
+                       } else {
+                               mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       }
+                       break;
+               case PAIR_CRITIC_HI:
+                       // Ignore if we're rejecting or accepting
+                       if ((scratch->extensions & EXT_CRITIC_REJECT) ||
+                               (scratch->extensions & EXT_CRITIC_ACCEPT))
+                               break;
+                       if (scratch->extensions & EXT_CRITIC) {
+                               t->child->type = TEXT_EMPTY;
+                               t->child->mate->type = TEXT_EMPTY;
+                               print("<mark>");
+                               mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                               print("</mark>");
+                       } else {
+                               mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       }
+                       break;
+               case CRITIC_SUB_DIV_A:
+                       print("~");
+                       break;
+               case CRITIC_SUB_DIV_B:
+                       print("&gt;");
+                       break;
+               case PAIR_CRITIC_SUB_DEL:
+                       if ((scratch->extensions & EXT_CRITIC) &&
+                               (t->next->type == PAIR_CRITIC_SUB_ADD)) {
+                               t->child->type = TEXT_EMPTY;
+                               t->child->mate->type = TEXT_EMPTY;
+                               if (scratch->extensions & EXT_CRITIC_ACCEPT) {
+
+                               } else if (scratch->extensions & EXT_CRITIC_REJECT) {
+                                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                               } else {
+                                       print("<del>");
+                                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                                       print("</del>");
+                               }
+                       } else {
+                               mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       }
+                       break;
+               case PAIR_CRITIC_SUB_ADD:
+                       if ((scratch->extensions & EXT_CRITIC) &&
+                               (t->prev->type == PAIR_CRITIC_SUB_DEL)) {
+                               t->child->type = TEXT_EMPTY;
+                               t->child->mate->type = TEXT_EMPTY;
+                               if (scratch->extensions & EXT_CRITIC_REJECT) {
+
+                               } else if (scratch->extensions & EXT_CRITIC_ACCEPT) {
+                                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                               } else {
+                                       print("<ins>");
+                                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                                       print("</ins>");
+                               }
+                       } else {
+                               mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       }
+                       break;
+               case PAIR_MATH:
+               case PAIR_PAREN:
+               case PAIR_QUOTE_DOUBLE:
+               case PAIR_QUOTE_SINGLE:
+               case PAIR_STAR:
+               case PAIR_UL:
+                       mmd_export_token_tree_html(out, source, t->child, offset, scratch);
+                       break;
+               case PAREN_LEFT:
+                       print("(");
+                       break;
+               case PAREN_RIGHT:
+                       print(")");
+                       break;
+               case PIPE:
+                       print_token(t);
+                       break;
+               case PLUS:
+                       print_token(t);
+                       break;
+               case QUOTE_SINGLE:
+                       if ((t->mate == NULL) || (!(scratch->extensions & EXT_SMART)))
+                               print("'");
+                       else
+                               (t->start < t->mate->start) ? ( print_localized(QUOTE_LEFT_SINGLE) ) : ( print_localized(QUOTE_RIGHT_SINGLE) );
+                       break;
+               case QUOTE_DOUBLE:
+                       if ((t->mate == NULL) || (!(scratch->extensions & EXT_SMART)))
+                               print("&quot;");
+                       else
+                               (t->start < t->mate->start) ? ( print_localized(QUOTE_LEFT_DOUBLE) ) : ( print_localized(QUOTE_RIGHT_DOUBLE) );
+                       break;
+               case QUOTE_RIGHT_ALT:
+                       if ((t->mate == NULL) || (!(scratch->extensions & EXT_SMART)))
+                               print("''");
+                       else
+                               print_localized(QUOTE_RIGHT_DOUBLE);
+                       break;
+               case STAR:
+                       print_token(t);
+                       break;
+               case STRONG_START:
+                       print("<strong>");
+                       break;
+               case STRONG_STOP:
+                       print("</strong>");
+                       break;
+               case SUBSCRIPT:
+                       if (t->mate) {
+                               (t->start < t->mate->start) ? (print("<sub>")) : (print("</sub>"));
+                       } else if (t->len != 1) {
+                               print("<sub>");
+                               mmd_export_token_html(out, source, t->child, offset, scratch);
+                               print("</sub>");
+                       } else {
+                               print("~");
+                       }
+                       break;
+               case SUPERSCRIPT:
+                       if (t->mate) {
+                               (t->start < t->mate->start) ? (print("<sup>")) : (print("</sup>"));
+                       } else if (t->len != 1) {
+                               print("<sup>");
+                               mmd_export_token_html(out, source, t->child, offset, scratch);
+                               print("</sup>");
+                       } else {
+                               print("^");
+                       }       
+                       break;
+               case TEXT_LINEBREAK:
+                       if (t->next) {
+                               print("<br />\n");
+                               scratch->padded = 1;
+                       }
+                       break;
+               case CODE_FENCE:
+               case TEXT_EMPTY:
+                       break;
+               case TEXT_NL:
+                       if (t->next)
+                               print_char('\n');
+                       break;
+               case TEXT_NUMBER_POSS_LIST:
+               case TEXT_PERIOD:
+               case TEXT_PLAIN:
+                       print_token(t);
+                       break;
+               case UL:
+                       print_token(t);
+                       break;
+               default:
+                       fprintf(stderr, "Unknown token type: %d\n", t->type);
+                       break;
+       }
+}
+
+
+void mmd_export_token_tree_html(DString * out, const char * source, token * t, size_t offset, scratch_pad * scratch) {
+       while (t != NULL) {
+               if (scratch->skip_token) {
+                       scratch->skip_token--;
+               } else {
+                       mmd_export_token_html(out, source, t, offset, scratch);
+               }
+
+               t = t->next;
+       }
+}
+
+
+void mmd_export_token_html_raw(DString * out, const char * source, token * t, size_t offset, scratch_pad * scratch) {
+       if (t == NULL)
+               return;
+
+       switch (t->type) {
+               case BACKTICK:
+                       print_token(t);
+                       break;
+               case AMPERSAND:
+                       print("&amp;");
+                       break;
+               case AMPERSAND_LONG:
+                       print("&amp;amp;");
+                       break;
+               case ANGLE_RIGHT:
+                       print("&gt;");
+                       break;
+               case ANGLE_LEFT:
+                       print("&lt;");
+                       break;
+               case ESCAPED_CHARACTER:
+                       print("\\");
+                       mmd_print_char_html(out, source[t->start + 1], false);
+                       break;
+               case QUOTE_DOUBLE:
+                       print("&quot;");
+                       break;
+               case CODE_FENCE:
+                       t->next->type = TEXT_EMPTY;
+               case TEXT_EMPTY:
+                       break;
+               default:
+                       if (t->child)
+                               mmd_export_token_tree_html_raw(out, source, t->child, offset, scratch);
+                       else
+                               print_token(t);
+                       break;
+       }
+}
+
+
+void mmd_export_token_tree_html_raw(DString * out, const char * source, token * t, size_t offset, scratch_pad * scratch) {
+       while (t != NULL) {
+               if (scratch->skip_token) {
+                       scratch->skip_token--;
+               } else {
+                       mmd_export_token_html_raw(out, source, t, offset, scratch);
+               }
+
+               t = t->next;
+       }
+}
+
+
+void mmd_export_footnote_list_html(DString * out, const char * source, scratch_pad * scratch) {
+       if (scratch->used_footnotes->size > 0) {
+               footnote * note;
+               token * content;
+
+               pad(out, 2, scratch);
+               print("<div class=\"footnotes\">\n<hr />\n<ol>");
+               scratch->padded = 0;
+
+               for (int i = 0; i < scratch->used_footnotes->size; ++i)
+               {
+                       // Export footnote
+                       pad(out, 2, scratch);
+
+                       printf("<li id=\"fn:%d\">\n", i + 1);
+                       scratch->padded = 6;
+
+                       note = stack_peek_index(scratch->used_footnotes, i);
+                       content = note->content;
+
+                       scratch->footnote_para_counter = 0;
+
+                       // We need to know which block is the last one in the footnote
+                       while(content) {
+                               if (content->type == BLOCK_PARA)
+                                       scratch->footnote_para_counter++;
+                               
+                               content = content->next;
+                       }
+
+                       content = note->content;
+                       scratch->footnote_being_printed = i + 1;
+
+                       mmd_export_token_tree_html(out, source, content, 0, scratch);
+
+                       pad(out, 1, scratch);
+                       printf("</li>");
+                       scratch->padded = 0;
+               }
+
+               pad(out, 2, scratch);
+               print("</ol>\n</div>");
+               scratch->padded = 0;
+       }
+}
+
+
+void mmd_export_citation_list_html(DString * out, const char * source, scratch_pad * scratch) {
+       if (scratch->used_citations->size > 0) {
+               footnote * note;
+               token * content;
+
+               pad(out, 2, scratch);
+               print("<div class=\"citations\">\n<hr />\n<ol>");
+               scratch->padded = 0;
+
+               for (int i = 0; i < scratch->used_citations->size; ++i)
+               {
+                       // Export footnote
+                       pad(out, 2, scratch);
+
+                       printf("<li id=\"cn:%d\">\n", i + 1);
+                       scratch->padded = 6;
+
+                       note = stack_peek_index(scratch->used_citations, i);
+                       content = note->content;
+
+                       scratch->footnote_para_counter = 0;
+
+                       // We need to know which block is the last one in the footnote
+                       while(content) {
+                               if (content->type == BLOCK_PARA)
+                                       scratch->footnote_para_counter++;
+                               
+                               content = content->next;
+                       }
+
+                       content = note->content;
+                       scratch->citation_being_printed = i + 1;
+
+                       mmd_export_token_tree_html(out, source, content, 0, scratch);
+
+                       pad(out, 1, scratch);
+                       printf("</li>");
+                       scratch->padded = 0;
+               }
+
+               pad(out, 2, scratch);
+               print("</ol>\n</div>");
+               scratch->padded = 0;
+       }
+}
+
+
+
diff --git a/src/html.h b/src/html.h
new file mode 100644 (file)
index 0000000..7caf98e
--- /dev/null
@@ -0,0 +1,74 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file html.h
+
+       @brief Convert token tree to HTML output.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+
+#ifndef HTML_MULTIMARKDOWN_H
+#define HTML_MULTIMARKDOWN_H
+
+#include "d_string.h"
+#include "token.h"
+#include "writer.h"
+
+void mmd_export_token_html(DString * out, const char * source, token * t, size_t offset, scratch_pad * scratch);
+void mmd_export_token_tree_html(DString * out, const char * source, token * t, size_t offset, scratch_pad * scratch);
+
+
+void mmd_export_token_html_raw(DString * out, const char * source, token * t, size_t offset, scratch_pad * scratch);
+void mmd_export_token_tree_html_raw(DString * out, const char * source, token * t, size_t offset, scratch_pad * scratch);
+
+void mmd_export_citation_list_html(DString * out, const char * source, scratch_pad * scratch);
+void mmd_export_footnote_list_html(DString * out, const char * source, scratch_pad * scratch);
+
+
+#endif
diff --git a/src/lexer.c b/src/lexer.c
new file mode 100644 (file)
index 0000000..2ab5080
--- /dev/null
@@ -0,0 +1,988 @@
+/* Generated by re2c 0.14.3 on Wed Jan 18 22:23:18 2017 */
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file lexer.re
+
+       @brief Description of the regular expressions used to define tokens, 
+       used by re2c to create a lexer/tokenizer.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+#include "lexer.h"
+#include "libMultiMarkdown.h"
+#include "parser.h"
+
+
+// Basic scanner struct
+
+#define YYCTYPE                char
+#define YYCURSOR       s->cur
+#define YYMARKER       s->ptr
+#define YYCTXMARKER    s->ctx
+
+
+int scan(Scanner * s, const char * stop) {
+
+       scan:
+
+       if (s->cur >= stop) {
+               return 0;
+       }
+
+       s->start = s->cur;
+
+       
+{
+       YYCTYPE yych;
+       unsigned int yyaccept = 0;
+
+       yych = *YYCURSOR;
+       switch (yych) {
+       case '\t':      goto yy39;
+       case '\n':      goto yy44;
+       case '\r':      goto yy46;
+       case ' ':       goto yy41;
+       case '!':       goto yy17;
+       case '"':       goto yy25;
+       case '#':       goto yy42;
+       case '$':       goto yy35;
+       case '&':       goto yy32;
+       case '\'':      goto yy27;
+       case '(':       goto yy18;
+       case ')':       goto yy20;
+       case '*':       goto yy47;
+       case '+':       goto yy4;
+       case '-':       goto yy6;
+       case '.':       goto yy29;
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy43;
+       case ':':       goto yy30;
+       case '<':       goto yy8;
+       case '=':       goto yy12;
+       case '>':       goto yy22;
+       case '[':       goto yy13;
+       case '\\':      goto yy34;
+       case ']':       goto yy15;
+       case '^':       goto yy37;
+       case '_':       goto yy49;
+       case '`':       goto yy51;
+       case '{':       goto yy2;
+       case '|':       goto yy53;
+       case '}':       goto yy24;
+       case '~':       goto yy10;
+       default:        goto yy55;
+       }
+yy2:
+       yyaccept = 0;
+       yych = *(YYMARKER = ++YYCURSOR);
+       switch (yych) {
+       case '+':       goto yy248;
+       case '-':       goto yy247;
+       case '=':       goto yy244;
+       case '>':       goto yy246;
+       case '{':       goto yy242;
+       case '~':       goto yy245;
+       default:        goto yy3;
+       }
+yy3:
+       { goto scan; }
+yy4:
+       yyaccept = 1;
+       yych = *(YYMARKER = ++YYCURSOR);
+       switch (yych) {
+       case '+':       goto yy239;
+       default:        goto yy5;
+       }
+yy5:
+       { return PLUS; }
+yy6:
+       ++YYCURSOR;
+       switch ((yych = *YYCURSOR)) {
+       case '-':       goto yy233;
+       default:        goto yy7;
+       }
+yy7:
+       { return DASH_N; }
+yy8:
+       yyaccept = 2;
+       yych = *(YYMARKER = ++YYCURSOR);
+       switch (yych) {
+       case '<':       goto yy230;
+       default:        goto yy9;
+       }
+yy9:
+       { return ANGLE_LEFT; }
+yy10:
+       yyaccept = 3;
+       yych = *(YYMARKER = ++YYCURSOR);
+       switch (yych) {
+       case '>':       goto yy226;
+       case '~':       goto yy225;
+       default:        goto yy11;
+       }
+yy11:
+       { return SUBSCRIPT; }
+yy12:
+       yyaccept = 0;
+       yych = *(YYMARKER = ++YYCURSOR);
+       switch (yych) {
+       case '=':       goto yy222;
+       default:        goto yy3;
+       }
+yy13:
+       ++YYCURSOR;
+       switch ((yych = *YYCURSOR)) {
+       case '#':       goto yy218;
+       case '%':       goto yy216;
+       case '^':       goto yy220;
+       default:        goto yy14;
+       }
+yy14:
+       { return BRACKET_LEFT; }
+yy15:
+       ++YYCURSOR;
+       { return BRACKET_RIGHT; }
+yy17:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '[':       goto yy214;
+       default:        goto yy3;
+       }
+yy18:
+       ++YYCURSOR;
+       { return PAREN_LEFT; }
+yy20:
+       ++YYCURSOR;
+       { return PAREN_RIGHT; }
+yy22:
+       ++YYCURSOR;
+       { return ANGLE_RIGHT; }
+yy24:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '}':       goto yy212;
+       default:        goto yy3;
+       }
+yy25:
+       ++YYCURSOR;
+       { return QUOTE_DOUBLE; }
+yy27:
+       ++YYCURSOR;
+       switch ((yych = *YYCURSOR)) {
+       case '\'':      goto yy210;
+       default:        goto yy28;
+       }
+yy28:
+       { return QUOTE_SINGLE; }
+yy29:
+       YYCTXMARKER = YYCURSOR + 1;
+       yyaccept = 0;
+       yych = *(YYMARKER = ++YYCURSOR);
+       switch (yych) {
+       case '\t':      goto yy200;
+       case '\n':      goto yy197;
+       case '\r':      goto yy199;
+       case ' ':       goto yy202;
+       case '.':       goto yy203;
+       default:        goto yy3;
+       }
+yy30:
+       ++YYCURSOR;
+       { return COLON; }
+yy32:
+       yyaccept = 4;
+       yych = *(YYMARKER = ++YYCURSOR);
+       switch (yych) {
+       case 'A':
+       case 'a':       goto yy192;
+       default:        goto yy33;
+       }
+yy33:
+       { return AMPERSAND; }
+yy34:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '!':       goto yy180;
+       case '"':       goto yy170;
+       case '#':       goto yy150;
+       case '$':       goto yy148;
+       case '%':       goto yy146;
+       case '&':       goto yy134;
+       case '\'':      goto yy168;
+       case '(':       goto yy162;
+       case ')':       goto yy160;
+       case '*':       goto yy126;
+       case '+':       goto yy144;
+       case ',':       goto yy176;
+       case '-':       goto yy142;
+       case '.':       goto yy182;
+       case '/':       goto yy130;
+       case ':':       goto yy172;
+       case ';':       goto yy174;
+       case '<':       goto yy138;
+       case '=':       goto yy140;
+       case '>':       goto yy136;
+       case '?':       goto yy178;
+       case '@':       goto yy132;
+       case '[':       goto yy154;
+       case '\\':      goto yy120;
+       case ']':       goto yy152;
+       case '^':       goto yy128;
+       case '_':       goto yy124;
+       case '`':       goto yy166;
+       case '{':       goto yy158;
+       case '|':       goto yy122;
+       case '}':       goto yy156;
+       case '~':       goto yy164;
+       default:        goto yy3;
+       }
+yy35:
+       ++YYCURSOR;
+       switch ((yych = *YYCURSOR)) {
+       case '$':       goto yy118;
+       default:        goto yy36;
+       }
+yy36:
+       { return MATH_DOLLAR_SINGLE; }
+yy37:
+       ++YYCURSOR;
+       { return SUPERSCRIPT; }
+yy39:
+       ++YYCURSOR;
+       { return INDENT_TAB; }
+yy41:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case ' ':       goto yy110;
+       default:        goto yy3;
+       }
+yy42:
+       YYCTXMARKER = YYCURSOR + 1;
+       yyaccept = 0;
+       yych = *(YYMARKER = ++YYCURSOR);
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':       goto yy71;
+       case '#':       goto yy69;
+       default:        goto yy3;
+       }
+yy43:
+       YYCTXMARKER = YYCURSOR + 1;
+       yyaccept = 0;
+       yych = *(YYMARKER = ++YYCURSOR);
+       switch (yych) {
+       case '.':       goto yy60;
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy62;
+       default:        goto yy3;
+       }
+yy44:
+       ++YYCURSOR;
+yy45:
+       { return TEXT_NL; }
+yy46:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\n':      goto yy44;
+       default:        goto yy45;
+       }
+yy47:
+       ++YYCURSOR;
+       { return STAR; }
+yy49:
+       ++YYCURSOR;
+       { return UL; }
+yy51:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+       goto yy59;
+yy52:
+       { return BACKTICK; }
+yy53:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+       goto yy57;
+yy54:
+       { return PIPE; }
+yy55:
+       yych = *++YYCURSOR;
+       goto yy3;
+yy56:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+yy57:
+       switch (yych) {
+       case '|':       goto yy56;
+       default:        goto yy54;
+       }
+yy58:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+yy59:
+       switch (yych) {
+       case '`':       goto yy58;
+       default:        goto yy52;
+       }
+yy60:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy67;
+       case '\n':      goto yy64;
+       case '\r':      goto yy66;
+       default:        goto yy61;
+       }
+yy61:
+       YYCURSOR = YYMARKER;
+       switch (yyaccept) {
+       case 0:         goto yy3;
+       case 1:         goto yy5;
+       case 2:         goto yy9;
+       case 3:         goto yy11;
+       case 4:         goto yy33;
+       default:        goto yy198;
+       }
+yy62:
+       YYCTXMARKER = YYCURSOR + 1;
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+       switch (yych) {
+       case '.':       goto yy60;
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy62;
+       default:        goto yy61;
+       }
+yy64:
+       ++YYCURSOR;
+yy65:
+       YYCURSOR = YYCTXMARKER;
+       { return TEXT_NUMBER_POSS_LIST; }
+yy66:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\n':      goto yy64;
+       default:        goto yy65;
+       }
+yy67:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy67;
+       default:        goto yy65;
+       }
+yy69:
+       YYCTXMARKER = YYCURSOR + 1;
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':       goto yy77;
+       case '#':       goto yy82;
+       default:        goto yy61;
+       }
+yy70:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+yy71:
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy70;
+       case '\n':      goto yy73;
+       case '\r':      goto yy75;
+       default:        goto yy72;
+       }
+yy72:
+       { return HASH1; }
+yy73:
+       ++YYCURSOR;
+yy74:
+       YYCURSOR = YYCTXMARKER;
+       { return HASH1; }
+yy75:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\n':      goto yy73;
+       default:        goto yy74;
+       }
+yy76:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+yy77:
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy76;
+       case '\n':      goto yy79;
+       case '\r':      goto yy81;
+       default:        goto yy78;
+       }
+yy78:
+       { return HASH2; }
+yy79:
+       ++YYCURSOR;
+yy80:
+       YYCURSOR = YYCTXMARKER;
+       { return HASH2; }
+yy81:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\n':      goto yy79;
+       default:        goto yy80;
+       }
+yy82:
+       YYCTXMARKER = YYCURSOR + 1;
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':       goto yy85;
+       case '#':       goto yy83;
+       default:        goto yy61;
+       }
+yy83:
+       YYCTXMARKER = YYCURSOR + 1;
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':       goto yy91;
+       case '#':       goto yy96;
+       default:        goto yy61;
+       }
+yy84:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+yy85:
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy84;
+       case '\n':      goto yy87;
+       case '\r':      goto yy89;
+       default:        goto yy86;
+       }
+yy86:
+       { return HASH3; }
+yy87:
+       ++YYCURSOR;
+yy88:
+       YYCURSOR = YYCTXMARKER;
+       { return HASH3; }
+yy89:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\n':      goto yy87;
+       default:        goto yy88;
+       }
+yy90:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+yy91:
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy90;
+       case '\n':      goto yy93;
+       case '\r':      goto yy95;
+       default:        goto yy92;
+       }
+yy92:
+       { return HASH4; }
+yy93:
+       ++YYCURSOR;
+yy94:
+       YYCURSOR = YYCTXMARKER;
+       { return HASH4; }
+yy95:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\n':      goto yy93;
+       default:        goto yy94;
+       }
+yy96:
+       YYCTXMARKER = YYCURSOR + 1;
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':       goto yy99;
+       case '#':       goto yy97;
+       default:        goto yy61;
+       }
+yy97:
+       YYCTXMARKER = YYCURSOR + 1;
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':       goto yy105;
+       default:        goto yy61;
+       }
+yy98:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+yy99:
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy98;
+       case '\n':      goto yy101;
+       case '\r':      goto yy103;
+       default:        goto yy100;
+       }
+yy100:
+       { return HASH5; }
+yy101:
+       ++YYCURSOR;
+yy102:
+       YYCURSOR = YYCTXMARKER;
+       { return HASH5; }
+yy103:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\n':      goto yy101;
+       default:        goto yy102;
+       }
+yy104:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+yy105:
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy104;
+       case '\n':      goto yy107;
+       case '\r':      goto yy109;
+       default:        goto yy106;
+       }
+yy106:
+       { return HASH6; }
+yy107:
+       ++YYCURSOR;
+yy108:
+       YYCURSOR = YYCTXMARKER;
+       { return HASH6; }
+yy109:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\n':      goto yy107;
+       default:        goto yy108;
+       }
+yy110:
+       ++YYCURSOR;
+       switch ((yych = *YYCURSOR)) {
+       case '\n':      goto yy113;
+       case '\r':      goto yy115;
+       case ' ':       goto yy112;
+       default:        goto yy111;
+       }
+yy111:
+       { return NON_INDENT_SPACE; }
+yy112:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case ' ':       goto yy116;
+       default:        goto yy111;
+       }
+yy113:
+       ++YYCURSOR;
+yy114:
+       { return TEXT_LINEBREAK; }
+yy115:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\n':      goto yy113;
+       default:        goto yy114;
+       }
+yy116:
+       ++YYCURSOR;
+       { return INDENT_SPACE; }
+yy118:
+       ++YYCURSOR;
+       { return MATH_DOLLAR_DOUBLE; }
+yy120:
+       ++YYCURSOR;
+       switch ((yych = *YYCURSOR)) {
+       case '(':       goto yy184;
+       case ')':       goto yy186;
+       case '[':       goto yy188;
+       case ']':       goto yy190;
+       default:        goto yy121;
+       }
+yy121:
+       { return ESCAPED_CHARACTER; }
+yy122:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy124:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy126:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy128:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy130:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy132:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy134:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy136:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy138:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy140:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy142:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy144:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy146:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy148:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy150:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy152:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy154:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy156:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy158:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy160:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy162:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy164:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy166:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy168:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy170:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy172:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy174:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy176:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy178:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy180:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy182:
+       ++YYCURSOR;
+       { return ESCAPED_CHARACTER; }
+yy184:
+       ++YYCURSOR;
+       { return MATH_PAREN_OPEN; }
+yy186:
+       ++YYCURSOR;
+       { return MATH_PAREN_CLOSE; }
+yy188:
+       ++YYCURSOR;
+       { return MATH_BRACKET_OPEN; }
+yy190:
+       ++YYCURSOR;
+       { return MATH_BRACKET_CLOSE; }
+yy192:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case 'M':
+       case 'm':       goto yy193;
+       default:        goto yy61;
+       }
+yy193:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case 'P':
+       case 'p':       goto yy194;
+       default:        goto yy61;
+       }
+yy194:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case ';':       goto yy195;
+       default:        goto yy61;
+       }
+yy195:
+       ++YYCURSOR;
+       { return AMPERSAND_LONG; }
+yy197:
+       ++YYCURSOR;
+yy198:
+       YYCURSOR = YYCTXMARKER;
+       { return TEXT_PERIOD; }
+yy199:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '\n':      goto yy197;
+       default:        goto yy198;
+       }
+yy200:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+yy201:
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy200;
+       default:        goto yy198;
+       }
+yy202:
+       yyaccept = 5;
+       yych = *(YYMARKER = ++YYCURSOR);
+       switch (yych) {
+       case '.':       goto yy206;
+       default:        goto yy201;
+       }
+yy203:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '.':       goto yy204;
+       default:        goto yy61;
+       }
+yy204:
+       ++YYCURSOR;
+       { return ELLIPSIS; }
+yy206:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case ' ':       goto yy207;
+       default:        goto yy61;
+       }
+yy207:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '.':       goto yy208;
+       default:        goto yy61;
+       }
+yy208:
+       ++YYCURSOR;
+       { return ELLIPSIS; }
+yy210:
+       ++YYCURSOR;
+       { return QUOTE_RIGHT_ALT; }
+yy212:
+       ++YYCURSOR;
+       { return BRACE_DOUBLE_RIGHT; }
+yy214:
+       ++YYCURSOR;
+       { return BRACKET_IMAGE_LEFT; }
+yy216:
+       ++YYCURSOR;
+       { return BRACKET_VARIABLE_LEFT; }
+yy218:
+       ++YYCURSOR;
+       { return BRACKET_CITATION_LEFT; }
+yy220:
+       ++YYCURSOR;
+       { return BRACKET_FOOTNOTE_LEFT; }
+yy222:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '}':       goto yy223;
+       default:        goto yy61;
+       }
+yy223:
+       ++YYCURSOR;
+       { return CRITIC_HI_CLOSE; }
+yy225:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '}':       goto yy228;
+       default:        goto yy61;
+       }
+yy226:
+       ++YYCURSOR;
+       { return CRITIC_SUB_DIV; }
+yy228:
+       ++YYCURSOR;
+       { return CRITIC_SUB_CLOSE; }
+yy230:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '}':       goto yy231;
+       default:        goto yy61;
+       }
+yy231:
+       ++YYCURSOR;
+       { return CRITIC_COM_CLOSE; }
+yy233:
+       ++YYCURSOR;
+       switch ((yych = *YYCURSOR)) {
+       case '-':       goto yy237;
+       case '}':       goto yy235;
+       default:        goto yy234;
+       }
+yy234:
+       { return DASH_N; }
+yy235:
+       ++YYCURSOR;
+       { return CRITIC_DEL_CLOSE; }
+yy237:
+       ++YYCURSOR;
+       { return DASH_M; }
+yy239:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '}':       goto yy240;
+       default:        goto yy61;
+       }
+yy240:
+       ++YYCURSOR;
+       { return CRITIC_ADD_CLOSE; }
+yy242:
+       ++YYCURSOR;
+       { return BRACE_DOUBLE_LEFT; }
+yy244:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '=':       goto yy257;
+       default:        goto yy61;
+       }
+yy245:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '~':       goto yy255;
+       default:        goto yy61;
+       }
+yy246:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '>':       goto yy253;
+       default:        goto yy61;
+       }
+yy247:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '-':       goto yy251;
+       default:        goto yy61;
+       }
+yy248:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case '+':       goto yy249;
+       default:        goto yy61;
+       }
+yy249:
+       ++YYCURSOR;
+       { return CRITIC_ADD_OPEN; }
+yy251:
+       ++YYCURSOR;
+       { return CRITIC_DEL_OPEN; }
+yy253:
+       ++YYCURSOR;
+       { return CRITIC_COM_OPEN; }
+yy255:
+       ++YYCURSOR;
+       { return CRITIC_SUB_OPEN; }
+yy257:
+       ++YYCURSOR;
+       { return CRITIC_HI_OPEN; }
+}
+
+}
diff --git a/src/lexer.h b/src/lexer.h
new file mode 100644 (file)
index 0000000..053692b
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file lexer.h
+
+       @brief Description of the regular expressions used to define tokens, 
+       used by re2c to create a lexer/tokenizer.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+/// Re2c scanner data -- this structure is used by the re2c
+/// lexer to track progress and offsets within the source
+/// string.  They can be used to create "tokens" that match
+/// sections of the text with an abstract syntax tree.
+struct Scanner {
+       const char *    start;          //!< Start of current token
+       const char *    cur;            //!< Character currently being matched
+       const char *    ptr;            //!< Used for backtracking by re2c
+       const char *    ctx;
+};
+
+typedef struct Scanner Scanner;
+
+
+/// Scan for the next token
+int scan(
+       Scanner * s,                    //!< Pointer to Scanner state structure
+       const char * stop               //!< Pointer to position in string at which to stop parsing
+);
+
diff --git a/src/lexer.re b/src/lexer.re
new file mode 100644 (file)
index 0000000..2d7b6d8
--- /dev/null
@@ -0,0 +1,227 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file lexer.re
+
+       @brief Description of the regular expressions used to define tokens, 
+       used by re2c to create a lexer/tokenizer.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+#include "lexer.h"
+#include "libMultiMarkdown.h"
+#include "parser.h"
+
+
+// Basic scanner struct
+
+#define YYCTYPE                char
+#define YYCURSOR       s->cur
+#define YYMARKER       s->ptr
+#define YYCTXMARKER    s->ctx
+
+
+int scan(Scanner * s, const char * stop) {
+
+       scan:
+
+       if (s->cur >= stop) {
+               return 0;
+       }
+
+       s->start = s->cur;
+
+       /*!re2c
+               re2c:yyfill:enable = 0;
+
+               NL                                                              = "\r\n" | '\n' | '\r';
+               SP                                                              = [ \t]+;
+
+               SPNL                                                    = [ \t]* NL;
+
+               INDENT_TAB                                              = '\t';
+               INDENT_SPACE                                    = ' '{4};
+               NON_INDENT_SPACE                                = ' '{2,3};
+
+               TEXT_LINEBREAK                                  = "  " NL;
+
+               // The order of these seems to matter
+
+               "{++"                                                   { return CRITIC_ADD_OPEN; }
+               "++}"                                                   { return CRITIC_ADD_CLOSE; }
+
+               "{--"                                                   { return CRITIC_DEL_OPEN; }
+               "--}"                                                   { return CRITIC_DEL_CLOSE; }
+
+               "{>>"                                                   { return CRITIC_COM_OPEN; }
+               "<<}"                                                   { return CRITIC_COM_CLOSE; }
+
+               "{~~"                                                   { return CRITIC_SUB_OPEN; }
+               "~>"                                                    { return CRITIC_SUB_DIV; }
+               "~~}"                                                   { return CRITIC_SUB_CLOSE; }
+
+               "{=="                                                   { return CRITIC_HI_OPEN; }
+               "==}"                                                   { return CRITIC_HI_CLOSE; }
+
+               "["                                                             { return BRACKET_LEFT; }
+               "]"                                                             { return BRACKET_RIGHT; }
+
+               "!["                                                    { return BRACKET_IMAGE_LEFT; }
+               "[^"                                                    { return BRACKET_FOOTNOTE_LEFT; }
+               "[#"                                                    { return BRACKET_CITATION_LEFT; }
+               "[%"                                                    { return BRACKET_VARIABLE_LEFT; }
+
+               "("                                                             { return PAREN_LEFT; }
+               ")"                                                             { return PAREN_RIGHT; }
+
+               "<"                                                             { return ANGLE_LEFT; }
+               ">"                                                             { return ANGLE_RIGHT; }
+
+               "{{"                                                    { return BRACE_DOUBLE_LEFT; }
+               "}}"                                                    { return BRACE_DOUBLE_RIGHT; }
+
+               "\""                                                    { return QUOTE_DOUBLE; }
+               "'"                                                             { return QUOTE_SINGLE; }
+               // "``"                                                 { return QUOTE_LEFT_ALT; }
+               "''"                                                    { return QUOTE_RIGHT_ALT; }
+               "-"                                                             { return DASH_N; }
+               "--"                                                    { return DASH_N; }
+               "---"                                                   { return DASH_M; }
+               "..."                                                   { return ELLIPSIS; }
+               ". . ."                                                 { return ELLIPSIS; }
+               ":"                                                             { return COLON; }
+               '&amp;'                                                 { return AMPERSAND_LONG; }
+               "&"                                                             { return AMPERSAND; }
+
+               "\\."                                                   { return ESCAPED_CHARACTER; }
+               "\\!"                                                   { return ESCAPED_CHARACTER; }
+               "\\?"                                                   { return ESCAPED_CHARACTER; }
+
+               "\\,"                                                   { return ESCAPED_CHARACTER; }
+               "\\;"                                                   { return ESCAPED_CHARACTER; }
+               "\\:"                                                   { return ESCAPED_CHARACTER; }
+
+               "\\\""                                                  { return ESCAPED_CHARACTER; }
+               "\\'"                                                   { return ESCAPED_CHARACTER; }
+               "\\`"                                                   { return ESCAPED_CHARACTER; }
+               "\\~"                                                   { return ESCAPED_CHARACTER; }
+
+               "\\("                                                   { return ESCAPED_CHARACTER; }
+               "\\)"                                                   { return ESCAPED_CHARACTER; }
+               "\\{"                                                   { return ESCAPED_CHARACTER; }
+               "\\}"                                                   { return ESCAPED_CHARACTER; }
+               "\\["                                                   { return ESCAPED_CHARACTER; }
+               "\\]"                                                   { return ESCAPED_CHARACTER; }
+
+               "\\#"                                                   { return ESCAPED_CHARACTER; }
+               "\\$"                                                   { return ESCAPED_CHARACTER; }
+               "\\%"                                                   { return ESCAPED_CHARACTER; }
+               "\\+"                                                   { return ESCAPED_CHARACTER; }
+               "\\-"                                                   { return ESCAPED_CHARACTER; }
+               "\\="                                                   { return ESCAPED_CHARACTER; }
+               "\\<"                                                   { return ESCAPED_CHARACTER; }
+               "\\>"                                                   { return ESCAPED_CHARACTER; }
+
+               "\\&"                                                   { return ESCAPED_CHARACTER; }
+               "\\@"                                                   { return ESCAPED_CHARACTER; }
+               "\\\\"                                                  { return ESCAPED_CHARACTER; }
+               "\\/"                                                   { return ESCAPED_CHARACTER; }
+               "\\^"                                                   { return ESCAPED_CHARACTER; }
+
+               "\\*"                                                   { return ESCAPED_CHARACTER; }
+               "\\_"                                                   { return ESCAPED_CHARACTER; }
+
+               "\\|"                                                   { return ESCAPED_CHARACTER; }
+
+               "\\\\("                                                 { return MATH_PAREN_OPEN; }
+               "\\\\)"                                                 { return MATH_PAREN_CLOSE; }
+               "\\\\["                                                 { return MATH_BRACKET_OPEN; }
+               "\\\\]"                                                 { return MATH_BRACKET_CLOSE; }
+               "$"                                                             { return MATH_DOLLAR_SINGLE; }
+               "$$"                                                    { return MATH_DOLLAR_DOUBLE; }
+
+               '^'                                                             { return SUPERSCRIPT; }
+               "~"                                                             { return SUBSCRIPT; }
+
+               INDENT_TAB                                              { return INDENT_TAB; }
+               INDENT_SPACE                                    { return INDENT_SPACE; }
+
+               '#'     SP                                                      { return HASH1; }
+               '#'     / SPNL                                          { return HASH1; }
+               '#'{2} SP                                               { return HASH2; }
+               '#'{2} / SPNL                                   { return HASH2; }
+               '#'{3} SP                                               { return HASH3; }
+               '#'{3} / SPNL                                   { return HASH3; }
+               '#'{4} SP                                               { return HASH4; }
+               '#'{4} / SPNL                                   { return HASH4; }
+               '#'{5} SP                                               { return HASH5; }
+               '#'{5} / SPNL                                   { return HASH5; }
+               '#'{6} SP                                               { return HASH6; }
+               '#'{6} / SPNL                                   { return HASH6; }
+
+
+               [0-9]+ / ('.' (SP|NL))                  { return TEXT_NUMBER_POSS_LIST; }
+               '.' / (SP|NL)                                   { return TEXT_PERIOD; }
+
+               TEXT_LINEBREAK                                  { return TEXT_LINEBREAK; }
+               NL                                                              { return TEXT_NL; }
+
+               NON_INDENT_SPACE                                { return NON_INDENT_SPACE; }
+
+               "*"                                                             { return STAR; }
+               "+"                                                             { return PLUS; }
+               "_"                                                             { return UL; }
+
+               '`'+                                                    { return BACKTICK; }
+
+               '|'+                                                    { return PIPE; }
+               
+               // Skip over anything else - '.' does not include '\n'
+               .                                                               { goto scan; }
+       */
+}
diff --git a/src/libMultiMarkdown.h b/src/libMultiMarkdown.h
new file mode 100644 (file)
index 0000000..a0bcfe8
--- /dev/null
@@ -0,0 +1,298 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file mmd.h
+
+       @brief Header file for libMultiMarkdown.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+
+#ifndef MMD6_H
+#define MMD6_H
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+
+#include "d_string.h"
+#include "token.h"
+
+
+/// MMD Engine is used for storing configuration information for MMD parser
+typedef struct mmd_engine mmd_engine;
+
+
+/// Create MMD Engine using an existing DString (A new copy is *not* made)
+mmd_engine * mmd_engine_create_with_dstring(
+       DString *               d,
+       unsigned long   extensions
+);
+
+
+/// Create MMD Engine using a C string (A private copy of the string will be
+/// made.  The one passed here can be freed by the calling function)
+mmd_engine * mmd_engine_create_with_string(
+       const char *    str,
+       unsigned long   extensions
+);
+
+
+/// Free an existing MMD Engine
+void mmd_engine_free(
+       mmd_engine * e,
+       bool freeDString
+);
+
+
+/// Parse part of the string into a token tree
+token * mmd_engine_parse_substring(mmd_engine * e, size_t byte_start, size_t byte_len);
+
+
+/// Parse the entire string into a token tree
+void mmd_engine_parse_string(mmd_engine * e);
+
+
+void mmd_export_token_tree(DString * out, mmd_engine * e, short format);
+
+
+/// Token types for parse tree
+enum token_types {
+       DOC_START_TOKEN = 0,    //!< DOC_START_TOKEN must be type 0
+
+       BLOCK_BLOCKQUOTE = 50,          //!< This must start *after* the largest number in parser.h
+       BLOCK_CODE_FENCED,
+       BLOCK_CODE_INDENTED,
+       BLOCK_DEF_CITATION,
+       BLOCK_DEF_FOOTNOTE,
+       BLOCK_DEF_LINK,
+       BLOCK_EMPTY,
+       BLOCK_HEADING,                          //!< Placeholder for theme cascading
+       BLOCK_H1,                                       //!< Leave H1, H2, etc. in order
+       BLOCK_H2,
+       BLOCK_H3,
+       BLOCK_H4,
+       BLOCK_H5,
+       BLOCK_H6,
+       BLOCK_HR,
+       BLOCK_HTML,
+       BLOCK_LIST_BULLETED,
+       BLOCK_LIST_BULLETED_LOOSE,
+       BLOCK_LIST_ENUMERATED,
+       BLOCK_LIST_ENUMERATED_LOOSE,
+       BLOCK_LIST_ITEM,
+       BLOCK_LIST_ITEM_TIGHT,
+       BLOCK_PARA,
+       BLOCK_TABLE,
+       ROW_TABLE,
+
+       CRITIC_ADD_OPEN,
+       CRITIC_ADD_CLOSE,
+       CRITIC_DEL_OPEN,
+       CRITIC_DEL_CLOSE,
+       CRITIC_COM_OPEN,
+       CRITIC_COM_CLOSE,
+       CRITIC_SUB_OPEN,
+       CRITIC_SUB_DIV,
+       CRITIC_SUB_DIV_A,
+       CRITIC_SUB_DIV_B,
+       CRITIC_SUB_CLOSE,
+       CRITIC_HI_OPEN,
+       CRITIC_HI_CLOSE,
+
+       PAIR_CRITIC_ADD,
+       PAIR_CRITIC_DEL,
+       PAIR_CRITIC_COM,
+       PAIR_CRITIC_SUB_ADD,
+       PAIR_CRITIC_SUB_DEL,
+       PAIR_CRITIC_HI,
+
+       PAIRS,                  //!< Placeholder for theme cascading
+       PAIR_ANGLE,
+       PAIR_BACKTICK,
+       PAIR_BRACKET,
+       PAIR_BRACKET_FOOTNOTE,
+       PAIR_BRACKET_CITATION,
+       PAIR_BRACKET_IMAGE,
+       PAIR_BRACKET_VARIABLE,
+       PAIR_MATH,
+       PAIR_PAREN,
+       PAIR_QUOTE_SINGLE,
+       PAIR_QUOTE_DOUBLE,
+       PAIR_QUOTE_ALT,
+       PAIR_SUPERSCRIPT,
+       PAIR_STAR,
+       PAIR_UL,
+       PAIR_BRACES,
+
+       STAR,
+       UL,
+       EMPH_START,
+       EMPH_STOP,
+       STRONG_START,
+       STRONG_STOP,
+
+       BRACKET_LEFT,
+       BRACKET_RIGHT,
+       BRACKET_FOOTNOTE_LEFT,
+       BRACKET_CITATION_LEFT,
+       BRACKET_IMAGE_LEFT,
+       BRACKET_VARIABLE_LEFT,
+
+       PAREN_LEFT,
+       PAREN_RIGHT,
+
+       ANGLE_LEFT,
+       ANGLE_RIGHT,
+
+       BRACE_DOUBLE_LEFT,
+       BRACE_DOUBLE_RIGHT,
+
+       AMPERSAND,
+       AMPERSAND_LONG,
+       APOSTROPHE,
+       BACKTICK,
+       CODE_FENCE,
+       COLON,
+       DASH_M,
+       DASH_N,
+       ELLIPSIS,
+       QUOTE_SINGLE,
+       QUOTE_DOUBLE,
+       QUOTE_LEFT_SINGLE,
+       QUOTE_RIGHT_SINGLE,
+       QUOTE_LEFT_DOUBLE,
+       QUOTE_RIGHT_DOUBLE,
+       QUOTE_RIGHT_ALT,
+
+       ESCAPED_CHARACTER,
+
+       MATH_PAREN_OPEN,
+       MATH_PAREN_CLOSE,
+       MATH_BRACKET_OPEN,
+       MATH_BRACKET_CLOSE,
+       MATH_DOLLAR_SINGLE,
+       MATH_DOLLAR_DOUBLE,
+
+       PIPE,
+       PLUS,
+       
+       SUPERSCRIPT,
+       SUBSCRIPT,
+
+       INDENT_TAB,
+       INDENT_SPACE,
+       NON_INDENT_SPACE,
+
+       HASH1,                                                  //!< Leave HASH1, HASH2, etc. in order
+       HASH2,
+       HASH3,
+       HASH4,
+       HASH5,
+       HASH6,
+       MARKER_BLOCKQUOTE,
+       MARKER_H1,                                              //!< Leave MARKER_H1, MARKER_H2, etc. in order
+       MARKER_H2,
+       MARKER_H3,
+       MARKER_H4,
+       MARKER_H5,
+       MARKER_H6,
+       MARKER_LIST_BULLET,
+       MARKER_LIST_ENUMERATOR,
+
+       TEXT_EMPTY,
+       TEXT_LINEBREAK,
+       TEXT_NL,
+       TEXT_NUMBER_POSS_LIST,
+       TEXT_PERIOD,
+       TEXT_PLAIN,
+};
+
+
+/// Define smart typography languages -- first in list is default
+enum smart_language {
+       ENGLISH,
+       DUTCH,
+       FRENCH,
+       GERMAN,
+       GERMANGUILL,
+       SWEDISH,
+};
+
+
+enum output_format {
+       FORMAT_HTML
+};
+
+
+enum parser_extensions {
+       EXT_COMPATIBILITY       = 1 << 0,    //!< Markdown compatibility mode
+       EXT_COMPLETE            = 1 << 1,    //!< Create complete document
+       EXT_SNIPPET             = 1 << 2,    //!< Create snippet only
+       EXT_HEAD_CLOSED         = 1 << 3,    //!< for use by parser
+       EXT_SMART               = 1 << 4,    //!< Enable Smart quotes
+       EXT_NOTES               = 1 << 5,    //!< Enable Footnotes
+       EXT_NO_LABELS           = 1 << 6,    //!< Don't add anchors to headers, etc.
+       EXT_FILTER_STYLES       = 1 << 7,    //!< Filter out style blocks
+       EXT_FILTER_HTML         = 1 << 8,    //!< Filter out raw HTML
+       EXT_PROCESS_HTML        = 1 << 9,    //!< Process Markdown inside HTML
+       EXT_NO_METADATA         = 1 << 10,   //!< Don't parse Metadata
+       EXT_OBFUSCATE           = 1 << 11,   //!< Mask email addresses
+       EXT_CRITIC              = 1 << 12,   //!< Critic Markup Support
+       EXT_CRITIC_ACCEPT       = 1 << 13,   //!< Accept all proposed changes
+       EXT_CRITIC_REJECT       = 1 << 14,   //!< Reject all proposed changes
+       EXT_RANDOM_FOOT         = 1 << 15,   //!< Use random numbers for footnote links
+       EXT_HEADINGSECTION      = 1 << 16,   //!< Group blocks under parent heading
+       EXT_ESCAPED_LINE_BREAKS = 1 << 17,   //!< Escaped line break
+       EXT_NO_STRONG           = 1 << 18,   //!< Don't allow nested \<strong\>'s
+       EXT_NO_EMPH             = 1 << 19,   //!< Don't allow nested \<emph\>'s
+       EXT_FAKE                = 1 << 31,   //!< 31 is highest number allowed
+};
+
+
+#endif
index 7d8ab53b384cfea2c9bd55af6a40b2425e8c6b92..1ad3e8fc3ab67d84ab605b7b31d70ac0e9eb7331 100644 (file)
@@ -1,33 +1,82 @@
-/*
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file main.c
+
+       @brief Create command-line frontend for libMultiMarkdown.
 
-       main.c -- Template main()
 
-       Copyright © 2015-2016 Fletcher T. Penney.
+       @author Fletcher T. Penney
+       @bug    
 
 
-       This program is free software you can redistribute it and/or modify
-       it under the terms of the GNU General Public License as published by
-       the Free Software Foundation either version 2 of the License, or
-       (at your option) any later version.
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
        
-       This program is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-       GNU General Public License for more details.
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
        
-       You should have received a copy of the GNU General Public License
-       along with this program if not, write to the Free Software
-       Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
        
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
 */
 
+#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
+
+#include "argtable3.h"
 #include "d_string.h"
+#include "libMultiMarkdown.h"
+#include "html.h"
+#include "mmd.h"
+#include "token.h"
+#include "version.h"
 
 #define kBUFFERSIZE 4096       // How many bytes to read at a time
 
+// argtable structs
+struct arg_lit *a_help, *a_version, *a_compatibility, *a_nolabels, *a_batch, *a_accept, *a_reject;
+struct arg_str *a_format;
+struct arg_file *a_file, *a_o;
+struct arg_end *a_end;
+struct arg_rem *a_rem1, *a_rem2, *a_rem3;
+
+
 DString * stdin_buffer() {
        /* Read from stdin and return a GString *
                `buffer` will need to be freed elsewhere */
@@ -37,17 +86,18 @@ DString * stdin_buffer() {
 
        DString * buffer = d_string_new("");
 
-    while ((bytes = fread(chunk, 1, kBUFFERSIZE, stdin)) > 0) {
-       d_string_append_c_array(buffer, chunk, bytes);
-    }
+       while ((bytes = fread(chunk, 1, kBUFFERSIZE, stdin)) > 0) {
+               d_string_append_c_array(buffer, chunk, bytes);
+       }
 
        fclose(stdin);
 
        return buffer;
 }
 
-DString * scan_file(char * fname) {
-       /* Read from stdin and return a GString *
+
+DString * scan_file(const char * fname) {
+       /* Read from a file and return a GString *
                `buffer` will need to be freed elsewhere */
 
        char chunk[kBUFFERSIZE];
@@ -61,15 +111,285 @@ DString * scan_file(char * fname) {
 
        DString * buffer = d_string_new("");
 
-    while ((bytes = fread(chunk, 1, kBUFFERSIZE, file)) > 0) {
-       d_string_append_c_array(buffer, chunk, bytes);
-    }
+       while ((bytes = fread(chunk, 1, kBUFFERSIZE, file)) > 0) {
+               d_string_append_c_array(buffer, chunk, bytes);
+       }
 
        fclose(file);
 
        return buffer;
 }
 
-int main( int argc, char** argv ) {
-       /* Make your program do whatever you want */
+
+/// Given a filename, remove the extension and replace it with a new one.
+/// The next extension must include the leading '.', e.g. '.html'
+char * filename_with_extension(const char * original, const char * new_extension) {
+       char * name_no_ext;
+       DString * new_name;
+
+       // Determine output filename without file extension
+       name_no_ext = strdup(original);
+
+       if (strrchr(name_no_ext, '.') != NULL) {
+               long count = strrchr(name_no_ext, '.') - name_no_ext;
+
+               if (count != 0) {
+                       name_no_ext[count] = '\0';
+               }
+       }
+
+       new_name = d_string_new(name_no_ext);
+       free(name_no_ext);
+
+       d_string_append(new_name, new_extension);
+
+       name_no_ext = new_name->str;
+
+       d_string_free(new_name, false);
+
+       return name_no_ext;
+}
+
+
+char * mmd_process(DString * buffer, unsigned long extensions, short format) {
+       char * result;
+
+       mmd_engine * e = mmd_engine_create_with_dstring(buffer, extensions);
+
+       mmd_engine_parse_string(e);
+
+       DString * output = d_string_new("");
+
+       mmd_export_token_tree(output, e, format);
+
+       result = output->str;
+
+       mmd_engine_free(e, false);
+       d_string_free(output, false);
+
+       return result;
+}
+
+
+int main(int argc, char** argv) {
+       int exitcode = EXIT_SUCCESS;
+       char * binname = "multimarkdown";
+       short format = 0;
+
+       // Initialize argtable structs
+       void *argtable[] = {
+               a_help                  = arg_lit0(NULL, "help", "display this help and exit"),
+               a_version               = arg_lit0(NULL, "version", "display version info and exit"),
+
+               a_rem1                  = arg_rem("", ""),
+
+               a_format                = arg_str0("t", "to", "FORMAT", "convert to FORMAT"),
+               a_o                             = arg_file0("o", "output", "FILE", "send output to FILE"),
+
+               a_batch                 = arg_lit0("b", "batch", "process each file separately"),
+               a_compatibility = arg_lit0("c", "compatibility", "Markdown compatibility mode"),
+
+               a_rem2                  = arg_rem("", ""),
+
+               a_accept                = arg_lit0("a", "accept", "accept all CriticMarkup changes"),
+               a_reject                = arg_lit0("r", "reject", "reject all CriticMarkup changes"),
+
+               a_rem3                  = arg_rem("", ""),
+
+               a_nolabels              = arg_lit0(NULL, "nolabels", "Disable id attributes for headers"),
+               
+               a_file                  = arg_filen(NULL, NULL, "<FILE>", 0, argc+2, "read input from file(s)"),
+               a_end                   = arg_end(20),
+       };
+
+       // Set default options
+       a_o->filename[0] = "-";         // Default to stdout if no option specified
+
+       int nerrors = arg_parse(argc, argv, argtable);
+
+       // '--help' takes precedence
+       if (a_help->count > 0) {
+               printf("\n%s v%s\n\n", MULTIMARKDOWN_6_NAME, MULTIMARKDOWN_6_VERSION);
+               printf("\tUsage: %s", binname);
+               arg_print_syntax(stdout, argtable, "\n\n");
+               printf("Options:\n");
+               arg_print_glossary(stdout, argtable, "\t%-25s %s\n");
+               printf("\n");
+               goto exit;
+       }
+
+       if (nerrors > 0) {
+               // Report errors
+               arg_print_errors(stdout, a_end, MULTIMARKDOWN_6_NAME);
+               printf("Try '%s --help' for more information.\n", binname);
+               exitcode = 1;
+               goto exit;
+       }
+
+       // '--version' also takes precedence
+       if (a_version->count > 0) {
+               printf("\nMultiMarkdown 6 v%s\n", MULTIMARKDOWN_6_VERSION);
+               printf("%s\n\n", MULTIMARKDOWN_6_COPYRIGHT);
+               printf("%s\n", MULTIMARKDOWN_6_LICENSE);
+               printf("\n");
+               goto exit;
+       }
+
+
+       // Parse options
+       unsigned long extensions = EXT_SMART | EXT_NOTES | EXT_CRITIC;
+
+       if (a_compatibility->count > 0) {
+               // Compatibility mode disables certain features
+               // Reset extensions
+               extensions = EXT_COMPATIBILITY | EXT_NO_LABELS | EXT_OBFUSCATE;
+       }
+
+       if (a_nolabels->count > 0) {
+               // Disable header id attributes
+               extensions |= EXT_NO_LABELS;
+       }
+
+       if (a_accept->count > 0) {
+               // Accept CriticMarkup changes
+               extensions |= EXT_CRITIC_ACCEPT | EXT_CRITIC;
+       }
+
+       if (a_reject->count > 0) {
+               // Reject CriticMarkup changes
+               extensions |= EXT_CRITIC_REJECT | EXT_CRITIC;
+       }
+
+       if (a_reject->count && a_accept->count) {
+               // Old options that don't apply now, so change them
+               extensions &= ~(EXT_CRITIC_REJECT | EXT_CRITIC_ACCEPT);
+       }
+
+       if (a_format->count > 0) {
+               if (strcmp(a_format->sval[0], "html") == 0)
+                       format = FORMAT_HTML;
+               else {
+                       // No valid format found
+                       fprintf(stderr, "%s: Unknown output format '%s'\n", binname, a_format->sval[0]);
+                       exitcode = 1;
+                       goto exit;
+               }
+       }
+
+       // Determine input
+       if (a_file->count == 0) {
+               // Read from stdin
+       } else {
+               // Read from files
+       }
+
+       DString * buffer = NULL;
+       char * result;
+       FILE * output_stream;
+       char * output_filename;
+
+       // Prepare token pool
+#ifdef kUseObjectPool
+       token_pool_init();
+#endif
+
+       // Determine processing mode -- batch/stdin/files??
+
+       if ((a_batch->count) && (a_file->count)) {
+               // Batch process 1 or more files
+               for (int i = 0; i < a_file->count; ++i)
+               {
+                       buffer = scan_file(a_file->filename[i]);
+
+                       if (buffer == NULL) {
+                               fprintf(stderr, "Error reading file '%s'\n", a_file->filename[i]);
+                               exitcode = 1;
+                               goto exit;
+                       }
+
+                       // Append output file extension
+                       switch (format) {
+                               case FORMAT_HTML:
+                                       output_filename = filename_with_extension(a_file->filename[i], ".html");
+                                       break;
+                       }
+
+                       result = mmd_process(buffer, extensions, format);
+
+                       if (!(output_stream = fopen(output_filename, "w"))) {
+                               // Failed to open file
+                               perror(output_filename);
+                       } else {
+                               fputs(result, output_stream);
+                               fputc('\n', output_stream);
+                               fclose(output_stream);
+                       }
+
+                       d_string_free(buffer, true);
+                       free(result);
+                       free(output_filename);
+               }
+       } else {
+               if (a_file->count) {
+                       // We have files to process
+                       buffer = d_string_new("");
+                       DString * file_buffer;
+
+                       // Concatenate all input files
+                       for (int i = 0; i < a_file->count; ++i)
+                       {
+                               file_buffer = scan_file(a_file->filename[i]);
+
+                               if (file_buffer == NULL) {
+                                       fprintf(stderr, "Error reading file '%s'\n", a_file->filename[i]);
+                                       exitcode = 1;
+                                       goto exit;
+                               }
+
+                               d_string_append_c_array(buffer, file_buffer->str, file_buffer->currentStringLength);
+                               d_string_free(file_buffer, true);
+                       }
+               } else {
+                       // Obtain input from stdin
+                       buffer = stdin_buffer();
+               }
+
+               result = mmd_process(buffer, extensions, format);
+
+               // Where does output go?
+               if (strcmp(a_o->filename[0], "-") == 0) {
+                       // direct to stdout
+                       output_stream = stdout;
+               } else if (!(output_stream = fopen(a_o->filename[0], "w"))) {
+                       perror(a_o->filename[0]);
+                       free(result);
+                       d_string_free(buffer, true);
+       
+                       exitcode = 1;
+                       goto exit;
+               }
+
+               fputs(result, output_stream);
+               fputc('\n', output_stream);
+               
+               if (output_stream != stdout)
+                       fclose(output_stream);
+               
+               d_string_free(buffer, true);
+
+               free(result);
+       }
+
+
+exit:
+
+       // Clean up token pool
+#ifdef kUseObjectPool
+       token_pool_free();
+#endif
+
+       // Clean up after argtable
+       arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+       return exitcode;
 }
+
diff --git a/src/mmd.c b/src/mmd.c
new file mode 100644 (file)
index 0000000..d94fe08
--- /dev/null
+++ b/src/mmd.c
@@ -0,0 +1,1399 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file mmd.c
+
+       @brief Create MMD parsing engine
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "char.h"
+#include "d_string.h"
+#include "html.h"      /// \todo: Remove this for production
+#include "lexer.h"
+#include "libMultiMarkdown.h"
+#include "mmd.h"
+#include "object_pool.h"
+#include "parser.h"
+#include "scanners.h"
+#include "stack.h"
+#include "token.h"
+#include "token_pairs.h"
+
+
+// Basic parser function declarations
+void * ParseAlloc();
+void Parse();
+void ParseFree();
+
+void mmd_pair_tokens_in_block(token * block, token_pair_engine * e, stack * s);
+
+
+
+/// Build MMD Engine
+mmd_engine * mmd_engine_create(DString * d, unsigned long extensions) {
+       mmd_engine * e = malloc(sizeof(mmd_engine));
+
+       if (e) {
+               e->dstr = d;
+
+               e->root = NULL;
+
+               e->extensions = extensions;
+
+               e->citation_stack = stack_new(0);
+               e->definition_stack = stack_new(0);
+               e->footnote_stack = stack_new(0);
+               e->header_stack = stack_new(0);
+               e->link_stack = stack_new(0);
+
+               e->pairings1 = token_pair_engine_new();
+               e->pairings2 = token_pair_engine_new();
+               e->pairings3 = token_pair_engine_new();
+
+               // CriticMarkup
+               if (extensions & EXT_CRITIC) {
+                       token_pair_engine_add_pairing(e->pairings1, CRITIC_ADD_OPEN, CRITIC_ADD_CLOSE, PAIR_CRITIC_ADD, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+                       token_pair_engine_add_pairing(e->pairings1, CRITIC_DEL_OPEN, CRITIC_DEL_CLOSE, PAIR_CRITIC_DEL, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+                       token_pair_engine_add_pairing(e->pairings1, CRITIC_COM_OPEN, CRITIC_COM_CLOSE, PAIR_CRITIC_COM, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+                       token_pair_engine_add_pairing(e->pairings1, CRITIC_SUB_OPEN, CRITIC_SUB_DIV_A, PAIR_CRITIC_SUB_DEL, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+                       token_pair_engine_add_pairing(e->pairings1, CRITIC_SUB_DIV_B, CRITIC_SUB_CLOSE, PAIR_CRITIC_SUB_ADD, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+                       token_pair_engine_add_pairing(e->pairings1, CRITIC_HI_OPEN, CRITIC_HI_CLOSE, PAIR_CRITIC_HI, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+               }
+
+               // Brackets, Parentheses, Angles
+               token_pair_engine_add_pairing(e->pairings2, BRACKET_LEFT, BRACKET_RIGHT, PAIR_BRACKET, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+               token_pair_engine_add_pairing(e->pairings2, BRACKET_CITATION_LEFT, BRACKET_RIGHT, PAIR_BRACKET_CITATION, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+               token_pair_engine_add_pairing(e->pairings2, BRACKET_FOOTNOTE_LEFT, BRACKET_RIGHT, PAIR_BRACKET_FOOTNOTE, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+               token_pair_engine_add_pairing(e->pairings2, BRACKET_IMAGE_LEFT, BRACKET_RIGHT, PAIR_BRACKET_IMAGE, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+               token_pair_engine_add_pairing(e->pairings2, BRACKET_VARIABLE_LEFT, BRACKET_RIGHT, PAIR_BRACKET_VARIABLE, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+               token_pair_engine_add_pairing(e->pairings2, PAREN_LEFT, PAREN_RIGHT, PAIR_PAREN, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+               token_pair_engine_add_pairing(e->pairings2, ANGLE_LEFT, ANGLE_RIGHT, PAIR_ANGLE, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+               token_pair_engine_add_pairing(e->pairings2, BRACE_DOUBLE_LEFT, BRACE_DOUBLE_RIGHT, PAIR_BRACES, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+
+               // Strong/Emph
+               token_pair_engine_add_pairing(e->pairings3, STAR, STAR, PAIR_STAR, 0);
+               token_pair_engine_add_pairing(e->pairings3, UL, UL, PAIR_UL, 0);
+
+               // Quotes and Backticks
+               token_pair_engine_add_pairing(e->pairings2, BACKTICK, BACKTICK, PAIR_BACKTICK, PAIRING_PRUNE_MATCH | PAIRING_MATCH_LENGTH);
+
+               token_pair_engine_add_pairing(e->pairings3, BACKTICK,   QUOTE_RIGHT_ALT,   PAIR_QUOTE_ALT, PAIRING_ALLOW_EMPTY | PAIRING_MATCH_LENGTH);
+               token_pair_engine_add_pairing(e->pairings3, QUOTE_SINGLE, QUOTE_SINGLE, PAIR_QUOTE_SINGLE, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+               token_pair_engine_add_pairing(e->pairings3, QUOTE_DOUBLE, QUOTE_DOUBLE, PAIR_QUOTE_DOUBLE, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+
+               // Math
+               if (!(extensions & EXT_COMPATIBILITY)) {
+                       token_pair_engine_add_pairing(e->pairings2, MATH_PAREN_OPEN, MATH_PAREN_CLOSE, PAIR_MATH, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+                       token_pair_engine_add_pairing(e->pairings2, MATH_BRACKET_OPEN, MATH_BRACKET_CLOSE, PAIR_MATH, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+                       token_pair_engine_add_pairing(e->pairings2, MATH_DOLLAR_SINGLE, MATH_DOLLAR_SINGLE, PAIR_MATH, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+                       token_pair_engine_add_pairing(e->pairings2, MATH_DOLLAR_DOUBLE, MATH_DOLLAR_DOUBLE, PAIR_MATH, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
+               }
+       
+               // Superscript/Subscript
+               if (!(extensions & EXT_COMPATIBILITY)) {
+                       token_pair_engine_add_pairing(e->pairings3, SUPERSCRIPT, SUPERSCRIPT, PAIR_SUPERSCRIPT, 0);
+                       token_pair_engine_add_pairing(e->pairings3, SUBSCRIPT, SUBSCRIPT, PAIR_SUPERSCRIPT, 0);
+               }
+
+       }
+
+       return e;
+}
+
+/// Create MMD Engine using an existing DString (A new copy is *not* made)
+mmd_engine * mmd_engine_create_with_dstring(DString * d, unsigned long extensions) {
+       return mmd_engine_create(d, extensions);
+}
+
+
+/// Create MMD Engine using a C string (A private copy of the string will be
+/// made.  The one passed here can be freed by the calling function)
+mmd_engine * mmd_engine_create_with_string(const char * str, unsigned long extensions) {
+       DString * d = d_string_new(str);
+
+       return mmd_engine_create(d, extensions);
+}
+
+
+/// Free an existing MMD Engine
+void mmd_engine_free(mmd_engine * e, bool freeDString) {
+       if (e == NULL)
+               return;
+
+       if (freeDString)
+               d_string_free(e->dstr, true);
+
+       if (e->extensions & EXT_CRITIC)
+               token_pair_engine_free(e->pairings1);
+       
+       token_pair_engine_free(e->pairings2);
+       token_pair_engine_free(e->pairings3);
+
+       token_tree_free(e->root);
+
+       // Pointers to blocks that are freed elsewhere
+       stack_free(e->definition_stack);
+       stack_free(e->header_stack);
+
+       // Links need to be freed
+       while (e->link_stack->size) {
+               link_free(stack_pop(e->link_stack));
+       }
+       stack_free(e->link_stack);
+
+       // Footnotes need to be freed
+       while (e->footnote_stack->size) {
+               footnote_free(stack_pop(e->footnote_stack));
+       }
+       stack_free(e->footnote_stack);
+       
+       free(e);
+}
+
+
+bool line_is_empty(token * t) {
+       while (t) {
+               switch (t->type) {
+                       case NON_INDENT_SPACE:
+                       case INDENT_TAB:
+                       case INDENT_SPACE:
+                               t = t->next;
+                               break;
+                       case TEXT_LINEBREAK:
+                       case TEXT_NL:
+                               return true;
+                       default:
+                               return false;
+               }
+       }
+
+       return true;
+}
+
+
+/// Determine what sort of line this is
+void mmd_assign_line_type(mmd_engine * e, token * line) {
+       if (!line)
+               return;
+
+       if (!line->child) {
+               line->type = LINE_EMPTY;
+               return;
+       }
+
+       const char * source = e->dstr->str;
+       
+       token * t = NULL;
+       short temp_short;
+       size_t scan_len;
+
+       // Skip non-indenting space
+       if (line->child->type == NON_INDENT_SPACE) {
+               token_remove_first_child(line);
+       } else if (line->child->type == TEXT_PLAIN && line->child->len == 1) {
+               if (source[line->child->start] == ' ')
+                       token_remove_first_child(line);
+       }
+
+       if (line->child == NULL) {
+               line->type = LINE_EMPTY;
+               return;
+       }
+       
+       switch (line->child->type) {
+               case INDENT_TAB:
+                       if (line_is_empty(line->child))
+                               line->type = LINE_EMPTY;
+                       else
+                               line->type = LINE_INDENTED_TAB;
+                       break;
+               case INDENT_SPACE:
+                       if (line_is_empty(line->child))
+                               line->type = LINE_EMPTY;
+                       else
+                               line->type = LINE_INDENTED_SPACE;
+                       break;
+               case ANGLE_LEFT:
+                       if (scan_html_block(&source[line->start]))
+                               line->type = LINE_HTML;
+                       else
+                               line->type = LINE_PLAIN;
+                       break;
+               case ANGLE_RIGHT:
+                       line->type = LINE_BLOCKQUOTE;
+                       line->child->type = MARKER_BLOCKQUOTE;
+                       break;
+               case BACKTICK:
+                       if (e->extensions & EXT_COMPATIBILITY) {
+                               line->type = LINE_PLAIN;
+                               break;
+                       }
+                       scan_len = scan_fence_end(&source[line->child->start]);
+                       if (scan_len) {
+                               line->type = LINE_FENCE_BACKTICK;
+                               break;
+                       } else {
+                               scan_len = scan_fence_start(&source[line->child->start]);
+                               if (scan_len) {
+                                       line->type = LINE_FENCE_BACKTICK_START;
+                                       break;
+                               }
+                       }
+                       line->type = LINE_PLAIN;
+                       break;
+               case HASH1:
+               case HASH2:
+               case HASH3:
+               case HASH4:
+               case HASH5:
+               case HASH6:
+                       line->type = (line->child->type - HASH1) + LINE_ATX_1;
+                       line->child->type = (line->type - LINE_ATX_1) + MARKER_H1;
+
+                       // Strip trailing whitespace from '#' sequence
+                       line->child->len = line->child->type - MARKER_H1 + 1;
+
+                       // Strip trailing '#' sequence if present
+                       if (line->child->tail->type == TEXT_NL) {
+                               if ((line->child->tail->prev->type >= HASH1) &&
+                                       (line->child->tail->prev->type <= HASH6))
+                                       line->child->tail->prev->type = TEXT_EMPTY;
+                       } else {
+                               token_describe(line->child->tail, NULL);
+                               if ((line->child->tail->type >= HASH1) &&
+                                       (line->child->tail->type <= HASH6))
+                                       line->child->tail->type = TEXT_EMPTY;
+                       }
+                       break;
+               case TEXT_NUMBER_POSS_LIST:
+                       switch(source[line->child->next->start]) {
+                               case '.':
+                                       switch(source[line->child->next->start + 1]) {
+                                               case ' ':
+                                               case '\t':
+                                                       line->type = LINE_LIST_ENUMERATED;
+                                                       line->child->type = MARKER_LIST_ENUMERATOR;
+
+                                                       // Strip period
+                                                       line->child->next->type = TEXT_EMPTY;
+
+                                                       switch (line->child->next->next->type) {
+                                                               case TEXT_PLAIN:
+                                                                       // Strip whitespace between bullet and text
+                                                                       while (char_is_whitespace(source[line->child->next->next->start])) {
+                                                                               line->child->next->next->start++;
+                                                                               line->child->next->next->len--;
+                                                                       }
+                                                                       break;
+                                                               case INDENT_SPACE:
+                                                               case INDENT_TAB:
+                                                               case NON_INDENT_SPACE:
+                                                                       t = line->child->next;
+                                                                       while(t->next && ((t->next->type == INDENT_SPACE) ||
+                                                                               (t->next->type == INDENT_TAB) ||
+                                                                               (t->next->type == NON_INDENT_SPACE))) {
+                                                                               tokens_prune(t->next, t->next);
+                                                                       }
+                                                                       break;
+                                                       }
+                                                       break;
+                                               default:
+                                                       line->type = LINE_PLAIN;
+                                                       line->child->type = TEXT_PLAIN;
+                                                       break;
+                                       }
+                                       break;
+                               default:
+                                       line->type = LINE_PLAIN;
+                                       line->child->type = TEXT_PLAIN;
+                                       break;
+                       }
+                       break;
+               case DASH_N:
+               case DASH_M:
+               case STAR:
+               case UL:
+                       // Could this be a horizontal rule?
+                       t = line->child->next;
+                       temp_short = line->child->len;
+                       while (t) {
+                               switch (t->type) {
+                                       case DASH_N:
+                                       case DASH_M:
+                                               if (t->type == line->child->type) {
+                                                       t = t->next;
+                                                       temp_short += t->len;
+                                               } else {
+                                                       temp_short = 0;
+                                                       t = NULL;
+                                               }
+                                               break;
+                                       case STAR:
+                                       case UL:
+                                               if (t->type == line->child->type) {
+                                                       t = t->next;
+                                                       temp_short++;
+                                               } else {
+                                                       temp_short = 0;
+                                                       t = NULL;
+                                               }
+                                               break;
+                                       case NON_INDENT_SPACE:
+                                       case INDENT_TAB:
+                                       case INDENT_SPACE:
+                                               t = t->next;
+                                               break;
+                                       case TEXT_PLAIN:
+                                               if ((t->len == 1) && (source[t->start] == ' ')) {
+                                                       t = t->next;
+                                                       break;
+                                               }
+                                               temp_short = 0;
+                                               t = NULL;
+                                               break;
+                                       case TEXT_NL:
+                                       case TEXT_LINEBREAK:
+                                               t = NULL;
+                                               break;
+                                       default:
+                                               temp_short = 0;
+                                               t = NULL;
+                                               break;
+                               }
+                       }
+                       if (temp_short > 2) {
+                               // This is a horizontal rule, not a list item
+                               line->type = LINE_HR;
+                               break;
+                       }
+                       if (line->child->type == UL) {
+                               // Revert to plain for this type
+                               line->type = LINE_PLAIN;
+                               break;
+                       }
+                       // If longer than 1 character, then it can't be a list marker, so it's a 
+                       // plain line
+                       if (line->child->len > 1) {
+                               line->type = LINE_PLAIN;
+                               break;
+                       }
+               case PLUS:
+                       if (!line->child->next) {
+                               // TODO: Should this be an empty list item instead??
+                               line->type = LINE_PLAIN;
+                       } else {
+                               switch(source[line->child->next->start]) {
+                                       case ' ':
+                                       case '\t':
+                                               line->type = LINE_LIST_BULLETED;
+                                               line->child->type = MARKER_LIST_BULLET;
+
+                                               switch (line->child->next->type) {
+                                                       case TEXT_PLAIN:
+                                                               // Strip whitespace between bullet and text
+                                                               while (char_is_whitespace(source[line->child->next->start])) {
+                                                                       line->child->next->start++;
+                                                                       line->child->next->len--;
+                                                               }
+                                                               break;
+                                                       case INDENT_SPACE:
+                                                       case INDENT_TAB:
+                                                       case NON_INDENT_SPACE:
+                                                               t = line->child;
+                                                               while(t->next && ((t->next->type == INDENT_SPACE) ||
+                                                                       (t->next->type == INDENT_TAB) ||
+                                                                       (t->next->type == NON_INDENT_SPACE))) {
+                                                                       tokens_prune(t->next, t->next);
+                                                               }
+                                                               break;
+                                               }
+                                               break;
+                                       default:
+                                               line->type = LINE_PLAIN;
+                                               break;
+                               }
+                       }
+                       break;
+               case TEXT_LINEBREAK:
+               case TEXT_NL:
+                       line->type = LINE_EMPTY;
+                       break;
+               case BRACKET_LEFT:
+                       if (e->extensions & EXT_COMPATIBILITY) {
+                               scan_len = scan_ref_link_no_attributes(&source[line->start]);
+                               line->type = (scan_len) ? LINE_DEF_LINK : LINE_PLAIN;
+                       } else {
+                               scan_len = scan_ref_link(&source[line->start]);
+                               line->type = (scan_len) ? LINE_DEF_LINK : LINE_PLAIN;
+                       }
+                       break;
+               case BRACKET_CITATION_LEFT:
+                       if (e->extensions & EXT_NOTES) {
+                               scan_len = scan_ref_citation(&source[line->start]);
+                               line->type = (scan_len) ? LINE_DEF_CITATION : LINE_PLAIN;
+                       } else {
+                               line->type = LINE_PLAIN;
+                       }
+                       break;
+               case BRACKET_FOOTNOTE_LEFT:
+                       if (e->extensions & EXT_NOTES) {
+                               scan_len = scan_ref_foot(&source[line->start]);
+                               line->type = (scan_len) ? LINE_DEF_FOOTNOTE : LINE_PLAIN;
+                       } else {
+                               line->type = LINE_PLAIN;
+                       }
+                       break;
+               case TEXT_PLAIN:
+               default:
+                       line->type = LINE_PLAIN;
+                       break;
+       }
+
+       if (line->type == LINE_PLAIN) {
+               token * walker = line->child;
+
+               while (walker != NULL) {
+                       if (walker->type == PIPE) {
+                               line->type = LINE_TABLE;
+
+                               return;
+                       }
+
+                       walker = walker->next;
+               }
+       }
+}
+
+
+/// Strip leading indenting space from line (if present)
+void deindent_line(token  * line) {
+       if (!line || !line->child)
+               return;
+       
+       token * t;
+
+       switch (line->child->type) {
+               case INDENT_TAB:
+               case INDENT_SPACE:
+                       t = line->child;
+                       line->child = t->next;
+                       t->next = NULL;
+                       if (line->child) {
+                               line->child->prev = NULL;
+                               line->child->tail = t->tail;
+                       }
+                       token_free(t);
+                       break;
+       }
+}
+
+
+/// Strip leading indenting space from block
+/// (for recursively parsing nested lists)
+void deindent_block(mmd_engine * e, token * block) {
+       if (!block || !block->child)
+               return;
+
+       token * t = block->child;
+
+       while (t != NULL) {
+               deindent_line(t);
+               mmd_assign_line_type(e, t);
+
+               t = t->next;
+       }
+}
+
+
+/// Strip leading blockquote marker from line
+void strip_quote_markers_from_line(token * line, const char * source) {
+       if (!line || !line->child)
+               return;
+
+       token * t;
+       
+       switch (line->child->type) {
+               case MARKER_BLOCKQUOTE:
+               case NON_INDENT_SPACE:
+                       t = line->child;
+                       line->child = t->next;
+                       t->next = NULL;
+                       if (line->child) {
+                               line->child->prev = NULL;
+                               line->child->tail = t->tail;
+                       }
+                       token_free(t);
+                       break;
+       }
+
+       if (line->child && (line->child->type == TEXT_PLAIN)) {
+               // Strip leading whitespace from first text token
+               t = line->child;
+               
+               while (t->len && char_is_whitespace(source[t->start])) {
+                       t->start++;
+                       t->len--;
+               }
+               
+               if (t->len == 0) {
+                       line->child = t->next;
+                       t->next = NULL;
+                       if (line->child) {
+                               line->child->prev = NULL;
+                               line->child->tail = t->tail;
+                       }
+                       
+                       token_free(t);
+               }
+       }
+}
+
+
+/// Strip leading blockquote markers and non-indent space
+/// (for recursively parsing blockquotes)
+void strip_quote_markers_from_block(mmd_engine * e, token * block) {
+       if (!block || !block->child)
+               return;
+
+       token * t = block->child;
+
+       while (t != NULL) {
+               strip_quote_markers_from_line(t, e->dstr->str);
+               mmd_assign_line_type(e, t);
+
+               t = t->next;
+       }
+}
+
+
+/// Create a token chain from source string
+token * mmd_tokenize_string(mmd_engine * e, const char * str, size_t len) {
+       // Create a scanner (for re2c)
+       Scanner s;
+       s.start = str;
+       s.cur = s.start;
+
+       // Strip trailing whitespace
+//     while (len && char_is_whitespace_or_line_ending(str[len - 1]))
+//             len--;
+       
+       // Where do we stop parsing?
+       const char * stop = str + len;
+
+       int type;                                                               // TOKEN type
+       token * t;                                                              // Create tokens for incorporation
+
+       token * root = token_new(0,0,0);                // Store the final parse tree here
+       token * line = token_new(0,0,0);                // Store current line here
+
+       const char * last_stop = str;                   // Remember where last token ended
+
+       do {
+               // Scan for next token (type of 0 means there is nothing left);
+               type = scan(&s, stop);
+
+               //if (type && s.start != last_stop) {
+        if (s.start != last_stop) {
+                       // We skipped characters between tokens
+
+            if (type) {
+                               // Create a default token type for the skipped characters
+                               t = token_new(TEXT_PLAIN, (size_t)(last_stop - str), (size_t)(s.start - last_stop));
+
+                               token_append_child(line, t);
+            } else {
+                               if (stop > last_stop) {
+                                       // Source text ends without newline
+                                       t = token_new(TEXT_PLAIN, (size_t)(last_stop - str), (size_t)(stop - last_stop));
+                
+                                       token_append_child(line, t);
+                               }
+            }
+               }
+
+               switch (type) {
+                       case 0:
+                               // 0 means we finished with input
+                               // Add current line to root
+
+                               // What sort of line is this?
+                               mmd_assign_line_type(e, line);
+
+                               token_append_child(root, line);
+                               break;
+                       case TEXT_LINEBREAK:
+                       case TEXT_NL:
+                               // We hit the end of a line
+                               t = token_new(type, (size_t)(s.start - str), (size_t)(s.cur - s.start));
+                               token_append_child(line, t);
+
+                               // What sort of line is this?
+                               mmd_assign_line_type(e, line);
+
+                               token_append_child(root, line);
+                               line = token_new(0,s.cur - str,0);
+                               break;
+                       default:
+                               t = token_new(type, (size_t)(s.start - str), (size_t)(s.cur - s.start));
+                               token_append_child(line, t);
+                               break;
+               }
+
+               // Remember where token ends to detect skipped characters
+               last_stop = s.cur;
+       } while (type != 0);
+
+       
+       return root;
+}
+
+
+/// Parse token tree
+void mmd_parse_token_chain(mmd_engine * e, token * chain) {
+
+       void* pParser = ParseAlloc (malloc);            // Create a parser (for lemon)
+       token * walker = chain->child;                          // Walk the existing tree
+       token * remainder;                                                      // Hold unparsed tail of chain
+
+       // Remove existing token tree
+       e->root = NULL;
+
+       while (walker != NULL) {
+               remainder = walker->next;
+
+               // Snip token from remainder
+               walker->next = NULL;
+               walker->tail = walker;
+
+               if (remainder)
+                       remainder->prev = NULL;
+
+               Parse(pParser, walker->type, walker, e);
+
+               walker = remainder;
+       }
+
+       // Signal finish to parser
+       Parse(pParser, 0, NULL, e);
+
+       // Disconnect of (now empty) root
+       chain->child = NULL;
+       token_append_child(chain, e->root);
+       e->root = NULL;
+
+       ParseFree(pParser, free);
+}
+
+
+void mmd_pair_tokens_in_chain(token * head, token_pair_engine * e, stack * s) {
+
+       while (head != NULL) {
+               mmd_pair_tokens_in_block(head, e, s);
+
+               head = head->next;
+       }
+}
+
+
+/// Match token pairs inside block
+void mmd_pair_tokens_in_block(token * block, token_pair_engine * e, stack * s) {
+       if (block == NULL || e == NULL)
+               return;
+
+       // Pair tokens (if appropriate)
+       // \todo: Check for leaf node.  Also, might need to put this somewhere else
+
+       switch (block->type) {
+               case BLOCK_BLOCKQUOTE:
+               case BLOCK_DEF_CITATION:
+               case BLOCK_DEF_FOOTNOTE:
+               case BLOCK_DEF_LINK:
+               case BLOCK_H1:
+               case BLOCK_H2:
+               case BLOCK_H3:
+               case BLOCK_H4:
+               case BLOCK_H5:
+               case BLOCK_H6:
+               case BLOCK_PARA:
+                       token_pairs_match_pairs_inside_token(block, e, s);
+                       break;
+               case DOC_START_TOKEN:
+               case BLOCK_LIST_BULLETED:
+               case BLOCK_LIST_BULLETED_LOOSE:
+               case BLOCK_LIST_ENUMERATED:
+               case BLOCK_LIST_ENUMERATED_LOOSE:
+                       mmd_pair_tokens_in_chain(block->child, e, s);
+                       break;
+               case BLOCK_LIST_ITEM:
+               case BLOCK_LIST_ITEM_TIGHT:
+                       token_pairs_match_pairs_inside_token(block, e, s);
+                       mmd_pair_tokens_in_chain(block->child, e, s);
+                       break;
+               case BLOCK_EMPTY:
+               case BLOCK_CODE_INDENTED:
+               case BLOCK_CODE_FENCED:
+                       // No need to pair tokens in these blocks
+                       break;
+               case LINE_TABLE:
+               case BLOCK_TABLE:       // \TODO: Need to handle tables differently and isolate by cell?
+                       token_pairs_match_pairs_inside_token(block, e, s);
+                       mmd_pair_tokens_in_chain(block->child, e, s);
+                       break;
+               default:
+                       // Nothing to do here
+                       //fprintf(stderr, "What to do for %d\n", block->type);
+                       return;
+       }
+}
+
+
+/// Ambidextrous tokens can open OR close a pair.  This routine gives the opportunity
+/// to change this behavior on case-by-case basis.  For example, in `foo **bar** foo`, the 
+/// first set of asterisks can open, but not close a pair.  The second set can close, but not
+/// open a pair.  This allows for complex behavior without having to bog down the tokenizer
+/// with figuring out which type of asterisk we have.  Default behavior is that open and close
+/// are enabled, so we just have to figure out when to turn it off.
+void mmd_assign_ambidextrous_tokens_in_block(mmd_engine * e, token * block, const char * str, size_t start_offset) {
+       if (block == NULL || block->child == NULL)
+               return;
+
+       size_t offset;          // Temp variable for use below
+       size_t lead_count, lag_count, pre_count, post_count;
+       
+       token * t = block->child;
+
+       while (t != NULL) {
+               switch (t->type) {
+                       case DOC_START_TOKEN:
+                       case BLOCK_BLOCKQUOTE:
+                       case BLOCK_H1:
+                       case BLOCK_H2:
+                       case BLOCK_H3:
+                       case BLOCK_H4:
+                       case BLOCK_H5:
+                       case BLOCK_H6:
+                       case BLOCK_LIST_BULLETED:
+                       case BLOCK_LIST_BULLETED_LOOSE:
+                       case BLOCK_LIST_ENUMERATED:
+                       case BLOCK_LIST_ENUMERATED_LOOSE:
+                       case BLOCK_LIST_ITEM:
+                       case BLOCK_LIST_ITEM_TIGHT:
+                       case BLOCK_PARA:
+                       case BLOCK_TABLE:
+                               // Assign child tokens of blocks
+                               mmd_assign_ambidextrous_tokens_in_block(e, t, str, start_offset);
+                               break;
+                       case CRITIC_SUB_DIV:
+                               // Divide this into two tokens
+                               t->child = token_new(CRITIC_SUB_DIV_B, t->start + 1, 1);
+                               t->child->next = t->next;
+                               t->next = t->child;
+                               t->child = NULL;
+                               t->len = 1;
+                               t->type = CRITIC_SUB_DIV_A;
+                               break;
+                       case STAR:
+                               // Look left and skip over neighboring '*' characters
+                               offset = t->start;
+                               
+                               while ((offset != 0) && ((str[offset] == '*') || (str[offset] == '_'))) {
+                                       offset--;
+                               }
+                               
+                               // We can only close if there is something to left besides whitespace
+                               if ((offset == 0) || (char_is_whitespace_or_line_ending(str[offset]))) {
+                                       // Whitespace or punctuation to left, so can't close
+                                       t->can_close = 0;
+                               }
+                               
+                               // Look right and skip over neighboring '*' characters
+                               offset = t->start + 1;
+                               
+                               while ((str[offset] == '*') || (str[offset] == '_'))
+                                       offset++;
+                               
+                               // We can only open if there is something to right besides whitespace/punctuation
+                               if (char_is_whitespace_or_line_ending(str[offset])) {
+                                       // Whitespace to right, so can't open
+                                       t->can_open = 0;
+                               }
+
+                               // If we're in the middle of a word, then we need to be more precise
+                               if (t->can_open && t->can_close) {
+                                       lead_count = 0;
+                                       lag_count = 0;
+                                       pre_count = 0;
+                                       post_count = 0;
+
+                                       offset = t->start - 1;
+
+                                       // How many '*' in this run before current token?
+                                       while (offset && (str[offset] == '*')) {
+                                               lead_count++;
+                                               offset--;
+                                       }
+
+                                       while (offset && (!char_is_whitespace_or_line_ending_or_punctuation(str[offset]))) {
+                                               offset--;
+                                       }
+
+                                       // Are there '*' at the beginning of this word?
+                                       while ((offset != -1) && (str[offset] == '*')) {
+                                               pre_count++;
+                                               offset--;
+                                       }
+
+                                       offset = t->start + 1;
+
+                                       // How many '*' in this run after current token?
+                                       while (str[offset] == '*') {
+                                               lag_count++;
+                                               offset++;
+                                       }
+
+                                       while (!char_is_whitespace_or_line_ending_or_punctuation(str[offset])) {
+                                               offset++;
+                                       }
+
+                                       // Are there '*' at the end of this word?
+                                       while (offset && (str[offset] == '*')) {
+                                               post_count++;
+                                               offset++;
+                                       }
+
+                                       if (pre_count + post_count > 0) {
+                                               if (pre_count + post_count == lead_count + lag_count + 1) {
+                                                       if (pre_count == post_count) {
+                                                               t->can_open = 0;
+                                                               t->can_close = 0;
+                                                       } else if (pre_count == 0) {
+                                                               t->can_close = 0;
+                                                       } else if (post_count == 0) {
+                                                               t->can_open = 0;
+                                                       }
+                                               } else if (pre_count == lead_count + lag_count + 1 + post_count) {
+                                                       t->can_open = 0;
+                                               } else if (post_count == pre_count + lead_count + lag_count + 1) {
+                                                       t->can_close = 0;
+                                               } else {
+                                                       if (pre_count != lead_count + lag_count + 1) {
+                                                               t->can_close = 0;
+                                                       }
+
+                                                       if (post_count != lead_count + lag_count + 1) {
+                                                               t->can_open = 0;
+                                                       }
+                                               }
+                                       }
+                               }
+                               break;
+                       case UL:
+                               // Look left and skip over neighboring '_' characters
+                               offset = t->start;
+                               
+                               while ((offset != 0) && ((str[offset] == '_') || (str[offset] == '*'))) {
+                                       offset--;
+                               }
+                               
+                               if ((offset == 0) || (char_is_whitespace_or_line_ending_or_punctuation(str[offset]))) {
+                                       // Whitespace or punctuation to left, so can't close
+                                       t->can_close = 0;
+                               }
+
+                               // We don't allow intraword underscores (e.g.  `foo_bar_foo`)
+                               if ((offset > 0) && (char_is_alphanumeric(str[offset]))) {
+                                       // Letters to left, so can't open
+                                       t->can_open = 0;
+                               }
+                               
+                               // Look right and skip over neighboring '_' characters
+                               offset = t->start + 1;
+                               
+                               while ((str[offset] == '*') || (str[offset] == '_'))
+                                       offset++;
+                               
+                               if (char_is_whitespace_or_line_ending_or_punctuation(str[offset])) {
+                                       // Whitespace to right, so can't open
+                                       t->can_open = 0;
+                               }
+                               
+                               if (char_is_alphanumeric(str[offset])) {
+                                       // Letters to right, so can't close
+                                       t->can_close = 0;
+                               }
+
+                               break;
+                       case BACKTICK:
+                               // Backticks are used for code spans, but also for ``foo'' double quote syntax.
+                               // We care only about the quote syntax.
+                               offset = t->start;
+                               
+                               // TODO: This does potentially prevent ``foo `` from closing due to space before closer?
+                               // Bug or feature??
+                               if (t->len != 2)
+                                       break;
+                               
+                               if ((offset == 0) || (str[offset] != '`' && char_is_whitespace_or_line_ending_or_punctuation(str[offset - 1]))) {
+                                       // Whitespace or punctuation to left, so can't close
+                                       t->can_close = 0;
+                               }
+                               break;
+                       case QUOTE_SINGLE:
+                               if (!(e->extensions & EXT_SMART))
+                                       break;
+                               // Some of these are actually APOSTROPHE's and should not be paired
+                               offset = t->start;
+
+                               if (!((offset == 0) || (char_is_whitespace_or_line_ending_or_punctuation(str[offset - 1])) ||
+                                       (char_is_whitespace_or_line_ending_or_punctuation(str[offset + 1])))) {
+                                       t->type = APOSTROPHE;
+                                       break;
+                               }
+
+                               if (offset && (char_is_punctuation(str[offset - 1])) &&
+                                       (char_is_alphanumeric(str[offset + 1]))) {
+                                       t->type = APOSTROPHE;
+                                       break;
+                               }
+                       case QUOTE_DOUBLE:
+                               if (!(e->extensions & EXT_SMART))
+                                       break;
+                               offset = t->start;
+
+                               if ((offset == 0) || (char_is_whitespace_or_line_ending(str[offset - 1]))) {
+                                       t->can_close = 0;
+                               }
+
+                               if (char_is_whitespace_or_line_ending(str[offset + 1])) {
+                                       t->can_open = 0;
+                               }
+
+                               break;
+                       case DASH_N:
+                               if (!(e->extensions & EXT_SMART))
+                                       break;
+                               // We want `1-2` to trigger a DASH_N, but regular hyphen otherwise (`a-b`)
+                               // This doesn't apply to `--` or `---`
+                               offset = t->start;
+                               if (t->len == 1) {
+                                       // Check whether we have '1-2'
+                                       if ((offset == 0) || (!char_is_digit(str[offset - 1])) ||
+                                               (!char_is_digit(str[offset + 1]))) {
+                                               t->type = TEXT_PLAIN;
+                                       }
+                               }
+                               break;
+                       case MATH_DOLLAR_SINGLE:
+                       case MATH_DOLLAR_DOUBLE:
+                               if (e->extensions & EXT_COMPATIBILITY)
+                                       break;
+
+                               offset = t->start;
+
+                               // Look left
+                               if ((offset == 0) || (char_is_whitespace_or_line_ending(str[offset - 1]))) {
+                                       // Whitespace to left, so can't close
+                                       t->can_close = 0;
+                               } else if ((offset != 0) && (!char_is_whitespace_or_line_ending_or_punctuation(str[offset - 1]))){
+                                       // No whitespace or punctuation to left, can't open
+                                       t->can_open = 0;
+                               }
+                               
+                               // Look right
+                               offset = t->start + t->len;
+                               
+                               if (char_is_whitespace_or_line_ending(str[offset])) {
+                                       // Whitespace to right, so can't open
+                                       t->can_open = 0;
+                               } else if (!char_is_whitespace_or_line_ending_or_punctuation(str[offset])) {
+                                       // No whitespace or punctuation to right, can't close
+                                       t->can_close = 0;
+                               }
+                               break;
+                       case SUPERSCRIPT:
+                       case SUBSCRIPT:
+                               if (e->extensions & EXT_COMPATIBILITY)
+                                       break;
+
+                               offset = t->start;
+
+                               // Look left -- no whitespace to left
+                               if ((offset == 0) || (char_is_whitespace_or_line_ending_or_punctuation(str[offset - 1]))) {
+                                       t->can_open = 0;
+                               }
+
+                               if ((offset != 0) && (char_is_whitespace_or_line_ending(str[offset - 1]))) {
+                                       t->can_close = 0;
+                               }
+
+                               offset = t->start + t->len;
+
+                               if (char_is_whitespace_or_line_ending_or_punctuation(str[offset])) {
+                                       t->can_open = 0;
+                               }
+
+                               // We need to be contiguous in order to match
+                               if (t->can_open) {
+                                       offset = t->start + t->len;
+                                       t->can_open = 0;
+
+                                       while (!(char_is_whitespace_or_line_ending(str[offset]))) {
+                                               if (str[offset] == str[t->start])
+                                                       t->can_open = 1;
+                                               offset++;
+                                       }
+
+                                       // Are we a standalone, e.g x^2
+                                       if (!t->can_open) {
+                                               offset = t->start + t->len;
+                                               while (!char_is_whitespace_or_line_ending_or_punctuation(str[offset]))
+                                                       offset++;
+
+                                               t->len = offset-t->start;
+                                               t->can_close = 0;
+
+                                               // Shift next token right and move those characters as child node
+                                               if ((t->next != NULL) && ((t->next->type == TEXT_PLAIN) || (t->next->type == TEXT_NUMBER_POSS_LIST))) {
+                                                       t->next->start += t->len - 1;
+                                                       t->next->len -= t->len - 1;
+
+                                                       t->child = token_new(TEXT_PLAIN, t->start + 1, t->len - 1);
+                                               }
+                                       }
+                               }
+
+                               // We need to be contiguous in order to match
+                               if (t->can_close) {
+                                       offset = t->start;
+                                       t->can_close = 0;
+
+                                       while ((offset > 0) && !(char_is_whitespace_or_line_ending(str[offset - 1]))) {
+                                               if (str[offset - 1] == str[t->start])
+                                                       t->can_close = 1;
+                                               offset--;
+                                       }
+                               }
+                               break;
+               }
+               
+               t = t->next;
+       }
+
+}
+
+
+/// Strong/emph parsing is done using single `*` and `_` characters, which are
+/// then combined in a separate routine here to determine when 
+/// consecutive characters should be interpreted as STRONG instead of EMPH
+/// \todo: Perhaps combining this with the routine when they are paired
+/// would improve performance?
+void pair_emphasis_tokens(token * t) {
+       token * closer;
+       
+       while (t != NULL) {
+               if (t->mate != NULL) {
+                       switch (t->type) {
+                               case STAR:
+                               case UL:
+                                       closer = t->mate;
+                                       if ((t->next->mate == closer->prev) &&
+                                               (t->type == t->next->type) &&
+                                               (t->next->mate != t) &&
+                                               (t->start+t->len == t->next->start) &&
+                                               (closer->start == closer->prev->start + closer->prev->len)) {
+                                               
+                                               // We have a strong pair
+                                               t->type = STRONG_START;
+                                               t->len = 2;
+                                               closer->type = STRONG_STOP;
+                                               closer->len = 2;
+                                               closer->start--;
+                                               
+                                               tokens_prune(t->next, t->next);
+                                               tokens_prune(closer->prev, closer->prev);
+                                       } else {
+                                               t->type = EMPH_START;
+                                               closer->type = EMPH_STOP;
+                                       }
+                                       break;
+                                       
+                               default:
+                                       break;
+                       }
+
+               }
+               
+               if (t->child != NULL)
+                       pair_emphasis_tokens(t->child);
+               
+               t = t->next;
+       }
+}
+
+
+void recursive_parse_list_item(mmd_engine * e, token * block) {
+       // Strip list marker from first line
+       token_remove_first_child(block->child);
+
+       // Remove all leading space from first line of list item
+//     strip_all_leading_space(block->child)
+
+       // Remove one indent level from all lines to allow recursive parsing
+       deindent_block(e, block);
+
+       mmd_parse_token_chain(e, block);
+}
+
+
+void is_list_loose(token * list) {
+       bool loose = false;
+       
+       token * walker = list->child;
+
+       while (walker->next != NULL) {
+               if (walker->type == BLOCK_LIST_ITEM) {
+                       if (walker->child->type == BLOCK_PARA) {
+                               loose = true;
+                       } else {
+                               walker->type = BLOCK_LIST_ITEM_TIGHT;
+                       }
+               }
+               
+               walker = walker->next;
+       }
+
+       if (loose) {
+               switch (list->type) {
+                       case BLOCK_LIST_BULLETED:
+                               list->type = BLOCK_LIST_BULLETED_LOOSE;
+                               break;
+                       case BLOCK_LIST_ENUMERATED:
+                               list->type = BLOCK_LIST_ENUMERATED_LOOSE;
+                               break;
+               }
+       }
+}
+
+
+/// Is this actually an HTML block?
+void is_para_html(mmd_engine * e, token * block) {
+       if (block->child->type != LINE_PLAIN)
+               return;
+       token * t = block->child->child;
+
+       if (t->type != ANGLE_LEFT)
+               return;
+
+       if (scan_html_block(&(e->dstr->str[t->start]))) {
+               block->type = BLOCK_HTML;
+               return;
+       }       
+
+       if (scan_html_line(&(e->dstr->str[t->start]))) {
+               block->type = BLOCK_HTML;
+               return;
+       }
+}
+
+void recursive_parse_blockquote(mmd_engine * e, token * block) {
+       // Strip blockquote markers (if present)
+       strip_quote_markers_from_block(e, block);
+
+       mmd_parse_token_chain(e, block);
+}
+
+
+void strip_line_tokens_from_block(token * block) {
+       if ((block == NULL) || (block->child == NULL))
+               return;
+
+#ifndef NDEBUG
+       fprintf(stderr, "Strip line tokens from %d (%lu:%lu) (child %d)\n", block->type, block->start, block->len, block->child->type);
+       token_tree_describe(block, NULL);
+#endif
+
+       token * l = block->child;
+
+       // Strip trailing empty lines from indented code blocks
+       if (block->type == BLOCK_CODE_INDENTED) {
+               while (l->tail->type == LINE_EMPTY)
+                       token_remove_last_child(block);
+       }
+
+       token * children = NULL;
+       block->child = NULL;
+
+       token * temp;
+
+
+       // Move contents of line directly into the parent block
+       while (l != NULL) {
+               switch (l->type) {
+                       case LINE_ATX_1:
+                       case LINE_ATX_2:
+                       case LINE_ATX_3:
+                       case LINE_ATX_4:
+                       case LINE_ATX_5:
+                       case LINE_ATX_6:
+                       case LINE_BLOCKQUOTE:
+                       case LINE_CONTINUATION:
+                       case LINE_DEF_CITATION:
+                       case LINE_DEF_FOOTNOTE:
+                       case LINE_DEF_LINK:
+                       case LINE_EMPTY:
+                       case LINE_LIST_BULLETED:
+                       case LINE_LIST_ENUMERATED:
+                       case LINE_PLAIN:
+                               // Remove leading non-indent space from line
+                               if (l->child && l->child->type == NON_INDENT_SPACE)
+                               token_remove_first_child(l);
+
+                       case LINE_INDENTED_TAB:
+                       case LINE_INDENTED_SPACE:
+                               // Strip leading indent (Only the first one)
+                               if (l->child && ((l->child->type == INDENT_SPACE) || (l->child->type == INDENT_TAB)))
+                                       token_remove_first_child(l);
+
+                               // If we're not a code block, strip additional indents
+                               if ((block->type != BLOCK_CODE_INDENTED) && 
+                                       (block->type != BLOCK_CODE_FENCED)) {
+                                       while (l->child && ((l->child->type == INDENT_SPACE) || (l->child->type == INDENT_TAB)))
+                                               token_remove_first_child(l);
+                               }
+                               // Add contents of line to parent block
+                               token_append_child(block, l->child);
+
+                               // Disconnect line from it's contents
+                               l->child = NULL;
+
+                               // Need to remember first line we strip
+                               if (children == NULL)
+                                       children = l;
+
+                               // Advance to next line
+                               l = l->next;
+                               break;
+                       case LINE_TABLE:
+                               l->type = ROW_TABLE;
+                               break;
+                       default:
+                               // This is a block, need to remove it from chain and
+                               // Add to parent
+                               temp = l->next;
+
+                               token_pop_link_from_chain(l);
+                               token_append_child(block, l);
+
+                               // Advance to next line
+                               l = temp;
+                               break;
+               }
+       }
+
+       // Free token chain of line types
+       token_tree_free(children);
+}
+
+
+/// Parse part of the string into a token tree
+token * mmd_engine_parse_substring(mmd_engine * e, size_t byte_start, size_t byte_len) {
+#ifdef kUseObjectPool
+       // Ensure token pool is available and ready
+       token_pool_init();
+#endif
+
+       // Reset definition stack
+       e->definition_stack->size = 0;
+       
+       // Tokenize the string
+       token * doc = mmd_tokenize_string(e, &e->dstr->str[byte_start], byte_len);
+
+       // Parse tokens into blocks
+       mmd_parse_token_chain(e, doc);
+
+       if (doc) {
+               // Parse blocks for pairs
+               mmd_assign_ambidextrous_tokens_in_block(e, doc, &e->dstr->str[byte_start], 0);
+
+               // Prepare stack to be used for token pairing
+               // This avoids allocating/freeing one for each iteration.
+               stack * pair_stack = stack_new(0);
+
+               mmd_pair_tokens_in_block(doc, e->pairings1, pair_stack);
+               mmd_pair_tokens_in_block(doc, e->pairings2, pair_stack);
+               mmd_pair_tokens_in_block(doc, e->pairings3, pair_stack);
+
+               // Free stack
+               stack_free(pair_stack);
+
+               pair_emphasis_tokens(doc);
+
+#ifndef NDEBUG
+               token_tree_describe(doc, &e->dstr->str[byte_start]);
+#endif
+       }
+
+       return doc;
+}
+
+
+/// Parse the entire string into a token tree
+void mmd_engine_parse_string(mmd_engine * e) {
+       // Free existing parse tree
+       if (e->root)
+               token_tree_free(e->root);
+
+       // New parse tree
+       e->root = mmd_engine_parse_substring(e, 0, e->dstr->currentStringLength);
+}
+
diff --git a/src/mmd.h b/src/mmd.h
new file mode 100644 (file)
index 0000000..f44ee82
--- /dev/null
+++ b/src/mmd.h
@@ -0,0 +1,91 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file mmd.h
+
+       @brief Create MMD parsing engine
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+
+#ifndef MMD_MULTIMARKDOWN_H
+#define MMD_MULTIMARKDOWN_H
+
+#include "d_string.h"
+#include "libMultiMarkdown.h"
+#include "stack.h"
+#include "token.h"
+#include "token_pairs.h"
+
+struct mmd_engine {
+       DString *                               dstr;
+       token *                                 root;
+       unsigned long                   extensions;
+
+       token_pair_engine *             pairings1;
+       token_pair_engine *             pairings2;
+       token_pair_engine *             pairings3;
+
+       stack *                                 citation_stack;
+       stack *                                 definition_stack;
+       stack *                                 header_stack;
+       stack *                                 footnote_stack;
+       stack *                                 link_stack;
+};
+
+
+/// Expose routines to lemon parser
+void recursive_parse_list_item(mmd_engine * e, token * block);
+void recursive_parse_blockquote(mmd_engine * e, token * block);
+void strip_line_tokens_from_block(token * block);
+void is_para_html(mmd_engine * e, token * block);
+
+
+void is_list_loose(token * list);
+
+#endif
diff --git a/src/object_pool.c b/src/object_pool.c
new file mode 100644 (file)
index 0000000..9579c8d
--- /dev/null
@@ -0,0 +1,140 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file object_pool.c
+
+       @brief Allocate memory for "objects" in large slabs, rather than one at a time. Improves
+       performance when generating large numbers of small chunks of memory, as the expense of 
+       allocating memory in larger units.  Could cause difficulty in extreme low memory situations.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+#include <stdlib.h>
+
+#include "object_pool.h"
+
+#define kNumberOfObjects       1024
+
+
+void pool_add_slab(pool * p) {
+       void * slab = malloc(p->object_size * kNumberOfObjects);
+
+       if (slab) {
+               stack_push(p->allocated, slab);
+
+               // Next object will come from beginning of this slab
+               p->next = slab;
+
+               // Set warning to trigger need for next slab
+               p->last = slab + (p->object_size * (kNumberOfObjects));
+       }
+}
+
+
+/// Allocate a new object pool
+pool * pool_new(short size) {
+       pool * p = malloc(sizeof(pool));
+
+       if (p) {
+               p->object_size = size;
+
+               p->allocated = stack_new(1024);
+
+               pool_add_slab(p);
+       }
+
+       return p;
+}
+
+
+/// Free object pool
+void pool_free(pool * p) {
+       if (p) {
+               pool_drain(p);
+
+               stack_free(p->allocated);
+
+               free(p);
+       }
+}
+
+
+/// Drain pool -- free slabs previously allocated
+void pool_drain(pool * p) {
+       if (p == NULL)
+               return;
+
+       void * slab;
+
+       while (p->allocated->size > 0) {
+               slab = stack_pop(p->allocated);
+               free(slab);
+       }
+
+       p->next = NULL;
+       p->last = NULL;
+}
+
+
+/// Request memory for a new object from the pool
+void * pool_allocate_object(pool * p) {
+       void * a = NULL;
+
+       if (p->next == p->last) {
+               pool_add_slab(p);
+       }
+
+       if (p->next < p->last) {
+               a = p->next;
+
+               p->next += (p->object_size);
+       }
+
+       return a;
+}
+
diff --git a/src/object_pool.h b/src/object_pool.h
new file mode 100644 (file)
index 0000000..a311c4a
--- /dev/null
@@ -0,0 +1,101 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file object_pool.h
+
+       @brief Allocate memory for "objects" in large slabs, rather than one at a time. Improves
+       performance when generating large numbers of small chunks of memory, as the expense of 
+       allocating memory in larger units.  Could cause difficulty in extreme low memory situations.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+
+#ifndef OBJECT_POOL_MULTIMARKDOWN_H
+#define OBJECT_POOL_MULTIMARKDOWN_H
+
+#include "stack.h"
+
+
+/// Structure for an object allocator pool
+struct pool {
+       stack *                 allocated;              //!< Stack of pointers to slabs that have been allocated
+       void *                  next;                   //!< Pointer to next available memory for allocation
+       void *                  last;                   //!< Pointer to end of available memory
+       short                   object_size;    //!< Size of individual objects to be allocated
+
+       char                    _PADDING[6];    //!< pad struct for alignment
+};
+
+typedef struct pool pool;
+
+
+/// Allocate a new object pool
+pool * pool_new(
+       short size                                              //!< How big are the objects to be allocated
+);
+
+
+/// Free object pool
+void pool_free(
+       pool * p                                                //!< Pool to be freed
+);
+
+
+/// Drain pool -- free slabs previously allocated
+void pool_drain(
+       pool * p                                                //!< Pool to be drained
+);
+
+
+/// Request memory for a new object from the pool
+void * pool_allocate_object(
+       pool * p                                                //!< Pool to be used for allocation
+);
+
+
+#endif
diff --git a/src/parser.c b/src/parser.c
new file mode 100644 (file)
index 0000000..f325eb0
--- /dev/null
@@ -0,0 +1,1431 @@
+/*
+** 2000-05-29
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** Driver template for the LEMON parser generator.
+**
+** The "lemon" program processes an LALR(1) input grammar file, then uses
+** this template to construct a parser.  The "lemon" program inserts text
+** at each "%%" line.  Also, any "P-a-r-s-e" identifer prefix (without the
+** interstitial "-" characters) contained in this template is changed into
+** the value of the %name directive from the grammar.  Otherwise, the content
+** of this template is copied straight through into the generate parser
+** source file.
+**
+** The following is the concatenation of all %include directives from the
+** input grammar file:
+*/
+#include <stdio.h>
+/************ Begin %include sections from the grammar ************************/
+
+       #include <assert.h>
+       #include <stdio.h>
+       #include <stdlib.h>
+
+       #include "libMultiMarkdown.h"
+       #include "mmd.h"
+       #include "parser.h"
+       #include "token.h"
+/**************** End of %include directives **********************************/
+/* These constants specify the various numeric values for terminal symbols
+** in a format understandable to "makeheaders".  This section is blank unless
+** "lemon" is run with the "-m" command-line option.
+***************** Begin makeheaders token definitions *************************/
+/**************** End makeheaders token definitions ***************************/
+
+/* The next sections is a series of control #defines.
+** various aspects of the generated parser.
+**    YYCODETYPE         is the data type used to store the integer codes
+**                       that represent terminal and non-terminal symbols.
+**                       "unsigned char" is used if there are fewer than
+**                       256 symbols.  Larger types otherwise.
+**    YYNOCODE           is a number of type YYCODETYPE that is not used for
+**                       any terminal or nonterminal symbol.
+**    YYFALLBACK         If defined, this indicates that one or more tokens
+**                       (also known as: "terminal symbols") have fall-back
+**                       values which should be used if the original symbol
+**                       would not parse.  This permits keywords to sometimes
+**                       be used as identifiers, for example.
+**    YYACTIONTYPE       is the data type used for "action codes" - numbers
+**                       that indicate what to do in response to the next
+**                       token.
+**    ParseTOKENTYPE     is the data type used for minor type for terminal
+**                       symbols.  Background: A "minor type" is a semantic
+**                       value associated with a terminal or non-terminal
+**                       symbols.  For example, for an "ID" terminal symbol,
+**                       the minor type might be the name of the identifier.
+**                       Each non-terminal can have a different minor type.
+**                       Terminal symbols all have the same minor type, though.
+**                       This macros defines the minor type for terminal 
+**                       symbols.
+**    YYMINORTYPE        is the data type used for all minor types.
+**                       This is typically a union of many types, one of
+**                       which is ParseTOKENTYPE.  The entry in the union
+**                       for terminal symbols is called "yy0".
+**    YYSTACKDEPTH       is the maximum depth of the parser's stack.  If
+**                       zero the stack is dynamically sized using realloc()
+**    ParseARG_SDECL     A static variable declaration for the %extra_argument
+**    ParseARG_PDECL     A parameter declaration for the %extra_argument
+**    ParseARG_STORE     Code to store %extra_argument into yypParser
+**    ParseARG_FETCH     Code to extract %extra_argument from yypParser
+**    YYERRORSYMBOL      is the code number of the error symbol.  If not
+**                       defined, then do no error processing.
+**    YYNSTATE           the combined number of states.
+**    YYNRULE            the number of rules in the grammar
+**    YY_MAX_SHIFT       Maximum value for shift actions
+**    YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
+**    YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
+**    YY_MIN_REDUCE      Maximum value for reduce actions
+**    YY_ERROR_ACTION    The yy_action[] code for syntax error
+**    YY_ACCEPT_ACTION   The yy_action[] code for accept
+**    YY_NO_ACTION       The yy_action[] code for no-op
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/************* Begin control #defines *****************************************/
+#define YYCODETYPE unsigned char
+#define YYNOCODE 54
+#define YYACTIONTYPE unsigned short int
+#define ParseTOKENTYPE  token * 
+typedef union {
+  int yyinit;
+  ParseTOKENTYPE yy0;
+} YYMINORTYPE;
+#ifndef YYSTACKDEPTH
+#define YYSTACKDEPTH 100
+#endif
+#define ParseARG_SDECL  mmd_engine * engine ;
+#define ParseARG_PDECL , mmd_engine * engine 
+#define ParseARG_FETCH  mmd_engine * engine  = yypParser->engine 
+#define ParseARG_STORE yypParser->engine  = engine 
+#define YYFALLBACK 1
+#define YYNSTATE             38
+#define YYNRULE              85
+#define YY_MAX_SHIFT         37
+#define YY_MIN_SHIFTREDUCE   88
+#define YY_MAX_SHIFTREDUCE   172
+#define YY_MIN_REDUCE        173
+#define YY_MAX_REDUCE        257
+#define YY_ERROR_ACTION      258
+#define YY_ACCEPT_ACTION     259
+#define YY_NO_ACTION         260
+/************* End control #defines *******************************************/
+
+/* Define the yytestcase() macro to be a no-op if is not already defined
+** otherwise.
+**
+** Applications can choose to define yytestcase() in the %include section
+** to a macro that can assist in verifying code coverage.  For production
+** code the yytestcase() macro should be turned off.  But it is useful
+** for testing.
+*/
+#ifndef yytestcase
+# define yytestcase(X)
+#endif
+
+
+/* Next are the tables used to determine what action to take based on the
+** current state and lookahead token.  These tables are used to implement
+** functions that take a state number and lookahead value and return an
+** action integer.  
+**
+** Suppose the action integer is N.  Then the action is determined as
+** follows
+**
+**   0 <= N <= YY_MAX_SHIFT             Shift N.  That is, push the lookahead
+**                                      token onto the stack and goto state N.
+**
+**   N between YY_MIN_SHIFTREDUCE       Shift to an arbitrary state then
+**     and YY_MAX_SHIFTREDUCE           reduce by rule N-YY_MIN_SHIFTREDUCE.
+**
+**   N between YY_MIN_REDUCE            Reduce by rule N-YY_MIN_REDUCE
+**     and YY_MAX_REDUCE
+**
+**   N == YY_ERROR_ACTION               A syntax error has occurred.
+**
+**   N == YY_ACCEPT_ACTION              The parser accepts its input.
+**
+**   N == YY_NO_ACTION                  No such action.  Denotes unused
+**                                      slots in the yy_action[] table.
+**
+** The action table is constructed as a single large table named yy_action[].
+** Given state S and lookahead X, the action is computed as either:
+**
+**    (A)   N = yy_action[ yy_shift_ofst[S] + X ]
+**    (B)   N = yy_default[S]
+**
+** The (A) formula is preferred.  The B formula is used instead if:
+**    (1)  The yy_shift_ofst[S]+X value is out of range, or
+**    (2)  yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or
+**    (3)  yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT.
+** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that
+** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X.
+** Hence only tests (1) and (2) need to be evaluated.)
+**
+** The formulas above are for computing the action when the lookahead is
+** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
+** a reduce action) then the yy_reduce_ofst[] array is used in place of
+** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
+** YY_SHIFT_USE_DFLT.
+**
+** The following are the tables generated in this section:
+**
+**  yy_action[]        A single table containing all actions.
+**  yy_lookahead[]     A table containing the lookahead for each entry in
+**                     yy_action.  Used to detect hash collisions.
+**  yy_shift_ofst[]    For each state, the offset into yy_action for
+**                     shifting terminals.
+**  yy_reduce_ofst[]   For each state, the offset into yy_action for
+**                     shifting non-terminals after a reduce.
+**  yy_default[]       Default action for each state.
+**
+*********** Begin parsing tables **********************************************/
+#define YY_ACTTAB_COUNT (162)
+static const YYACTIONTYPE yy_action[] = {
+ /*     0 */   173,  153,   20,  147,  148,   93,   94,   95,   96,   97,
+ /*    10 */    98,  104,  153,   14,    5,    4,  162,    3,    2,   15,
+ /*    20 */    13,   12,   11,   20,  147,  148,   93,   94,   95,   96,
+ /*    30 */    97,   98,  104,  153,   14,    5,    4,  162,    3,    2,
+ /*    40 */    15,   13,   12,   11,  259,    1,   90,   91,   10,   37,
+ /*    50 */    35,   33,  102,   36,  105,  106,  107,  108,  109,  112,
+ /*    60 */   112,   26,   26,   27,   27,   35,  168,   33,   89,   91,
+ /*    70 */    10,   37,   35,   33,  102,   36,  105,  106,  107,  108,
+ /*    80 */   109,   28,  146,  146,   28,  169,   28,   35,  143,   33,
+ /*    90 */    25,    6,    6,  153,    7,    7,  138,   28,   16,  111,
+ /*   100 */    16,   18,   28,   18,  171,  126,   28,    8,    8,   28,
+ /*   110 */    29,   29,    9,    9,   21,  172,   21,  111,  171,   23,
+ /*   120 */   111,   23,   28,   17,  141,   17,   19,   28,   19,  172,
+ /*   130 */   115,  151,  152,  111,  171,  157,    4,  121,  111,   22,
+ /*   140 */   150,   22,  151,  152,   24,  172,   24,  156,   30,   30,
+ /*   150 */     5,  113,   31,   31,  139,   32,   32,   34,   34,  116,
+ /*   160 */   129,  113,
+};
+static const YYCODETYPE yy_lookahead[] = {
+ /*     0 */     0,   12,    2,    3,    4,    5,    6,    7,    8,    9,
+ /*    10 */    10,   11,   12,   13,   14,   15,   16,   17,   18,   19,
+ /*    20 */    20,   21,   22,    2,    3,    4,    5,    6,    7,    8,
+ /*    30 */     9,   10,   11,   12,   13,   14,   15,   16,   17,   18,
+ /*    40 */    19,   20,   21,   22,   24,   25,   26,   27,   28,   29,
+ /*    50 */    30,   31,   32,   33,   34,   35,   36,   37,   38,   41,
+ /*    60 */    42,   51,   52,   51,   52,   45,    1,   47,   26,   27,
+ /*    70 */    28,   29,   30,   31,   32,   33,   34,   35,   36,   37,
+ /*    80 */    38,   29,    1,    1,   29,   20,   29,   45,   52,   47,
+ /*    90 */    42,   39,   40,   12,   39,   40,   50,   29,   46,   40,
+ /*   100 */    48,   46,   29,   48,    1,   48,   29,   39,   40,   29,
+ /*   110 */    49,   50,   39,   40,   46,   12,   48,   40,    1,   46,
+ /*   120 */    40,   48,   29,   46,   21,   48,   46,   29,   48,   12,
+ /*   130 */    44,    3,    4,   40,    1,    1,   15,   47,   40,   46,
+ /*   140 */    12,   48,    3,    4,   46,   12,   48,   13,   43,   44,
+ /*   150 */    14,   12,   39,   40,   21,   39,   40,   39,   40,   45,
+ /*   160 */    16,   12,
+};
+#define YY_SHIFT_USE_DFLT (162)
+#define YY_SHIFT_COUNT    (37)
+#define YY_SHIFT_MIN      (-11)
+#define YY_SHIFT_MAX      (149)
+static const short yy_shift_ofst[] = {
+ /*     0 */    21,    0,   81,   81,   81,   81,   81,   81,   81,   81,
+ /*    10 */   128,  117,  117,   65,  134,   82,  -11,  -11,  -11,  -11,
+ /*    20 */    82,  -11,  -11,  -11,  -11,   82,  103,  133,  139,   65,
+ /*    30 */   134,   82,   82,  121,   82,  136,  144,  149,
+};
+#define YY_REDUCE_USE_DFLT (-1)
+#define YY_REDUCE_COUNT (35)
+#define YY_REDUCE_MIN   (0)
+#define YY_REDUCE_MAX   (118)
+static const signed char yy_reduce_ofst[] = {
+ /*     0 */    20,   42,   52,   55,   68,   73,   77,   80,   93,   98,
+ /*    10 */    18,   10,   12,   61,  105,  113,   57,   57,   57,   57,
+ /*    20 */   116,   57,   57,   57,   57,  118,   36,   36,   48,   46,
+ /*    30 */    86,   59,   59,   90,   59,  114,
+};
+static const YYACTIONTYPE yy_default[] = {
+ /*     0 */   258,  258,  249,  248,  210,  205,  219,  216,  208,  203,
+ /*    10 */   177,  258,  258,  251,  239,  250,  220,  218,  217,  215,
+ /*    20 */   229,  209,  207,  204,  202,  213,  227,  225,  246,  222,
+ /*    30 */   199,  221,  195,  186,  212,  185,  188,  184,
+};
+/********** End of lemon-generated parsing tables *****************************/
+
+/* The next table maps tokens (terminal symbols) into fallback tokens.  
+** If a construct like the following:
+** 
+**      %fallback ID X Y Z.
+**
+** appears in the grammar, then ID becomes a fallback token for X, Y,
+** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
+** but it does not parse, the type of the token is changed to ID and
+** the parse is retried before an error is thrown.
+**
+** This feature can be used, for example, to cause some keywords in a language
+** to revert to identifiers if they keyword does not apply in the context where
+** it appears.
+*/
+#ifdef YYFALLBACK
+static const YYCODETYPE yyFallback[] = {
+    0,  /*          $ => nothing */
+    0,  /* LINE_CONTINUATION => nothing */
+    1,  /* LINE_PLAIN => LINE_CONTINUATION */
+    1,  /* LINE_INDENTED_TAB => LINE_CONTINUATION */
+    1,  /* LINE_INDENTED_SPACE => LINE_CONTINUATION */
+};
+#endif /* YYFALLBACK */
+
+/* The following structure represents a single element of the
+** parser's stack.  Information stored includes:
+**
+**   +  The state number for the parser at this level of the stack.
+**
+**   +  The value of the token stored at this level of the stack.
+**      (In other words, the "major" token.)
+**
+**   +  The semantic value stored at this level of the stack.  This is
+**      the information used by the action routines in the grammar.
+**      It is sometimes called the "minor" token.
+**
+** After the "shift" half of a SHIFTREDUCE action, the stateno field
+** actually contains the reduce action for the second half of the
+** SHIFTREDUCE.
+*/
+struct yyStackEntry {
+  YYACTIONTYPE stateno;  /* The state-number, or reduce action in SHIFTREDUCE */
+  YYCODETYPE major;      /* The major token value.  This is the code
+                         ** number for the token at this stack level */
+  YYMINORTYPE minor;     /* The user-supplied minor token value.  This
+                         ** is the value of the token  */
+};
+typedef struct yyStackEntry yyStackEntry;
+
+/* The state of the parser is completely contained in an instance of
+** the following structure */
+struct yyParser {
+  yyStackEntry *yytos;          /* Pointer to top element of the stack */
+#ifdef YYTRACKMAXSTACKDEPTH
+  int yyhwm;                    /* High-water mark of the stack */
+#endif
+#ifndef YYNOERRORRECOVERY
+  int yyerrcnt;                 /* Shifts left before out of the error */
+#endif
+  ParseARG_SDECL                /* A place to hold %extra_argument */
+#if YYSTACKDEPTH<=0
+  int yystksz;                  /* Current side of the stack */
+  yyStackEntry *yystack;        /* The parser's stack */
+  yyStackEntry yystk0;          /* First stack entry */
+#else
+  yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
+#endif
+};
+typedef struct yyParser yyParser;
+
+#ifndef NDEBUG
+#include <stdio.h>
+static FILE *yyTraceFILE = 0;
+static char *yyTracePrompt = 0;
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* 
+** Turn parser tracing on by giving a stream to which to write the trace
+** and a prompt to preface each trace message.  Tracing is turned off
+** by making either argument NULL 
+**
+** Inputs:
+** <ul>
+** <li> A FILE* to which trace output should be written.
+**      If NULL, then tracing is turned off.
+** <li> A prefix string written at the beginning of every
+**      line of trace output.  If NULL, then tracing is
+**      turned off.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
+  yyTraceFILE = TraceFILE;
+  yyTracePrompt = zTracePrompt;
+  if( yyTraceFILE==0 ) yyTracePrompt = 0;
+  else if( yyTracePrompt==0 ) yyTraceFILE = 0;
+}
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing shifts, the names of all terminals and nonterminals
+** are required.  The following table supplies these names */
+static const char *const yyTokenName[] = { 
+  "$",             "LINE_CONTINUATION",  "LINE_PLAIN",    "LINE_INDENTED_TAB",
+  "LINE_INDENTED_SPACE",  "LINE_ATX_1",    "LINE_ATX_2",    "LINE_ATX_3",  
+  "LINE_ATX_4",    "LINE_ATX_5",    "LINE_ATX_6",    "LINE_HR",     
+  "LINE_EMPTY",    "LINE_BLOCKQUOTE",  "LINE_LIST_BULLETED",  "LINE_LIST_ENUMERATED",
+  "LINE_TABLE",    "LINE_DEF_CITATION",  "LINE_DEF_FOOTNOTE",  "LINE_DEF_LINK",
+  "LINE_HTML",     "LINE_FENCE_BACKTICK",  "LINE_FENCE_BACKTICK_START",  "error",       
+  "doc",           "blocks",        "block",         "para",        
+  "indented_code",  "empty",         "list_bulleted",  "list_enumerated",
+  "blockquote",    "table",         "def_citation",  "def_footnote",
+  "def_link",      "html_block",    "fenced_block",  "para_lines",  
+  "para_line",     "code_line",     "indented_line",  "quote_lines", 
+  "quote_line",    "item_bulleted",  "cont_blocks",   "item_enumerated",
+  "cont_block",    "html_block_lines",  "html_block_line",  "fenced_lines",
+  "fenced_line", 
+};
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing reduce actions, the names of all rules are required.
+*/
+static const char *const yyRuleName[] = {
+ /*   0 */ "doc ::= blocks",
+ /*   1 */ "blocks ::= blocks block",
+ /*   2 */ "blocks ::= block",
+ /*   3 */ "block ::= para",
+ /*   4 */ "block ::= indented_code",
+ /*   5 */ "block ::= LINE_ATX_1",
+ /*   6 */ "block ::= LINE_ATX_2",
+ /*   7 */ "block ::= LINE_ATX_3",
+ /*   8 */ "block ::= LINE_ATX_4",
+ /*   9 */ "block ::= LINE_ATX_5",
+ /*  10 */ "block ::= LINE_ATX_6",
+ /*  11 */ "block ::= empty",
+ /*  12 */ "block ::= list_bulleted",
+ /*  13 */ "block ::= list_enumerated",
+ /*  14 */ "block ::= blockquote",
+ /*  15 */ "block ::= table",
+ /*  16 */ "block ::= LINE_HR",
+ /*  17 */ "block ::= def_citation",
+ /*  18 */ "block ::= def_footnote",
+ /*  19 */ "block ::= def_link",
+ /*  20 */ "block ::= html_block",
+ /*  21 */ "block ::= fenced_block",
+ /*  22 */ "para ::= LINE_PLAIN para_lines",
+ /*  23 */ "para_lines ::= para_lines para_line",
+ /*  24 */ "indented_code ::= indented_code code_line",
+ /*  25 */ "empty ::= empty LINE_EMPTY",
+ /*  26 */ "blockquote ::= LINE_BLOCKQUOTE quote_lines",
+ /*  27 */ "quote_lines ::= quote_lines quote_line",
+ /*  28 */ "list_bulleted ::= list_bulleted item_bulleted",
+ /*  29 */ "item_bulleted ::= LINE_LIST_BULLETED para_lines cont_blocks",
+ /*  30 */ "item_bulleted ::= LINE_LIST_BULLETED para_lines",
+ /*  31 */ "item_bulleted ::= LINE_LIST_BULLETED cont_blocks",
+ /*  32 */ "item_bulleted ::= LINE_LIST_BULLETED",
+ /*  33 */ "list_enumerated ::= list_enumerated item_enumerated",
+ /*  34 */ "item_enumerated ::= LINE_LIST_ENUMERATED para_lines cont_blocks",
+ /*  35 */ "item_enumerated ::= LINE_LIST_ENUMERATED para_lines",
+ /*  36 */ "item_enumerated ::= LINE_LIST_ENUMERATED cont_blocks",
+ /*  37 */ "item_enumerated ::= LINE_LIST_ENUMERATED",
+ /*  38 */ "cont_blocks ::= cont_blocks cont_block",
+ /*  39 */ "cont_block ::= empty indented_line para_lines",
+ /*  40 */ "cont_block ::= empty indented_line",
+ /*  41 */ "table ::= table LINE_TABLE",
+ /*  42 */ "def_citation ::= LINE_DEF_CITATION para_lines cont_blocks",
+ /*  43 */ "def_citation ::= LINE_DEF_CITATION para_lines",
+ /*  44 */ "def_citation ::= LINE_DEF_CITATION cont_blocks",
+ /*  45 */ "def_footnote ::= LINE_DEF_FOOTNOTE para_lines cont_blocks",
+ /*  46 */ "def_footnote ::= LINE_DEF_FOOTNOTE para_lines",
+ /*  47 */ "def_footnote ::= LINE_DEF_FOOTNOTE cont_blocks",
+ /*  48 */ "def_link ::= LINE_DEF_LINK para_lines",
+ /*  49 */ "html_block ::= LINE_HTML html_block_lines",
+ /*  50 */ "html_block_lines ::= html_block_lines html_block_line",
+ /*  51 */ "fenced_block ::= LINE_FENCE_BACKTICK fenced_lines LINE_FENCE_BACKTICK",
+ /*  52 */ "fenced_block ::= LINE_FENCE_BACKTICK fenced_lines",
+ /*  53 */ "fenced_block ::= LINE_FENCE_BACKTICK_START fenced_lines LINE_FENCE_BACKTICK",
+ /*  54 */ "fenced_block ::= LINE_FENCE_BACKTICK_START fenced_lines",
+ /*  55 */ "fenced_lines ::= fenced_lines fenced_line",
+ /*  56 */ "para ::= LINE_PLAIN",
+ /*  57 */ "para_lines ::= para_line",
+ /*  58 */ "para_line ::= LINE_CONTINUATION",
+ /*  59 */ "indented_code ::= LINE_INDENTED_TAB",
+ /*  60 */ "indented_code ::= LINE_INDENTED_SPACE",
+ /*  61 */ "code_line ::= indented_line",
+ /*  62 */ "code_line ::= LINE_EMPTY",
+ /*  63 */ "indented_line ::= LINE_INDENTED_TAB",
+ /*  64 */ "indented_line ::= LINE_INDENTED_SPACE",
+ /*  65 */ "empty ::= LINE_EMPTY",
+ /*  66 */ "blockquote ::= LINE_BLOCKQUOTE",
+ /*  67 */ "quote_lines ::= quote_line",
+ /*  68 */ "quote_line ::= LINE_BLOCKQUOTE",
+ /*  69 */ "quote_line ::= LINE_CONTINUATION",
+ /*  70 */ "list_bulleted ::= item_bulleted",
+ /*  71 */ "list_enumerated ::= item_enumerated",
+ /*  72 */ "cont_blocks ::= cont_block",
+ /*  73 */ "cont_block ::= empty",
+ /*  74 */ "table ::= LINE_TABLE",
+ /*  75 */ "def_citation ::= LINE_DEF_CITATION",
+ /*  76 */ "def_footnote ::= LINE_DEF_FOOTNOTE",
+ /*  77 */ "def_link ::= LINE_DEF_LINK",
+ /*  78 */ "html_block ::= LINE_HTML",
+ /*  79 */ "html_block_lines ::= html_block_line",
+ /*  80 */ "html_block_line ::= LINE_CONTINUATION",
+ /*  81 */ "html_block_line ::= LINE_HTML",
+ /*  82 */ "fenced_lines ::= fenced_line",
+ /*  83 */ "fenced_line ::= LINE_CONTINUATION",
+ /*  84 */ "fenced_line ::= LINE_EMPTY",
+};
+#endif /* NDEBUG */
+
+
+#if YYSTACKDEPTH<=0
+/*
+** Try to increase the size of the parser stack.  Return the number
+** of errors.  Return 0 on success.
+*/
+static int yyGrowStack(yyParser *p){
+  int newSize;
+  int idx;
+  yyStackEntry *pNew;
+
+  newSize = p->yystksz*2 + 100;
+  idx = p->yytos ? (int)(p->yytos - p->yystack) : 0;
+  if( p->yystack==&p->yystk0 ){
+    pNew = malloc(newSize*sizeof(pNew[0]));
+    if( pNew ) pNew[0] = p->yystk0;
+  }else{
+    pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+  }
+  if( pNew ){
+    p->yystack = pNew;
+    p->yytos = &p->yystack[idx];
+#ifndef NDEBUG
+    if( yyTraceFILE ){
+      fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
+              yyTracePrompt, p->yystksz, newSize);
+    }
+#endif
+    p->yystksz = newSize;
+  }
+  return pNew==0; 
+}
+#endif
+
+/* Datatype of the argument to the memory allocated passed as the
+** second argument to ParseAlloc() below.  This can be changed by
+** putting an appropriate #define in the %include section of the input
+** grammar.
+*/
+#ifndef YYMALLOCARGTYPE
+# define YYMALLOCARGTYPE size_t
+#endif
+
+/* 
+** This function allocates a new parser.
+** The only argument is a pointer to a function which works like
+** malloc.
+**
+** Inputs:
+** A pointer to the function used to allocate memory.
+**
+** Outputs:
+** A pointer to a parser.  This pointer is used in subsequent calls
+** to Parse and ParseFree.
+*/
+void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){
+  yyParser *pParser;
+  pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
+  if( pParser ){
+#ifdef YYTRACKMAXSTACKDEPTH
+    pParser->yyhwm = 0;
+#endif
+#if YYSTACKDEPTH<=0
+    pParser->yytos = NULL;
+    pParser->yystack = NULL;
+    pParser->yystksz = 0;
+    if( yyGrowStack(pParser) ){
+      pParser->yystack = &pParser->yystk0;
+      pParser->yystksz = 1;
+    }
+#endif
+#ifndef YYNOERRORRECOVERY
+    pParser->yyerrcnt = -1;
+#endif
+    pParser->yytos = pParser->yystack;
+    pParser->yystack[0].stateno = 0;
+    pParser->yystack[0].major = 0;
+  }
+  return pParser;
+}
+
+/* The following function deletes the "minor type" or semantic value
+** associated with a symbol.  The symbol can be either a terminal
+** or nonterminal. "yymajor" is the symbol code, and "yypminor" is
+** a pointer to the value to be deleted.  The code used to do the 
+** deletions is derived from the %destructor and/or %token_destructor
+** directives of the input grammar.
+*/
+static void yy_destructor(
+  yyParser *yypParser,    /* The parser */
+  YYCODETYPE yymajor,     /* Type code for object to destroy */
+  YYMINORTYPE *yypminor   /* The object to be destroyed */
+){
+  ParseARG_FETCH;
+  switch( yymajor ){
+    /* Here is inserted the actions which take place when a
+    ** terminal or non-terminal is destroyed.  This can happen
+    ** when the symbol is popped from the stack during a
+    ** reduce or during error processing or when a parser is 
+    ** being destroyed before it is finished parsing.
+    **
+    ** Note: during a reduce, the only symbols destroyed are those
+    ** which appear on the RHS of the rule, but which are *not* used
+    ** inside the C code.
+    */
+/********* Begin destructor definitions ***************************************/
+/********* End destructor definitions *****************************************/
+    default:  break;   /* If no destructor action specified: do nothing */
+  }
+}
+
+/*
+** Pop the parser's stack once.
+**
+** If there is a destructor routine associated with the token which
+** is popped from the stack, then call it.
+*/
+static void yy_pop_parser_stack(yyParser *pParser){
+  yyStackEntry *yytos;
+  assert( pParser->yytos!=0 );
+  assert( pParser->yytos > pParser->yystack );
+  yytos = pParser->yytos--;
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sPopping %s\n",
+      yyTracePrompt,
+      yyTokenName[yytos->major]);
+  }
+#endif
+  yy_destructor(pParser, yytos->major, &yytos->minor);
+}
+
+/* 
+** Deallocate and destroy a parser.  Destructors are called for
+** all stack elements before shutting the parser down.
+**
+** If the YYPARSEFREENEVERNULL macro exists (for example because it
+** is defined in a %include section of the input grammar) then it is
+** assumed that the input pointer is never NULL.
+*/
+void ParseFree(
+  void *p,                    /* The parser to be deleted */
+  void (*freeProc)(void*)     /* Function used to reclaim memory */
+){
+  yyParser *pParser = (yyParser*)p;
+#ifndef YYPARSEFREENEVERNULL
+  if( pParser==0 ) return;
+#endif
+  while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
+#if YYSTACKDEPTH<=0
+  if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
+#endif
+  (*freeProc)((void*)pParser);
+}
+
+/*
+** Return the peak depth of the stack for a parser.
+*/
+#ifdef YYTRACKMAXSTACKDEPTH
+int ParseStackPeak(void *p){
+  yyParser *pParser = (yyParser*)p;
+  return pParser->yyhwm;
+}
+#endif
+
+/*
+** Find the appropriate action for a parser given the terminal
+** look-ahead token iLookAhead.
+*/
+static unsigned int yy_find_shift_action(
+  yyParser *pParser,        /* The parser */
+  YYCODETYPE iLookAhead     /* The look-ahead token */
+){
+  int i;
+  int stateno = pParser->yytos->stateno;
+  if( stateno>=YY_MIN_REDUCE ) return stateno;
+  assert( stateno <= YY_SHIFT_COUNT );
+  do{
+    i = yy_shift_ofst[stateno];
+    assert( iLookAhead!=YYNOCODE );
+    i += iLookAhead;
+    if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+#ifdef YYFALLBACK
+      YYCODETYPE iFallback;            /* Fallback token */
+      if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+             && (iFallback = yyFallback[iLookAhead])!=0 ){
+#ifndef NDEBUG
+        if( yyTraceFILE ){
+          fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+             yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+        }
+#endif
+        assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
+        iLookAhead = iFallback;
+        continue;
+      }
+#endif
+#ifdef YYWILDCARD
+      {
+        int j = i - iLookAhead + YYWILDCARD;
+        if( 
+#if YY_SHIFT_MIN+YYWILDCARD<0
+          j>=0 &&
+#endif
+#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
+          j<YY_ACTTAB_COUNT &&
+#endif
+          yy_lookahead[j]==YYWILDCARD && iLookAhead>0
+        ){
+#ifndef NDEBUG
+          if( yyTraceFILE ){
+            fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
+               yyTracePrompt, yyTokenName[iLookAhead],
+               yyTokenName[YYWILDCARD]);
+          }
+#endif /* NDEBUG */
+          return yy_action[j];
+        }
+      }
+#endif /* YYWILDCARD */
+      return yy_default[stateno];
+    }else{
+      return yy_action[i];
+    }
+  }while(1);
+}
+
+/*
+** Find the appropriate action for a parser given the non-terminal
+** look-ahead token iLookAhead.
+*/
+static int yy_find_reduce_action(
+  int stateno,              /* Current state number */
+  YYCODETYPE iLookAhead     /* The look-ahead token */
+){
+  int i;
+#ifdef YYERRORSYMBOL
+  if( stateno>YY_REDUCE_COUNT ){
+    return yy_default[stateno];
+  }
+#else
+  assert( stateno<=YY_REDUCE_COUNT );
+#endif
+  i = yy_reduce_ofst[stateno];
+  assert( i!=YY_REDUCE_USE_DFLT );
+  assert( iLookAhead!=YYNOCODE );
+  i += iLookAhead;
+#ifdef YYERRORSYMBOL
+  if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+    return yy_default[stateno];
+  }
+#else
+  assert( i>=0 && i<YY_ACTTAB_COUNT );
+  assert( yy_lookahead[i]==iLookAhead );
+#endif
+  return yy_action[i];
+}
+
+/*
+** The following routine is called if the stack overflows.
+*/
+static void yyStackOverflow(yyParser *yypParser){
+   ParseARG_FETCH;
+   yypParser->yytos--;
+#ifndef NDEBUG
+   if( yyTraceFILE ){
+     fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+   }
+#endif
+   while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
+   /* Here code is inserted which will execute if the parser
+   ** stack every overflows */
+/******** Begin %stack_overflow code ******************************************/
+/******** End %stack_overflow code ********************************************/
+   ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
+}
+
+/*
+** Print tracing information for a SHIFT action
+*/
+#ifndef NDEBUG
+static void yyTraceShift(yyParser *yypParser, int yyNewState){
+  if( yyTraceFILE ){
+    if( yyNewState<YYNSTATE ){
+      fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n",
+         yyTracePrompt,yyTokenName[yypParser->yytos->major],
+         yyNewState);
+    }else{
+      fprintf(yyTraceFILE,"%sShift '%s'\n",
+         yyTracePrompt,yyTokenName[yypParser->yytos->major]);
+    }
+  }
+}
+#else
+# define yyTraceShift(X,Y)
+#endif
+
+/*
+** Perform a shift action.
+*/
+static void yy_shift(
+  yyParser *yypParser,          /* The parser to be shifted */
+  int yyNewState,               /* The new state to shift in */
+  int yyMajor,                  /* The major token to shift in */
+  ParseTOKENTYPE yyMinor        /* The minor token to shift in */
+){
+  yyStackEntry *yytos;
+  yypParser->yytos++;
+#ifdef YYTRACKMAXSTACKDEPTH
+  if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
+    yypParser->yyhwm++;
+    assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
+  }
+#endif
+#if YYSTACKDEPTH>0 
+  if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){
+    yyStackOverflow(yypParser);
+    return;
+  }
+#else
+  if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){
+    if( yyGrowStack(yypParser) ){
+      yyStackOverflow(yypParser);
+      return;
+    }
+  }
+#endif
+  if( yyNewState > YY_MAX_SHIFT ){
+    yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
+  }
+  yytos = yypParser->yytos;
+  yytos->stateno = (YYACTIONTYPE)yyNewState;
+  yytos->major = (YYCODETYPE)yyMajor;
+  yytos->minor.yy0 = yyMinor;
+  yyTraceShift(yypParser, yyNewState);
+}
+
+/* The following table contains information about every rule that
+** is used during the reduce.
+*/
+static const struct {
+  YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
+  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
+} yyRuleInfo[] = {
+  { 24, 1 },
+  { 25, 2 },
+  { 25, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 26, 1 },
+  { 27, 2 },
+  { 39, 2 },
+  { 28, 2 },
+  { 29, 2 },
+  { 32, 2 },
+  { 43, 2 },
+  { 30, 2 },
+  { 45, 3 },
+  { 45, 2 },
+  { 45, 2 },
+  { 45, 1 },
+  { 31, 2 },
+  { 47, 3 },
+  { 47, 2 },
+  { 47, 2 },
+  { 47, 1 },
+  { 46, 2 },
+  { 48, 3 },
+  { 48, 2 },
+  { 33, 2 },
+  { 34, 3 },
+  { 34, 2 },
+  { 34, 2 },
+  { 35, 3 },
+  { 35, 2 },
+  { 35, 2 },
+  { 36, 2 },
+  { 37, 2 },
+  { 49, 2 },
+  { 38, 3 },
+  { 38, 2 },
+  { 38, 3 },
+  { 38, 2 },
+  { 51, 2 },
+  { 27, 1 },
+  { 39, 1 },
+  { 40, 1 },
+  { 28, 1 },
+  { 28, 1 },
+  { 41, 1 },
+  { 41, 1 },
+  { 42, 1 },
+  { 42, 1 },
+  { 29, 1 },
+  { 32, 1 },
+  { 43, 1 },
+  { 44, 1 },
+  { 44, 1 },
+  { 30, 1 },
+  { 31, 1 },
+  { 46, 1 },
+  { 48, 1 },
+  { 33, 1 },
+  { 34, 1 },
+  { 35, 1 },
+  { 36, 1 },
+  { 37, 1 },
+  { 49, 1 },
+  { 50, 1 },
+  { 50, 1 },
+  { 51, 1 },
+  { 52, 1 },
+  { 52, 1 },
+};
+
+static void yy_accept(yyParser*);  /* Forward Declaration */
+
+/*
+** Perform a reduce action and the shift that must immediately
+** follow the reduce.
+*/
+static void yy_reduce(
+  yyParser *yypParser,         /* The parser */
+  unsigned int yyruleno        /* Number of the rule by which to reduce */
+){
+  int yygoto;                     /* The next state */
+  int yyact;                      /* The next action */
+  yyStackEntry *yymsp;            /* The top of the parser's stack */
+  int yysize;                     /* Amount to pop the stack */
+  ParseARG_FETCH;
+  yymsp = yypParser->yytos;
+#ifndef NDEBUG
+  if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
+    yysize = yyRuleInfo[yyruleno].nrhs;
+    fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt,
+      yyRuleName[yyruleno], yymsp[-yysize].stateno);
+  }
+#endif /* NDEBUG */
+
+  /* Check that the stack is large enough to grow by a single entry
+  ** if the RHS of the rule is empty.  This ensures that there is room
+  ** enough on the stack to push the LHS value */
+  if( yyRuleInfo[yyruleno].nrhs==0 ){
+#ifdef YYTRACKMAXSTACKDEPTH
+    if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
+      yypParser->yyhwm++;
+      assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack));
+    }
+#endif
+#if YYSTACKDEPTH>0 
+    if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){
+      yyStackOverflow(yypParser);
+      return;
+    }
+#else
+    if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
+      if( yyGrowStack(yypParser) ){
+        yyStackOverflow(yypParser);
+        return;
+      }
+      yymsp = yypParser->yytos;
+    }
+#endif
+  }
+
+  switch( yyruleno ){
+  /* Beginning here are the reduction cases.  A typical example
+  ** follows:
+  **   case 0:
+  **  #line <lineno> <grammarfile>
+  **     { ... }           // User supplied code
+  **  #line <lineno> <thisfile>
+  **     break;
+  */
+/********** Begin reduce actions **********************************************/
+        YYMINORTYPE yylhsminor;
+      case 0: /* doc ::= blocks */
+{ engine->root = yymsp[0].minor.yy0; }
+        break;
+      case 1: /* blocks ::= blocks block */
+{
+               strip_line_tokens_from_block(yymsp[0].minor.yy0);
+               if (yymsp[-1].minor.yy0 == NULL) { yymsp[-1].minor.yy0 = yymsp[0].minor.yy0; yymsp[0].minor.yy0 = NULL;}
+               yylhsminor.yy0 = yymsp[-1].minor.yy0;
+               token_chain_append(yylhsminor.yy0, yymsp[0].minor.yy0);
+               #ifndef NDEBUG
+               fprintf(stderr, "Next block %d\n", yylhsminor.yy0->tail->type);
+               #endif
+       }
+  yymsp[-1].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 2: /* blocks ::= block */
+{
+               strip_line_tokens_from_block(yymsp[0].minor.yy0);
+               #ifndef NDEBUG
+               fprintf(stderr, "First block %d\n", yymsp[0].minor.yy0->type);
+               #endif
+               yylhsminor.yy0 = yymsp[0].minor.yy0;
+       }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 3: /* block ::= para */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_PARA); is_para_html(engine, yylhsminor.yy0); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 4: /* block ::= indented_code */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_CODE_INDENTED); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 5: /* block ::= LINE_ATX_1 */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_H1); if (!(engine->extensions & EXT_NO_LABELS)) stack_push(engine->header_stack, yylhsminor.yy0); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 6: /* block ::= LINE_ATX_2 */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_H2); if (!(engine->extensions & EXT_NO_LABELS)) stack_push(engine->header_stack, yylhsminor.yy0); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 7: /* block ::= LINE_ATX_3 */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_H3); if (!(engine->extensions & EXT_NO_LABELS)) stack_push(engine->header_stack, yylhsminor.yy0); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 8: /* block ::= LINE_ATX_4 */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_H4); if (!(engine->extensions & EXT_NO_LABELS)) stack_push(engine->header_stack, yylhsminor.yy0); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 9: /* block ::= LINE_ATX_5 */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_H5); if (!(engine->extensions & EXT_NO_LABELS)) stack_push(engine->header_stack, yylhsminor.yy0); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 10: /* block ::= LINE_ATX_6 */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_H6); if (!(engine->extensions & EXT_NO_LABELS)) stack_push(engine->header_stack, yylhsminor.yy0); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 11: /* block ::= empty */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_EMPTY); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 12: /* block ::= list_bulleted */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_LIST_BULLETED); is_list_loose(yylhsminor.yy0); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 13: /* block ::= list_enumerated */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_LIST_ENUMERATED); is_list_loose(yylhsminor.yy0); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 14: /* block ::= blockquote */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_BLOCKQUOTE); recursive_parse_blockquote(engine, yylhsminor.yy0); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 15: /* block ::= table */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_TABLE); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 16: /* block ::= LINE_HR */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_HR); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 17: /* block ::= def_citation */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_DEF_CITATION); stack_push(engine->definition_stack, yylhsminor.yy0); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 18: /* block ::= def_footnote */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_DEF_FOOTNOTE); stack_push(engine->definition_stack, yylhsminor.yy0); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 19: /* block ::= def_link */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_DEF_LINK); stack_push(engine->definition_stack, yylhsminor.yy0); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 20: /* block ::= html_block */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_HTML); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 21: /* block ::= fenced_block */
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_CODE_FENCED); yymsp[0].minor.yy0->child->type = CODE_FENCE; }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 22: /* para ::= LINE_PLAIN para_lines */
+      case 23: /* para_lines ::= para_lines para_line */ yytestcase(yyruleno==23);
+      case 24: /* indented_code ::= indented_code code_line */ yytestcase(yyruleno==24);
+      case 25: /* empty ::= empty LINE_EMPTY */ yytestcase(yyruleno==25);
+      case 26: /* blockquote ::= LINE_BLOCKQUOTE quote_lines */ yytestcase(yyruleno==26);
+      case 27: /* quote_lines ::= quote_lines quote_line */ yytestcase(yyruleno==27);
+      case 28: /* list_bulleted ::= list_bulleted item_bulleted */ yytestcase(yyruleno==28);
+      case 33: /* list_enumerated ::= list_enumerated item_enumerated */ yytestcase(yyruleno==33);
+      case 38: /* cont_blocks ::= cont_blocks cont_block */ yytestcase(yyruleno==38);
+      case 41: /* table ::= table LINE_TABLE */ yytestcase(yyruleno==41);
+      case 43: /* def_citation ::= LINE_DEF_CITATION para_lines */ yytestcase(yyruleno==43);
+      case 44: /* def_citation ::= LINE_DEF_CITATION cont_blocks */ yytestcase(yyruleno==44);
+      case 46: /* def_footnote ::= LINE_DEF_FOOTNOTE para_lines */ yytestcase(yyruleno==46);
+      case 47: /* def_footnote ::= LINE_DEF_FOOTNOTE cont_blocks */ yytestcase(yyruleno==47);
+      case 48: /* def_link ::= LINE_DEF_LINK para_lines */ yytestcase(yyruleno==48);
+      case 49: /* html_block ::= LINE_HTML html_block_lines */ yytestcase(yyruleno==49);
+      case 50: /* html_block_lines ::= html_block_lines html_block_line */ yytestcase(yyruleno==50);
+      case 52: /* fenced_block ::= LINE_FENCE_BACKTICK fenced_lines */ yytestcase(yyruleno==52);
+      case 54: /* fenced_block ::= LINE_FENCE_BACKTICK_START fenced_lines */ yytestcase(yyruleno==54);
+      case 55: /* fenced_lines ::= fenced_lines fenced_line */ yytestcase(yyruleno==55);
+{ yylhsminor.yy0 = yymsp[-1].minor.yy0; token_chain_append(yymsp[-1].minor.yy0, yymsp[0].minor.yy0); }
+  yymsp[-1].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 29: /* item_bulleted ::= LINE_LIST_BULLETED para_lines cont_blocks */
+      case 34: /* item_enumerated ::= LINE_LIST_ENUMERATED para_lines cont_blocks */ yytestcase(yyruleno==34);
+{ token_chain_append(yymsp[-2].minor.yy0, yymsp[-1].minor.yy0); token_chain_append(yymsp[-2].minor.yy0, yymsp[0].minor.yy0); yylhsminor.yy0 = token_new_parent(yymsp[-2].minor.yy0, BLOCK_LIST_ITEM); recursive_parse_list_item(engine, yylhsminor.yy0); }
+  yymsp[-2].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 30: /* item_bulleted ::= LINE_LIST_BULLETED para_lines */
+      case 35: /* item_enumerated ::= LINE_LIST_ENUMERATED para_lines */ yytestcase(yyruleno==35);
+{ token_chain_append(yymsp[-1].minor.yy0, yymsp[0].minor.yy0); yylhsminor.yy0 = token_new_parent(yymsp[-1].minor.yy0, BLOCK_LIST_ITEM_TIGHT); recursive_parse_list_item(engine, yylhsminor.yy0); }
+  yymsp[-1].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 31: /* item_bulleted ::= LINE_LIST_BULLETED cont_blocks */
+{ token_chain_append(yymsp[-1].minor.yy0, yymsp[0].minor.yy0); yylhsminor.yy0 = token_new_parent(yymsp[-1].minor.yy0, BLOCK_LIST_ITEM); if (yymsp[0].minor.yy0) {recursive_parse_list_item(engine, yylhsminor.yy0);} }
+  yymsp[-1].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 32: /* item_bulleted ::= LINE_LIST_BULLETED */
+      case 37: /* item_enumerated ::= LINE_LIST_ENUMERATED */ yytestcase(yyruleno==37);
+{ yylhsminor.yy0 = token_new_parent(yymsp[0].minor.yy0, BLOCK_LIST_ITEM_TIGHT); }
+  yymsp[0].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 36: /* item_enumerated ::= LINE_LIST_ENUMERATED cont_blocks */
+{ token_chain_append(yymsp[-1].minor.yy0, yymsp[0].minor.yy0); yylhsminor.yy0 = token_new_parent(yymsp[-1].minor.yy0, BLOCK_LIST_ITEM); recursive_parse_list_item(engine, yylhsminor.yy0); }
+  yymsp[-1].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 39: /* cont_block ::= empty indented_line para_lines */
+{ yylhsminor.yy0 = yymsp[-2].minor.yy0; token_chain_append(yymsp[-2].minor.yy0, yymsp[-1].minor.yy0); token_chain_append(yymsp[-2].minor.yy0, yymsp[0].minor.yy0); yymsp[-1].minor.yy0->type = LINE_CONTINUATION; }
+  yymsp[-2].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 40: /* cont_block ::= empty indented_line */
+{ yylhsminor.yy0 = yymsp[-1].minor.yy0; token_chain_append(yymsp[-1].minor.yy0, yymsp[0].minor.yy0); yymsp[0].minor.yy0->type = LINE_CONTINUATION; }
+  yymsp[-1].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 42: /* def_citation ::= LINE_DEF_CITATION para_lines cont_blocks */
+      case 45: /* def_footnote ::= LINE_DEF_FOOTNOTE para_lines cont_blocks */ yytestcase(yyruleno==45);
+{ yylhsminor.yy0 = yymsp[-2].minor.yy0; token_chain_append(yymsp[-2].minor.yy0, yymsp[-1].minor.yy0); token_chain_append(yymsp[-2].minor.yy0, yymsp[0].minor.yy0); }
+  yymsp[-2].minor.yy0 = yylhsminor.yy0;
+        break;
+      case 51: /* fenced_block ::= LINE_FENCE_BACKTICK fenced_lines LINE_FENCE_BACKTICK */
+      case 53: /* fenced_block ::= LINE_FENCE_BACKTICK_START fenced_lines LINE_FENCE_BACKTICK */ yytestcase(yyruleno==53);
+{ yylhsminor.yy0 = yymsp[-2].minor.yy0; token_chain_append(yymsp[-2].minor.yy0, yymsp[-1].minor.yy0); token_chain_append(yymsp[-2].minor.yy0, yymsp[0].minor.yy0); yymsp[0].minor.yy0->child->type = CODE_FENCE; }
+  yymsp[-2].minor.yy0 = yylhsminor.yy0;
+        break;
+      default:
+      /* (56) para ::= LINE_PLAIN */ yytestcase(yyruleno==56);
+      /* (57) para_lines ::= para_line (OPTIMIZED OUT) */ assert(yyruleno!=57);
+      /* (58) para_line ::= LINE_CONTINUATION */ yytestcase(yyruleno==58);
+      /* (59) indented_code ::= LINE_INDENTED_TAB */ yytestcase(yyruleno==59);
+      /* (60) indented_code ::= LINE_INDENTED_SPACE */ yytestcase(yyruleno==60);
+      /* (61) code_line ::= indented_line (OPTIMIZED OUT) */ assert(yyruleno!=61);
+      /* (62) code_line ::= LINE_EMPTY */ yytestcase(yyruleno==62);
+      /* (63) indented_line ::= LINE_INDENTED_TAB */ yytestcase(yyruleno==63);
+      /* (64) indented_line ::= LINE_INDENTED_SPACE */ yytestcase(yyruleno==64);
+      /* (65) empty ::= LINE_EMPTY */ yytestcase(yyruleno==65);
+      /* (66) blockquote ::= LINE_BLOCKQUOTE */ yytestcase(yyruleno==66);
+      /* (67) quote_lines ::= quote_line (OPTIMIZED OUT) */ assert(yyruleno!=67);
+      /* (68) quote_line ::= LINE_BLOCKQUOTE */ yytestcase(yyruleno==68);
+      /* (69) quote_line ::= LINE_CONTINUATION */ yytestcase(yyruleno==69);
+      /* (70) list_bulleted ::= item_bulleted (OPTIMIZED OUT) */ assert(yyruleno!=70);
+      /* (71) list_enumerated ::= item_enumerated (OPTIMIZED OUT) */ assert(yyruleno!=71);
+      /* (72) cont_blocks ::= cont_block (OPTIMIZED OUT) */ assert(yyruleno!=72);
+      /* (73) cont_block ::= empty */ yytestcase(yyruleno==73);
+      /* (74) table ::= LINE_TABLE */ yytestcase(yyruleno==74);
+      /* (75) def_citation ::= LINE_DEF_CITATION */ yytestcase(yyruleno==75);
+      /* (76) def_footnote ::= LINE_DEF_FOOTNOTE */ yytestcase(yyruleno==76);
+      /* (77) def_link ::= LINE_DEF_LINK */ yytestcase(yyruleno==77);
+      /* (78) html_block ::= LINE_HTML */ yytestcase(yyruleno==78);
+      /* (79) html_block_lines ::= html_block_line (OPTIMIZED OUT) */ assert(yyruleno!=79);
+      /* (80) html_block_line ::= LINE_CONTINUATION */ yytestcase(yyruleno==80);
+      /* (81) html_block_line ::= LINE_HTML */ yytestcase(yyruleno==81);
+      /* (82) fenced_lines ::= fenced_line (OPTIMIZED OUT) */ assert(yyruleno!=82);
+      /* (83) fenced_line ::= LINE_CONTINUATION */ yytestcase(yyruleno==83);
+      /* (84) fenced_line ::= LINE_EMPTY */ yytestcase(yyruleno==84);
+        break;
+/********** End reduce actions ************************************************/
+  };
+  assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
+  yygoto = yyRuleInfo[yyruleno].lhs;
+  yysize = yyRuleInfo[yyruleno].nrhs;
+  yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
+  if( yyact <= YY_MAX_SHIFTREDUCE ){
+    if( yyact>YY_MAX_SHIFT ){
+      yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
+    }
+    yymsp -= yysize-1;
+    yypParser->yytos = yymsp;
+    yymsp->stateno = (YYACTIONTYPE)yyact;
+    yymsp->major = (YYCODETYPE)yygoto;
+    yyTraceShift(yypParser, yyact);
+  }else{
+    assert( yyact == YY_ACCEPT_ACTION );
+    yypParser->yytos -= yysize;
+    yy_accept(yypParser);
+  }
+}
+
+/*
+** The following code executes when the parse fails
+*/
+#ifndef YYNOERRORRECOVERY
+static void yy_parse_failed(
+  yyParser *yypParser           /* The parser */
+){
+  ParseARG_FETCH;
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
+  }
+#endif
+  while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
+  /* Here code is inserted which will be executed whenever the
+  ** parser fails */
+/************ Begin %parse_failure code ***************************************/
+
+       fprintf(stderr, "Parser failed to successfully parse.\n");
+/************ End %parse_failure code *****************************************/
+  ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+#endif /* YYNOERRORRECOVERY */
+
+/*
+** The following code executes when a syntax error first occurs.
+*/
+static void yy_syntax_error(
+  yyParser *yypParser,           /* The parser */
+  int yymajor,                   /* The major type of the error token */
+  ParseTOKENTYPE yyminor         /* The minor type of the error token */
+){
+  ParseARG_FETCH;
+#define TOKEN yyminor
+/************ Begin %syntax_error code ****************************************/
+
+#ifndef NDEBUG
+       fprintf(stderr,"Parser syntax error.\n");
+       int n = sizeof(yyTokenName) / sizeof(yyTokenName[0]);
+       for (int i = 0; i < n; ++i) {
+               int a = yy_find_shift_action(yypParser, (YYCODETYPE)i);
+               if (a < YYNSTATE + YYNRULE) {
+                       fprintf(stderr,"expected token: %s\n", yyTokenName[i]);
+               }
+       }
+#endif
+/************ End %syntax_error code ******************************************/
+  ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following is executed when the parser accepts
+*/
+static void yy_accept(
+  yyParser *yypParser           /* The parser */
+){
+  ParseARG_FETCH;
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
+  }
+#endif
+#ifndef YYNOERRORRECOVERY
+  yypParser->yyerrcnt = -1;
+#endif
+  assert( yypParser->yytos==yypParser->yystack );
+  /* Here code is inserted which will be executed whenever the
+  ** parser accepts */
+/*********** Begin %parse_accept code *****************************************/
+/*********** End %parse_accept code *******************************************/
+  ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/* The main parser program.
+** The first argument is a pointer to a structure obtained from
+** "ParseAlloc" which describes the current state of the parser.
+** The second argument is the major token number.  The third is
+** the minor token.  The fourth optional argument is whatever the
+** user wants (and specified in the grammar) and is available for
+** use by the action routines.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser (an opaque structure.)
+** <li> The major token number.
+** <li> The minor token number.
+** <li> An option argument of a grammar-specified type.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void Parse(
+  void *yyp,                   /* The parser */
+  int yymajor,                 /* The major token code number */
+  ParseTOKENTYPE yyminor       /* The value for the token */
+  ParseARG_PDECL               /* Optional %extra_argument parameter */
+){
+  YYMINORTYPE yyminorunion;
+  unsigned int yyact;   /* The parser action. */
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+  int yyendofinput;     /* True if we are at the end of input */
+#endif
+#ifdef YYERRORSYMBOL
+  int yyerrorhit = 0;   /* True if yymajor has invoked an error */
+#endif
+  yyParser *yypParser;  /* The parser */
+
+  yypParser = (yyParser*)yyp;
+  assert( yypParser->yytos!=0 );
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+  yyendofinput = (yymajor==0);
+#endif
+  ParseARG_STORE;
+
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]);
+  }
+#endif
+
+  do{
+    yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
+    if( yyact <= YY_MAX_SHIFTREDUCE ){
+      yy_shift(yypParser,yyact,yymajor,yyminor);
+#ifndef YYNOERRORRECOVERY
+      yypParser->yyerrcnt--;
+#endif
+      yymajor = YYNOCODE;
+    }else if( yyact <= YY_MAX_REDUCE ){
+      yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
+    }else{
+      assert( yyact == YY_ERROR_ACTION );
+      yyminorunion.yy0 = yyminor;
+#ifdef YYERRORSYMBOL
+      int yymx;
+#endif
+#ifndef NDEBUG
+      if( yyTraceFILE ){
+        fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
+      }
+#endif
+#ifdef YYERRORSYMBOL
+      /* A syntax error has occurred.
+      ** The response to an error depends upon whether or not the
+      ** grammar defines an error token "ERROR".  
+      **
+      ** This is what we do if the grammar does define ERROR:
+      **
+      **  * Call the %syntax_error function.
+      **
+      **  * Begin popping the stack until we enter a state where
+      **    it is legal to shift the error symbol, then shift
+      **    the error symbol.
+      **
+      **  * Set the error count to three.
+      **
+      **  * Begin accepting and shifting new tokens.  No new error
+      **    processing will occur until three tokens have been
+      **    shifted successfully.
+      **
+      */
+      if( yypParser->yyerrcnt<0 ){
+        yy_syntax_error(yypParser,yymajor,yyminor);
+      }
+      yymx = yypParser->yytos->major;
+      if( yymx==YYERRORSYMBOL || yyerrorhit ){
+#ifndef NDEBUG
+        if( yyTraceFILE ){
+          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
+             yyTracePrompt,yyTokenName[yymajor]);
+        }
+#endif
+        yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
+        yymajor = YYNOCODE;
+      }else{
+        while( yypParser->yytos >= yypParser->yystack
+            && yymx != YYERRORSYMBOL
+            && (yyact = yy_find_reduce_action(
+                        yypParser->yytos->stateno,
+                        YYERRORSYMBOL)) >= YY_MIN_REDUCE
+        ){
+          yy_pop_parser_stack(yypParser);
+        }
+        if( yypParser->yytos < yypParser->yystack || yymajor==0 ){
+          yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+          yy_parse_failed(yypParser);
+#ifndef YYNOERRORRECOVERY
+          yypParser->yyerrcnt = -1;
+#endif
+          yymajor = YYNOCODE;
+        }else if( yymx!=YYERRORSYMBOL ){
+          yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor);
+        }
+      }
+      yypParser->yyerrcnt = 3;
+      yyerrorhit = 1;
+#elif defined(YYNOERRORRECOVERY)
+      /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
+      ** do any kind of error recovery.  Instead, simply invoke the syntax
+      ** error routine and continue going as if nothing had happened.
+      **
+      ** Applications can set this macro (for example inside %include) if
+      ** they intend to abandon the parse upon the first syntax error seen.
+      */
+      yy_syntax_error(yypParser,yymajor, yyminor);
+      yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+      yymajor = YYNOCODE;
+      
+#else  /* YYERRORSYMBOL is not defined */
+      /* This is what we do if the grammar does not define ERROR:
+      **
+      **  * Report an error message, and throw away the input token.
+      **
+      **  * If the input token is $, then fail the parse.
+      **
+      ** As before, subsequent error messages are suppressed until
+      ** three input tokens have been successfully shifted.
+      */
+      if( yypParser->yyerrcnt<=0 ){
+        yy_syntax_error(yypParser,yymajor, yyminor);
+      }
+      yypParser->yyerrcnt = 3;
+      yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+      if( yyendofinput ){
+        yy_parse_failed(yypParser);
+#ifndef YYNOERRORRECOVERY
+        yypParser->yyerrcnt = -1;
+#endif
+      }
+      yymajor = YYNOCODE;
+#endif
+    }
+  }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack );
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    yyStackEntry *i;
+    char cDiv = '[';
+    fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt);
+    for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){
+      fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]);
+      cDiv = ' ';
+    }
+    fprintf(yyTraceFILE,"]\n");
+  }
+#endif
+  return;
+}
diff --git a/src/parser.h b/src/parser.h
new file mode 100644 (file)
index 0000000..06471ee
--- /dev/null
@@ -0,0 +1,22 @@
+#define LINE_CONTINUATION                1
+#define LINE_PLAIN                       2
+#define LINE_INDENTED_TAB                3
+#define LINE_INDENTED_SPACE              4
+#define LINE_ATX_1                       5
+#define LINE_ATX_2                       6
+#define LINE_ATX_3                       7
+#define LINE_ATX_4                       8
+#define LINE_ATX_5                       9
+#define LINE_ATX_6                      10
+#define LINE_HR                         11
+#define LINE_EMPTY                      12
+#define LINE_BLOCKQUOTE                 13
+#define LINE_LIST_BULLETED              14
+#define LINE_LIST_ENUMERATED            15
+#define LINE_TABLE                      16
+#define LINE_DEF_CITATION               17
+#define LINE_DEF_FOOTNOTE               18
+#define LINE_DEF_LINK                   19
+#define LINE_HTML                       20
+#define LINE_FENCE_BACKTICK             21
+#define LINE_FENCE_BACKTICK_START       22
diff --git a/src/parser.out b/src/parser.out
new file mode 100644 (file)
index 0000000..94a0f4d
--- /dev/null
@@ -0,0 +1,819 @@
+State 0:
+          doc ::= * blocks
+          blocks ::= * blocks block
+          blocks ::= * block
+          block ::= * para
+          block ::= * indented_code
+          block ::= * LINE_ATX_1
+          block ::= * LINE_ATX_2
+          block ::= * LINE_ATX_3
+          block ::= * LINE_ATX_4
+          block ::= * LINE_ATX_5
+          block ::= * LINE_ATX_6
+          block ::= * empty
+          block ::= * list_bulleted
+          block ::= * list_enumerated
+          block ::= * blockquote
+          block ::= * table
+          block ::= * LINE_HR
+          block ::= * def_citation
+          block ::= * def_footnote
+          block ::= * def_link
+          block ::= * html_block
+          block ::= * fenced_block
+          para ::= * LINE_PLAIN para_lines
+          para ::= * LINE_PLAIN
+          indented_code ::= * indented_code code_line
+          indented_code ::= * LINE_INDENTED_TAB
+          indented_code ::= * LINE_INDENTED_SPACE
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          blockquote ::= * LINE_BLOCKQUOTE quote_lines
+          blockquote ::= * LINE_BLOCKQUOTE
+          list_bulleted ::= * list_bulleted item_bulleted
+          list_bulleted ::= * item_bulleted
+          item_bulleted ::= * LINE_LIST_BULLETED para_lines cont_blocks
+          item_bulleted ::= * LINE_LIST_BULLETED para_lines
+          item_bulleted ::= * LINE_LIST_BULLETED cont_blocks
+          item_bulleted ::= * LINE_LIST_BULLETED
+          list_enumerated ::= * list_enumerated item_enumerated
+          list_enumerated ::= * item_enumerated
+          item_enumerated ::= * LINE_LIST_ENUMERATED para_lines cont_blocks
+          item_enumerated ::= * LINE_LIST_ENUMERATED para_lines
+          item_enumerated ::= * LINE_LIST_ENUMERATED cont_blocks
+          item_enumerated ::= * LINE_LIST_ENUMERATED
+          table ::= * table LINE_TABLE
+          table ::= * LINE_TABLE
+          def_citation ::= * LINE_DEF_CITATION para_lines cont_blocks
+          def_citation ::= * LINE_DEF_CITATION para_lines
+          def_citation ::= * LINE_DEF_CITATION cont_blocks
+          def_citation ::= * LINE_DEF_CITATION
+          def_footnote ::= * LINE_DEF_FOOTNOTE para_lines cont_blocks
+          def_footnote ::= * LINE_DEF_FOOTNOTE para_lines
+          def_footnote ::= * LINE_DEF_FOOTNOTE cont_blocks
+          def_footnote ::= * LINE_DEF_FOOTNOTE
+          def_link ::= * LINE_DEF_LINK para_lines
+          def_link ::= * LINE_DEF_LINK
+          html_block ::= * LINE_HTML html_block_lines
+          html_block ::= * LINE_HTML
+          fenced_block ::= * LINE_FENCE_BACKTICK fenced_lines LINE_FENCE_BACKTICK
+          fenced_block ::= * LINE_FENCE_BACKTICK fenced_lines
+          fenced_block ::= * LINE_FENCE_BACKTICK_START fenced_lines LINE_FENCE_BACKTICK
+          fenced_block ::= * LINE_FENCE_BACKTICK_START fenced_lines
+
+                    LINE_PLAIN shift        20     
+             LINE_INDENTED_TAB shift-reduce 59     indented_code ::= LINE_INDENTED_TAB
+           LINE_INDENTED_SPACE shift-reduce 60     indented_code ::= LINE_INDENTED_SPACE
+                    LINE_ATX_1 shift-reduce 5      block ::= LINE_ATX_1
+                    LINE_ATX_2 shift-reduce 6      block ::= LINE_ATX_2
+                    LINE_ATX_3 shift-reduce 7      block ::= LINE_ATX_3
+                    LINE_ATX_4 shift-reduce 8      block ::= LINE_ATX_4
+                    LINE_ATX_5 shift-reduce 9      block ::= LINE_ATX_5
+                    LINE_ATX_6 shift-reduce 10     block ::= LINE_ATX_6
+                       LINE_HR shift-reduce 16     block ::= LINE_HR
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+               LINE_BLOCKQUOTE shift        14     
+            LINE_LIST_BULLETED shift        5      
+          LINE_LIST_ENUMERATED shift        4      
+                    LINE_TABLE shift-reduce 74     table ::= LINE_TABLE
+             LINE_DEF_CITATION shift        3      
+             LINE_DEF_FOOTNOTE shift        2      
+                 LINE_DEF_LINK shift        15     
+                     LINE_HTML shift        13     
+           LINE_FENCE_BACKTICK shift        12     
+     LINE_FENCE_BACKTICK_START shift        11     
+                           doc accept
+                        blocks shift        1      
+                         block shift-reduce 2      blocks ::= block
+                          para shift-reduce 3      block ::= para
+                 indented_code shift        10     
+                         empty shift        37     
+                 list_bulleted shift        35     
+               list_enumerated shift        33     
+                    blockquote shift-reduce 14     block ::= blockquote
+                         table shift        36     
+                  def_citation shift-reduce 17     block ::= def_citation
+                  def_footnote shift-reduce 18     block ::= def_footnote
+                      def_link shift-reduce 19     block ::= def_link
+                    html_block shift-reduce 20     block ::= html_block
+                  fenced_block shift-reduce 21     block ::= fenced_block
+                 item_bulleted shift        35       /* because item_bulleted==list_bulleted */
+               item_enumerated shift        33       /* because item_enumerated==list_enumerated */
+
+State 1:
+      (0) doc ::= blocks *
+          blocks ::= blocks * block
+          block ::= * para
+          block ::= * indented_code
+          block ::= * LINE_ATX_1
+          block ::= * LINE_ATX_2
+          block ::= * LINE_ATX_3
+          block ::= * LINE_ATX_4
+          block ::= * LINE_ATX_5
+          block ::= * LINE_ATX_6
+          block ::= * empty
+          block ::= * list_bulleted
+          block ::= * list_enumerated
+          block ::= * blockquote
+          block ::= * table
+          block ::= * LINE_HR
+          block ::= * def_citation
+          block ::= * def_footnote
+          block ::= * def_link
+          block ::= * html_block
+          block ::= * fenced_block
+          para ::= * LINE_PLAIN para_lines
+          para ::= * LINE_PLAIN
+          indented_code ::= * indented_code code_line
+          indented_code ::= * LINE_INDENTED_TAB
+          indented_code ::= * LINE_INDENTED_SPACE
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          blockquote ::= * LINE_BLOCKQUOTE quote_lines
+          blockquote ::= * LINE_BLOCKQUOTE
+          list_bulleted ::= * list_bulleted item_bulleted
+          list_bulleted ::= * item_bulleted
+          item_bulleted ::= * LINE_LIST_BULLETED para_lines cont_blocks
+          item_bulleted ::= * LINE_LIST_BULLETED para_lines
+          item_bulleted ::= * LINE_LIST_BULLETED cont_blocks
+          item_bulleted ::= * LINE_LIST_BULLETED
+          list_enumerated ::= * list_enumerated item_enumerated
+          list_enumerated ::= * item_enumerated
+          item_enumerated ::= * LINE_LIST_ENUMERATED para_lines cont_blocks
+          item_enumerated ::= * LINE_LIST_ENUMERATED para_lines
+          item_enumerated ::= * LINE_LIST_ENUMERATED cont_blocks
+          item_enumerated ::= * LINE_LIST_ENUMERATED
+          table ::= * table LINE_TABLE
+          table ::= * LINE_TABLE
+          def_citation ::= * LINE_DEF_CITATION para_lines cont_blocks
+          def_citation ::= * LINE_DEF_CITATION para_lines
+          def_citation ::= * LINE_DEF_CITATION cont_blocks
+          def_citation ::= * LINE_DEF_CITATION
+          def_footnote ::= * LINE_DEF_FOOTNOTE para_lines cont_blocks
+          def_footnote ::= * LINE_DEF_FOOTNOTE para_lines
+          def_footnote ::= * LINE_DEF_FOOTNOTE cont_blocks
+          def_footnote ::= * LINE_DEF_FOOTNOTE
+          def_link ::= * LINE_DEF_LINK para_lines
+          def_link ::= * LINE_DEF_LINK
+          html_block ::= * LINE_HTML html_block_lines
+          html_block ::= * LINE_HTML
+          fenced_block ::= * LINE_FENCE_BACKTICK fenced_lines LINE_FENCE_BACKTICK
+          fenced_block ::= * LINE_FENCE_BACKTICK fenced_lines
+          fenced_block ::= * LINE_FENCE_BACKTICK_START fenced_lines LINE_FENCE_BACKTICK
+          fenced_block ::= * LINE_FENCE_BACKTICK_START fenced_lines
+
+                             $ reduce       0      doc ::= blocks
+                    LINE_PLAIN shift        20     
+             LINE_INDENTED_TAB shift-reduce 59     indented_code ::= LINE_INDENTED_TAB
+           LINE_INDENTED_SPACE shift-reduce 60     indented_code ::= LINE_INDENTED_SPACE
+                    LINE_ATX_1 shift-reduce 5      block ::= LINE_ATX_1
+                    LINE_ATX_2 shift-reduce 6      block ::= LINE_ATX_2
+                    LINE_ATX_3 shift-reduce 7      block ::= LINE_ATX_3
+                    LINE_ATX_4 shift-reduce 8      block ::= LINE_ATX_4
+                    LINE_ATX_5 shift-reduce 9      block ::= LINE_ATX_5
+                    LINE_ATX_6 shift-reduce 10     block ::= LINE_ATX_6
+                       LINE_HR shift-reduce 16     block ::= LINE_HR
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+               LINE_BLOCKQUOTE shift        14     
+            LINE_LIST_BULLETED shift        5      
+          LINE_LIST_ENUMERATED shift        4      
+                    LINE_TABLE shift-reduce 74     table ::= LINE_TABLE
+             LINE_DEF_CITATION shift        3      
+             LINE_DEF_FOOTNOTE shift        2      
+                 LINE_DEF_LINK shift        15     
+                     LINE_HTML shift        13     
+           LINE_FENCE_BACKTICK shift        12     
+     LINE_FENCE_BACKTICK_START shift        11     
+                         block shift-reduce 1      blocks ::= blocks block
+                          para shift-reduce 3      block ::= para
+                 indented_code shift        10     
+                         empty shift        37     
+                 list_bulleted shift        35     
+               list_enumerated shift        33     
+                    blockquote shift-reduce 14     block ::= blockquote
+                         table shift        36     
+                  def_citation shift-reduce 17     block ::= def_citation
+                  def_footnote shift-reduce 18     block ::= def_footnote
+                      def_link shift-reduce 19     block ::= def_link
+                    html_block shift-reduce 20     block ::= html_block
+                  fenced_block shift-reduce 21     block ::= fenced_block
+                 item_bulleted shift        35       /* because item_bulleted==list_bulleted */
+               item_enumerated shift        33       /* because item_enumerated==list_enumerated */
+
+State 2:
+          para_lines ::= * para_lines para_line
+          para_lines ::= * para_line
+          para_line ::= * LINE_CONTINUATION
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          cont_blocks ::= * cont_blocks cont_block
+          cont_blocks ::= * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+          def_footnote ::= LINE_DEF_FOOTNOTE * para_lines cont_blocks
+          def_footnote ::= LINE_DEF_FOOTNOTE * para_lines
+          def_footnote ::= LINE_DEF_FOOTNOTE * cont_blocks
+     (76) def_footnote ::= LINE_DEF_FOOTNOTE *
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       76      ** Parsing conflict **
+                         empty shift        28     
+                    para_lines shift        6      
+                     para_line shift        6        /* because para_line==para_lines */
+                   cont_blocks shift        16     
+                    cont_block shift        16       /* because cont_block==cont_blocks */
+                     {default} reduce       76     def_footnote ::= LINE_DEF_FOOTNOTE
+
+State 3:
+          para_lines ::= * para_lines para_line
+          para_lines ::= * para_line
+          para_line ::= * LINE_CONTINUATION
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          cont_blocks ::= * cont_blocks cont_block
+          cont_blocks ::= * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+          def_citation ::= LINE_DEF_CITATION * para_lines cont_blocks
+          def_citation ::= LINE_DEF_CITATION * para_lines
+          def_citation ::= LINE_DEF_CITATION * cont_blocks
+     (75) def_citation ::= LINE_DEF_CITATION *
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       75      ** Parsing conflict **
+                         empty shift        28     
+                    para_lines shift        7      
+                     para_line shift        7        /* because para_line==para_lines */
+                   cont_blocks shift        18     
+                    cont_block shift        18       /* because cont_block==cont_blocks */
+                     {default} reduce       75     def_citation ::= LINE_DEF_CITATION
+
+State 4:
+          para_lines ::= * para_lines para_line
+          para_lines ::= * para_line
+          para_line ::= * LINE_CONTINUATION
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          item_enumerated ::= LINE_LIST_ENUMERATED * para_lines cont_blocks
+          item_enumerated ::= LINE_LIST_ENUMERATED * para_lines
+          item_enumerated ::= LINE_LIST_ENUMERATED * cont_blocks
+     (37) item_enumerated ::= LINE_LIST_ENUMERATED *
+          cont_blocks ::= * cont_blocks cont_block
+          cont_blocks ::= * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       37      ** Parsing conflict **
+                         empty shift        28     
+                    para_lines shift        8      
+                     para_line shift        8        /* because para_line==para_lines */
+                   cont_blocks shift        21     
+                    cont_block shift        21       /* because cont_block==cont_blocks */
+                     {default} reduce       37     item_enumerated ::= LINE_LIST_ENUMERATED
+
+State 5:
+          para_lines ::= * para_lines para_line
+          para_lines ::= * para_line
+          para_line ::= * LINE_CONTINUATION
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          item_bulleted ::= LINE_LIST_BULLETED * para_lines cont_blocks
+          item_bulleted ::= LINE_LIST_BULLETED * para_lines
+          item_bulleted ::= LINE_LIST_BULLETED * cont_blocks
+     (32) item_bulleted ::= LINE_LIST_BULLETED *
+          cont_blocks ::= * cont_blocks cont_block
+          cont_blocks ::= * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       32      ** Parsing conflict **
+                         empty shift        28     
+                    para_lines shift        9      
+                     para_line shift        9        /* because para_line==para_lines */
+                   cont_blocks shift        23     
+                    cont_block shift        23       /* because cont_block==cont_blocks */
+                     {default} reduce       32     item_bulleted ::= LINE_LIST_BULLETED
+
+State 6:
+          para_lines ::= para_lines * para_line
+          para_line ::= * LINE_CONTINUATION
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          cont_blocks ::= * cont_blocks cont_block
+          cont_blocks ::= * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+          def_footnote ::= LINE_DEF_FOOTNOTE para_lines * cont_blocks
+     (46) def_footnote ::= LINE_DEF_FOOTNOTE para_lines *
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       46      ** Parsing conflict **
+                         empty shift        28     
+                     para_line shift-reduce 23     para_lines ::= para_lines para_line
+                   cont_blocks shift        17     
+                    cont_block shift        17       /* because cont_block==cont_blocks */
+                     {default} reduce       46     def_footnote ::= LINE_DEF_FOOTNOTE para_lines
+
+State 7:
+          para_lines ::= para_lines * para_line
+          para_line ::= * LINE_CONTINUATION
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          cont_blocks ::= * cont_blocks cont_block
+          cont_blocks ::= * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+          def_citation ::= LINE_DEF_CITATION para_lines * cont_blocks
+     (43) def_citation ::= LINE_DEF_CITATION para_lines *
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       43      ** Parsing conflict **
+                         empty shift        28     
+                     para_line shift-reduce 23     para_lines ::= para_lines para_line
+                   cont_blocks shift        19     
+                    cont_block shift        19       /* because cont_block==cont_blocks */
+                     {default} reduce       43     def_citation ::= LINE_DEF_CITATION para_lines
+
+State 8:
+          para_lines ::= para_lines * para_line
+          para_line ::= * LINE_CONTINUATION
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          item_enumerated ::= LINE_LIST_ENUMERATED para_lines * cont_blocks
+     (35) item_enumerated ::= LINE_LIST_ENUMERATED para_lines *
+          cont_blocks ::= * cont_blocks cont_block
+          cont_blocks ::= * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       35      ** Parsing conflict **
+                         empty shift        28     
+                     para_line shift-reduce 23     para_lines ::= para_lines para_line
+                   cont_blocks shift        22     
+                    cont_block shift        22       /* because cont_block==cont_blocks */
+                     {default} reduce       35     item_enumerated ::= LINE_LIST_ENUMERATED para_lines
+
+State 9:
+          para_lines ::= para_lines * para_line
+          para_line ::= * LINE_CONTINUATION
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          item_bulleted ::= LINE_LIST_BULLETED para_lines * cont_blocks
+     (30) item_bulleted ::= LINE_LIST_BULLETED para_lines *
+          cont_blocks ::= * cont_blocks cont_block
+          cont_blocks ::= * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       30      ** Parsing conflict **
+                         empty shift        28     
+                     para_line shift-reduce 23     para_lines ::= para_lines para_line
+                   cont_blocks shift        24     
+                    cont_block shift        24       /* because cont_block==cont_blocks */
+                     {default} reduce       30     item_bulleted ::= LINE_LIST_BULLETED para_lines
+
+State 10:
+      (4) block ::= indented_code *
+          indented_code ::= indented_code * code_line
+          code_line ::= * indented_line
+          code_line ::= * LINE_EMPTY
+          indented_line ::= * LINE_INDENTED_TAB
+          indented_line ::= * LINE_INDENTED_SPACE
+
+             LINE_INDENTED_TAB shift-reduce 63     indented_line ::= LINE_INDENTED_TAB
+             LINE_INDENTED_TAB reduce       4       ** Parsing conflict **
+           LINE_INDENTED_SPACE shift-reduce 64     indented_line ::= LINE_INDENTED_SPACE
+           LINE_INDENTED_SPACE reduce       4       ** Parsing conflict **
+                    LINE_EMPTY shift-reduce 62     code_line ::= LINE_EMPTY
+                    LINE_EMPTY reduce       4       ** Parsing conflict **
+                     code_line shift-reduce 24     indented_code ::= indented_code code_line
+                 indented_line shift-reduce 24     indented_code ::= indented_code code_line  /* because indented_line==code_line */
+                     {default} reduce       4      block ::= indented_code
+
+State 11:
+          fenced_block ::= LINE_FENCE_BACKTICK_START * fenced_lines LINE_FENCE_BACKTICK
+          fenced_block ::= LINE_FENCE_BACKTICK_START * fenced_lines
+          fenced_lines ::= * fenced_lines fenced_line
+          fenced_lines ::= * fenced_line
+          fenced_line ::= * LINE_CONTINUATION
+          fenced_line ::= * LINE_EMPTY
+
+             LINE_CONTINUATION shift-reduce 83     fenced_line ::= LINE_CONTINUATION
+                    LINE_EMPTY shift-reduce 84     fenced_line ::= LINE_EMPTY
+                  fenced_lines shift        26     
+                   fenced_line shift        26       /* because fenced_line==fenced_lines */
+
+State 12:
+          fenced_block ::= LINE_FENCE_BACKTICK * fenced_lines LINE_FENCE_BACKTICK
+          fenced_block ::= LINE_FENCE_BACKTICK * fenced_lines
+          fenced_lines ::= * fenced_lines fenced_line
+          fenced_lines ::= * fenced_line
+          fenced_line ::= * LINE_CONTINUATION
+          fenced_line ::= * LINE_EMPTY
+
+             LINE_CONTINUATION shift-reduce 83     fenced_line ::= LINE_CONTINUATION
+                    LINE_EMPTY shift-reduce 84     fenced_line ::= LINE_EMPTY
+                  fenced_lines shift        27     
+                   fenced_line shift        27       /* because fenced_line==fenced_lines */
+
+State 13:
+          html_block ::= LINE_HTML * html_block_lines
+     (78) html_block ::= LINE_HTML *
+          html_block_lines ::= * html_block_lines html_block_line
+          html_block_lines ::= * html_block_line
+          html_block_line ::= * LINE_CONTINUATION
+          html_block_line ::= * LINE_HTML
+
+             LINE_CONTINUATION shift-reduce 80     html_block_line ::= LINE_CONTINUATION
+                     LINE_HTML shift-reduce 81     html_block_line ::= LINE_HTML
+                     LINE_HTML reduce       78      ** Parsing conflict **
+              html_block_lines shift        29     
+               html_block_line shift        29       /* because html_block_line==html_block_lines */
+                     {default} reduce       78     html_block ::= LINE_HTML
+
+State 14:
+          blockquote ::= LINE_BLOCKQUOTE * quote_lines
+     (66) blockquote ::= LINE_BLOCKQUOTE *
+          quote_lines ::= * quote_lines quote_line
+          quote_lines ::= * quote_line
+          quote_line ::= * LINE_BLOCKQUOTE
+          quote_line ::= * LINE_CONTINUATION
+
+             LINE_CONTINUATION shift-reduce 69     quote_line ::= LINE_CONTINUATION
+               LINE_BLOCKQUOTE shift-reduce 68     quote_line ::= LINE_BLOCKQUOTE
+               LINE_BLOCKQUOTE reduce       66      ** Parsing conflict **
+                   quote_lines shift        30     
+                    quote_line shift        30       /* because quote_line==quote_lines */
+                     {default} reduce       66     blockquote ::= LINE_BLOCKQUOTE
+
+State 15:
+          para_lines ::= * para_lines para_line
+          para_lines ::= * para_line
+          para_line ::= * LINE_CONTINUATION
+          def_link ::= LINE_DEF_LINK * para_lines
+     (77) def_link ::= LINE_DEF_LINK *
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                    para_lines shift        31     
+                     para_line shift        31       /* because para_line==para_lines */
+                     {default} reduce       77     def_link ::= LINE_DEF_LINK
+
+State 16:
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          cont_blocks ::= cont_blocks * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+     (47) def_footnote ::= LINE_DEF_FOOTNOTE cont_blocks *
+
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       47      ** Parsing conflict **
+                         empty shift        28     
+                    cont_block shift-reduce 38     cont_blocks ::= cont_blocks cont_block
+                     {default} reduce       47     def_footnote ::= LINE_DEF_FOOTNOTE cont_blocks
+
+State 17:
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          cont_blocks ::= cont_blocks * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+     (45) def_footnote ::= LINE_DEF_FOOTNOTE para_lines cont_blocks *
+
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       45      ** Parsing conflict **
+                         empty shift        28     
+                    cont_block shift-reduce 38     cont_blocks ::= cont_blocks cont_block
+                     {default} reduce       45     def_footnote ::= LINE_DEF_FOOTNOTE para_lines cont_blocks
+
+State 18:
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          cont_blocks ::= cont_blocks * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+     (44) def_citation ::= LINE_DEF_CITATION cont_blocks *
+
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       44      ** Parsing conflict **
+                         empty shift        28     
+                    cont_block shift-reduce 38     cont_blocks ::= cont_blocks cont_block
+                     {default} reduce       44     def_citation ::= LINE_DEF_CITATION cont_blocks
+
+State 19:
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+          cont_blocks ::= cont_blocks * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+     (42) def_citation ::= LINE_DEF_CITATION para_lines cont_blocks *
+
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       42      ** Parsing conflict **
+                         empty shift        28     
+                    cont_block shift-reduce 38     cont_blocks ::= cont_blocks cont_block
+                     {default} reduce       42     def_citation ::= LINE_DEF_CITATION para_lines cont_blocks
+
+State 20:
+          para ::= LINE_PLAIN * para_lines
+     (56) para ::= LINE_PLAIN *
+          para_lines ::= * para_lines para_line
+          para_lines ::= * para_line
+          para_line ::= * LINE_CONTINUATION
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                    para_lines shift        32     
+                     para_line shift        32       /* because para_line==para_lines */
+                     {default} reduce       56     para ::= LINE_PLAIN
+
+State 21:
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+     (36) item_enumerated ::= LINE_LIST_ENUMERATED cont_blocks *
+          cont_blocks ::= cont_blocks * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       36      ** Parsing conflict **
+                         empty shift        28     
+                    cont_block shift-reduce 38     cont_blocks ::= cont_blocks cont_block
+                     {default} reduce       36     item_enumerated ::= LINE_LIST_ENUMERATED cont_blocks
+
+State 22:
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+     (34) item_enumerated ::= LINE_LIST_ENUMERATED para_lines cont_blocks *
+          cont_blocks ::= cont_blocks * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       34      ** Parsing conflict **
+                         empty shift        28     
+                    cont_block shift-reduce 38     cont_blocks ::= cont_blocks cont_block
+                     {default} reduce       34     item_enumerated ::= LINE_LIST_ENUMERATED para_lines cont_blocks
+
+State 23:
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+     (31) item_bulleted ::= LINE_LIST_BULLETED cont_blocks *
+          cont_blocks ::= cont_blocks * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       31      ** Parsing conflict **
+                         empty shift        28     
+                    cont_block shift-reduce 38     cont_blocks ::= cont_blocks cont_block
+                     {default} reduce       31     item_bulleted ::= LINE_LIST_BULLETED cont_blocks
+
+State 24:
+          empty ::= * empty LINE_EMPTY
+          empty ::= * LINE_EMPTY
+     (29) item_bulleted ::= LINE_LIST_BULLETED para_lines cont_blocks *
+          cont_blocks ::= cont_blocks * cont_block
+          cont_block ::= * empty indented_line para_lines
+          cont_block ::= * empty indented_line
+          cont_block ::= * empty
+
+                    LINE_EMPTY shift-reduce 65     empty ::= LINE_EMPTY
+                    LINE_EMPTY reduce       29      ** Parsing conflict **
+                         empty shift        28     
+                    cont_block shift-reduce 38     cont_blocks ::= cont_blocks cont_block
+                     {default} reduce       29     item_bulleted ::= LINE_LIST_BULLETED para_lines cont_blocks
+
+State 25:
+          para_lines ::= * para_lines para_line
+          para_lines ::= * para_line
+          para_line ::= * LINE_CONTINUATION
+          cont_block ::= empty indented_line * para_lines
+     (40) cont_block ::= empty indented_line *
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                    para_lines shift        34     
+                     para_line shift        34       /* because para_line==para_lines */
+                     {default} reduce       40     cont_block ::= empty indented_line
+
+State 26:
+          fenced_block ::= LINE_FENCE_BACKTICK_START fenced_lines * LINE_FENCE_BACKTICK
+     (54) fenced_block ::= LINE_FENCE_BACKTICK_START fenced_lines *
+          fenced_lines ::= fenced_lines * fenced_line
+          fenced_line ::= * LINE_CONTINUATION
+          fenced_line ::= * LINE_EMPTY
+
+             LINE_CONTINUATION shift-reduce 83     fenced_line ::= LINE_CONTINUATION
+                    LINE_EMPTY shift-reduce 84     fenced_line ::= LINE_EMPTY
+                    LINE_EMPTY reduce       54      ** Parsing conflict **
+           LINE_FENCE_BACKTICK shift-reduce 53     fenced_block ::= LINE_FENCE_BACKTICK_START fenced_lines LINE_FENCE_BACKTICK
+           LINE_FENCE_BACKTICK reduce       54      ** Parsing conflict **
+                   fenced_line shift-reduce 55     fenced_lines ::= fenced_lines fenced_line
+                     {default} reduce       54     fenced_block ::= LINE_FENCE_BACKTICK_START fenced_lines
+
+State 27:
+          fenced_block ::= LINE_FENCE_BACKTICK fenced_lines * LINE_FENCE_BACKTICK
+     (52) fenced_block ::= LINE_FENCE_BACKTICK fenced_lines *
+          fenced_lines ::= fenced_lines * fenced_line
+          fenced_line ::= * LINE_CONTINUATION
+          fenced_line ::= * LINE_EMPTY
+
+             LINE_CONTINUATION shift-reduce 83     fenced_line ::= LINE_CONTINUATION
+                    LINE_EMPTY shift-reduce 84     fenced_line ::= LINE_EMPTY
+                    LINE_EMPTY reduce       52      ** Parsing conflict **
+           LINE_FENCE_BACKTICK shift-reduce 51     fenced_block ::= LINE_FENCE_BACKTICK fenced_lines LINE_FENCE_BACKTICK
+           LINE_FENCE_BACKTICK reduce       52      ** Parsing conflict **
+                   fenced_line shift-reduce 55     fenced_lines ::= fenced_lines fenced_line
+                     {default} reduce       52     fenced_block ::= LINE_FENCE_BACKTICK fenced_lines
+
+State 28:
+          indented_line ::= * LINE_INDENTED_TAB
+          indented_line ::= * LINE_INDENTED_SPACE
+          empty ::= empty * LINE_EMPTY
+          cont_block ::= empty * indented_line para_lines
+          cont_block ::= empty * indented_line
+     (73) cont_block ::= empty *
+
+             LINE_INDENTED_TAB shift-reduce 63     indented_line ::= LINE_INDENTED_TAB
+             LINE_INDENTED_TAB reduce       73      ** Parsing conflict **
+           LINE_INDENTED_SPACE shift-reduce 64     indented_line ::= LINE_INDENTED_SPACE
+           LINE_INDENTED_SPACE reduce       73      ** Parsing conflict **
+                    LINE_EMPTY shift-reduce 25     empty ::= empty LINE_EMPTY
+                    LINE_EMPTY reduce       73      ** Parsing conflict **
+                 indented_line shift        25     
+                     {default} reduce       73     cont_block ::= empty
+
+State 29:
+     (49) html_block ::= LINE_HTML html_block_lines *
+          html_block_lines ::= html_block_lines * html_block_line
+          html_block_line ::= * LINE_CONTINUATION
+          html_block_line ::= * LINE_HTML
+
+             LINE_CONTINUATION shift-reduce 80     html_block_line ::= LINE_CONTINUATION
+                     LINE_HTML shift-reduce 81     html_block_line ::= LINE_HTML
+                     LINE_HTML reduce       49      ** Parsing conflict **
+               html_block_line shift-reduce 50     html_block_lines ::= html_block_lines html_block_line
+                     {default} reduce       49     html_block ::= LINE_HTML html_block_lines
+
+State 30:
+     (26) blockquote ::= LINE_BLOCKQUOTE quote_lines *
+          quote_lines ::= quote_lines * quote_line
+          quote_line ::= * LINE_BLOCKQUOTE
+          quote_line ::= * LINE_CONTINUATION
+
+             LINE_CONTINUATION shift-reduce 69     quote_line ::= LINE_CONTINUATION
+               LINE_BLOCKQUOTE shift-reduce 68     quote_line ::= LINE_BLOCKQUOTE
+               LINE_BLOCKQUOTE reduce       26      ** Parsing conflict **
+                    quote_line shift-reduce 27     quote_lines ::= quote_lines quote_line
+                     {default} reduce       26     blockquote ::= LINE_BLOCKQUOTE quote_lines
+
+State 31:
+          para_lines ::= para_lines * para_line
+          para_line ::= * LINE_CONTINUATION
+     (48) def_link ::= LINE_DEF_LINK para_lines *
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                     para_line shift-reduce 23     para_lines ::= para_lines para_line
+                     {default} reduce       48     def_link ::= LINE_DEF_LINK para_lines
+
+State 32:
+     (22) para ::= LINE_PLAIN para_lines *
+          para_lines ::= para_lines * para_line
+          para_line ::= * LINE_CONTINUATION
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                     para_line shift-reduce 23     para_lines ::= para_lines para_line
+                     {default} reduce       22     para ::= LINE_PLAIN para_lines
+
+State 33:
+     (13) block ::= list_enumerated *
+          list_enumerated ::= list_enumerated * item_enumerated
+          item_enumerated ::= * LINE_LIST_ENUMERATED para_lines cont_blocks
+          item_enumerated ::= * LINE_LIST_ENUMERATED para_lines
+          item_enumerated ::= * LINE_LIST_ENUMERATED cont_blocks
+          item_enumerated ::= * LINE_LIST_ENUMERATED
+
+          LINE_LIST_ENUMERATED shift        4      
+          LINE_LIST_ENUMERATED reduce       13      ** Parsing conflict **
+               item_enumerated shift-reduce 33     list_enumerated ::= list_enumerated item_enumerated
+                     {default} reduce       13     block ::= list_enumerated
+
+State 34:
+          para_lines ::= para_lines * para_line
+          para_line ::= * LINE_CONTINUATION
+     (39) cont_block ::= empty indented_line para_lines *
+
+             LINE_CONTINUATION shift-reduce 58     para_line ::= LINE_CONTINUATION
+                     para_line shift-reduce 23     para_lines ::= para_lines para_line
+                     {default} reduce       39     cont_block ::= empty indented_line para_lines
+
+State 35:
+     (12) block ::= list_bulleted *
+          list_bulleted ::= list_bulleted * item_bulleted
+          item_bulleted ::= * LINE_LIST_BULLETED para_lines cont_blocks
+          item_bulleted ::= * LINE_LIST_BULLETED para_lines
+          item_bulleted ::= * LINE_LIST_BULLETED cont_blocks
+          item_bulleted ::= * LINE_LIST_BULLETED
+
+            LINE_LIST_BULLETED shift        5      
+            LINE_LIST_BULLETED reduce       12      ** Parsing conflict **
+                 item_bulleted shift-reduce 28     list_bulleted ::= list_bulleted item_bulleted
+                     {default} reduce       12     block ::= list_bulleted
+
+State 36:
+     (15) block ::= table *
+          table ::= table * LINE_TABLE
+
+                    LINE_TABLE shift-reduce 41     table ::= table LINE_TABLE
+                    LINE_TABLE reduce       15      ** Parsing conflict **
+                     {default} reduce       15     block ::= table
+
+State 37:
+     (11) block ::= empty *
+          empty ::= empty * LINE_EMPTY
+
+                    LINE_EMPTY shift-reduce 25     empty ::= empty LINE_EMPTY
+                    LINE_EMPTY reduce       11      ** Parsing conflict **
+                     {default} reduce       11     block ::= empty
+
+----------------------------------------------------
+Symbols:
+    0: $:
+    1: LINE_CONTINUATION
+    2: LINE_PLAIN
+    3: LINE_INDENTED_TAB
+    4: LINE_INDENTED_SPACE
+    5: LINE_ATX_1
+    6: LINE_ATX_2
+    7: LINE_ATX_3
+    8: LINE_ATX_4
+    9: LINE_ATX_5
+   10: LINE_ATX_6
+   11: LINE_HR
+   12: LINE_EMPTY
+   13: LINE_BLOCKQUOTE
+   14: LINE_LIST_BULLETED
+   15: LINE_LIST_ENUMERATED
+   16: LINE_TABLE
+   17: LINE_DEF_CITATION
+   18: LINE_DEF_FOOTNOTE
+   19: LINE_DEF_LINK
+   20: LINE_HTML
+   21: LINE_FENCE_BACKTICK
+   22: LINE_FENCE_BACKTICK_START
+   23: error:
+   24: doc: LINE_PLAIN LINE_INDENTED_TAB LINE_INDENTED_SPACE LINE_ATX_1 LINE_ATX_2 LINE_ATX_3 LINE_ATX_4 LINE_ATX_5 LINE_ATX_6 LINE_HR LINE_EMPTY LINE_BLOCKQUOTE LINE_LIST_BULLETED LINE_LIST_ENUMERATED LINE_TABLE LINE_DEF_CITATION LINE_DEF_FOOTNOTE LINE_DEF_LINK LINE_HTML LINE_FENCE_BACKTICK LINE_FENCE_BACKTICK_START
+   25: blocks: LINE_PLAIN LINE_INDENTED_TAB LINE_INDENTED_SPACE LINE_ATX_1 LINE_ATX_2 LINE_ATX_3 LINE_ATX_4 LINE_ATX_5 LINE_ATX_6 LINE_HR LINE_EMPTY LINE_BLOCKQUOTE LINE_LIST_BULLETED LINE_LIST_ENUMERATED LINE_TABLE LINE_DEF_CITATION LINE_DEF_FOOTNOTE LINE_DEF_LINK LINE_HTML LINE_FENCE_BACKTICK LINE_FENCE_BACKTICK_START
+   26: block: LINE_PLAIN LINE_INDENTED_TAB LINE_INDENTED_SPACE LINE_ATX_1 LINE_ATX_2 LINE_ATX_3 LINE_ATX_4 LINE_ATX_5 LINE_ATX_6 LINE_HR LINE_EMPTY LINE_BLOCKQUOTE LINE_LIST_BULLETED LINE_LIST_ENUMERATED LINE_TABLE LINE_DEF_CITATION LINE_DEF_FOOTNOTE LINE_DEF_LINK LINE_HTML LINE_FENCE_BACKTICK LINE_FENCE_BACKTICK_START
+   27: para: LINE_PLAIN
+   28: indented_code: LINE_INDENTED_TAB LINE_INDENTED_SPACE
+   29: empty: LINE_EMPTY
+   30: list_bulleted: LINE_LIST_BULLETED
+   31: list_enumerated: LINE_LIST_ENUMERATED
+   32: blockquote: LINE_BLOCKQUOTE
+   33: table: LINE_TABLE
+   34: def_citation: LINE_DEF_CITATION
+   35: def_footnote: LINE_DEF_FOOTNOTE
+   36: def_link: LINE_DEF_LINK
+   37: html_block: LINE_HTML
+   38: fenced_block: LINE_FENCE_BACKTICK LINE_FENCE_BACKTICK_START
+   39: para_lines: LINE_CONTINUATION
+   40: para_line: LINE_CONTINUATION
+   41: code_line: LINE_INDENTED_TAB LINE_INDENTED_SPACE LINE_EMPTY
+   42: indented_line: LINE_INDENTED_TAB LINE_INDENTED_SPACE
+   43: quote_lines: LINE_CONTINUATION LINE_BLOCKQUOTE
+   44: quote_line: LINE_CONTINUATION LINE_BLOCKQUOTE
+   45: item_bulleted: LINE_LIST_BULLETED
+   46: cont_blocks: LINE_EMPTY
+   47: item_enumerated: LINE_LIST_ENUMERATED
+   48: cont_block: LINE_EMPTY
+   49: html_block_lines: LINE_CONTINUATION LINE_HTML
+   50: html_block_line: LINE_CONTINUATION LINE_HTML
+   51: fenced_lines: LINE_CONTINUATION LINE_EMPTY
+   52: fenced_line: LINE_CONTINUATION LINE_EMPTY
diff --git a/src/parser.y b/src/parser.y
new file mode 100644 (file)
index 0000000..d6923a4
--- /dev/null
@@ -0,0 +1,237 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file parser.y
+
+       @brief Definition of the parser grammar, processed with lemon to create a parser.
+
+               http://www.hwaci.com/sw/lemon/
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+
+//
+// Language grammar here
+//
+
+%token_type { token * }
+
+%extra_argument { mmd_engine * engine }
+
+%fallback LINE_CONTINUATION LINE_PLAIN LINE_INDENTED_TAB LINE_INDENTED_SPACE.
+
+
+doc                                    ::= blocks(B).                                                          { engine->root = B; }
+
+blocks(A)                      ::= blocks(B) block(C).
+       {
+               strip_line_tokens_from_block(C);
+               if (B == NULL) { B = C; C = NULL;}
+               A = B;
+               token_chain_append(A, C);
+               #ifndef NDEBUG
+               fprintf(stderr, "Next block %d\n", A->tail->type);
+               #endif
+       }
+blocks(A)                      ::= block(B).
+       {
+               strip_line_tokens_from_block(B);
+               #ifndef NDEBUG
+               fprintf(stderr, "First block %d\n", B->type);
+               #endif
+               A = B;
+       }
+
+       
+block(A)                       ::= para(B).                                                            { A = token_new_parent(B, BLOCK_PARA); is_para_html(engine, A); }
+block(A)                       ::= indented_code(B).                                           { A = token_new_parent(B, BLOCK_CODE_INDENTED); }
+block(A)                       ::= LINE_ATX_1(B).                                                      { A = token_new_parent(B, BLOCK_H1); if (!(engine->extensions & EXT_NO_LABELS)) stack_push(engine->header_stack, A); }
+block(A)                       ::= LINE_ATX_2(B).                                                      { A = token_new_parent(B, BLOCK_H2); if (!(engine->extensions & EXT_NO_LABELS)) stack_push(engine->header_stack, A); }
+block(A)                       ::= LINE_ATX_3(B).                                                      { A = token_new_parent(B, BLOCK_H3); if (!(engine->extensions & EXT_NO_LABELS)) stack_push(engine->header_stack, A); }
+block(A)                       ::= LINE_ATX_4(B).                                                      { A = token_new_parent(B, BLOCK_H4); if (!(engine->extensions & EXT_NO_LABELS)) stack_push(engine->header_stack, A); }
+block(A)                       ::= LINE_ATX_5(B).                                                      { A = token_new_parent(B, BLOCK_H5); if (!(engine->extensions & EXT_NO_LABELS)) stack_push(engine->header_stack, A); }
+block(A)                       ::= LINE_ATX_6(B).                                                      { A = token_new_parent(B, BLOCK_H6); if (!(engine->extensions & EXT_NO_LABELS)) stack_push(engine->header_stack, A); }
+block(A)                       ::= empty(B).                                                           { A = token_new_parent(B, BLOCK_EMPTY); }
+block(A)                       ::= list_bulleted(B).                                           { A = token_new_parent(B, BLOCK_LIST_BULLETED); is_list_loose(A); }
+block(A)                       ::= list_enumerated(B).                                         { A = token_new_parent(B, BLOCK_LIST_ENUMERATED); is_list_loose(A); }
+block(A)                       ::= blockquote(B).                                                      { A = token_new_parent(B, BLOCK_BLOCKQUOTE); recursive_parse_blockquote(engine, A); }
+block(A)                       ::= table(B).                                                           { A = token_new_parent(B, BLOCK_TABLE); }
+block(A)                       ::= LINE_HR(B).                                                         { A = token_new_parent(B, BLOCK_HR); }
+block(A)                       ::= def_citation(B).                                            { A = token_new_parent(B, BLOCK_DEF_CITATION); stack_push(engine->definition_stack, A); }
+block(A)                       ::= def_footnote(B).                                            { A = token_new_parent(B, BLOCK_DEF_FOOTNOTE); stack_push(engine->definition_stack, A); }
+block(A)                       ::= def_link(B).                                                        { A = token_new_parent(B, BLOCK_DEF_LINK); stack_push(engine->definition_stack, A); }
+block(A)                       ::= html_block(B).                                                      { A = token_new_parent(B, BLOCK_HTML); }
+block(A)                       ::= fenced_block(B).                                            { A = token_new_parent(B, BLOCK_CODE_FENCED); B->child->type = CODE_FENCE; }
+
+
+para(A)                                ::= LINE_PLAIN(B) para_lines(C).                        { A = B; token_chain_append(B, C); }
+para                           ::= LINE_PLAIN.
+
+para_lines(A)          ::= para_lines(B) para_line(C).                         { A = B; token_chain_append(B, C); }
+para_lines                     ::= para_line.
+
+para_line                      ::= LINE_CONTINUATION.
+
+indented_code(A)       ::= indented_code(B) code_line(C).                      { A = B; token_chain_append(B, C); }
+indented_code          ::= LINE_INDENTED_TAB.
+indented_code          ::= LINE_INDENTED_SPACE.
+
+code_line                      ::= indented_line.
+code_line                      ::= LINE_EMPTY.
+
+indented_line          ::= LINE_INDENTED_TAB.
+indented_line          ::= LINE_INDENTED_SPACE.
+
+empty(A)                       ::= empty(B) LINE_EMPTY(C).                                     { A = B; token_chain_append(B, C); }
+empty                          ::= LINE_EMPTY.
+
+blockquote(A)          ::= LINE_BLOCKQUOTE(B) quote_lines(C).          { A = B; token_chain_append(B, C); }
+blockquote                     ::= LINE_BLOCKQUOTE.
+
+quote_lines(A)         ::= quote_lines(B) quote_line(C).                       { A = B; token_chain_append(B, C); }
+quote_lines                    ::= quote_line.
+
+quote_line                     ::= LINE_BLOCKQUOTE.
+quote_line                     ::= LINE_CONTINUATION.
+
+list_bulleted(A)       ::= list_bulleted(B) item_bulleted(C).          { A = B; token_chain_append(B, C); }
+list_bulleted          ::=     item_bulleted.
+
+item_bulleted(A)       ::= LINE_LIST_BULLETED(B) para_lines(C) cont_blocks(D). { token_chain_append(B, C); token_chain_append(B, D); A = token_new_parent(B, BLOCK_LIST_ITEM); recursive_parse_list_item(engine, A); }
+item_bulleted(A)       ::= LINE_LIST_BULLETED(B) para_lines(C).        { token_chain_append(B, C); A = token_new_parent(B, BLOCK_LIST_ITEM_TIGHT); recursive_parse_list_item(engine, A); }
+item_bulleted(A)       ::= LINE_LIST_BULLETED(B) cont_blocks(C).       { token_chain_append(B, C); A = token_new_parent(B, BLOCK_LIST_ITEM); if (C) {recursive_parse_list_item(engine, A);} }
+item_bulleted(A)       ::= LINE_LIST_BULLETED(B).                                      { A = token_new_parent(B, BLOCK_LIST_ITEM_TIGHT); }
+
+list_enumerated(A)     ::= list_enumerated(B) item_enumerated(C).      { A = B; token_chain_append(B, C); }
+list_enumerated                ::=     item_enumerated.
+
+item_enumerated(A)     ::= LINE_LIST_ENUMERATED(B) para_lines(C) cont_blocks(D).       { token_chain_append(B, C); token_chain_append(B, D); A = token_new_parent(B, BLOCK_LIST_ITEM); recursive_parse_list_item(engine, A); }
+item_enumerated(A)     ::= LINE_LIST_ENUMERATED(B) para_lines(C).      { token_chain_append(B, C); A = token_new_parent(B, BLOCK_LIST_ITEM_TIGHT); recursive_parse_list_item(engine, A); }
+item_enumerated(A)     ::= LINE_LIST_ENUMERATED(B) cont_blocks(C).     { token_chain_append(B, C); A = token_new_parent(B, BLOCK_LIST_ITEM); recursive_parse_list_item(engine, A); }
+item_enumerated(A)     ::= LINE_LIST_ENUMERATED(B).                            { A = token_new_parent(B, BLOCK_LIST_ITEM_TIGHT); }
+
+cont_blocks(A)         ::= cont_blocks(B) cont_block(C).                       { A = B; token_chain_append(B, C); }
+cont_blocks                    ::= cont_block.
+
+cont_block(A)          ::= empty(B) indented_line(C) para_lines(D).{ A = B; token_chain_append(B, C); token_chain_append(B, D); C->type = LINE_CONTINUATION; }
+cont_block(A)          ::= empty(B) indented_line(C).                          { A = B; token_chain_append(B, C); C->type = LINE_CONTINUATION; }
+cont_block                     ::= empty.
+
+table(A)                       ::= table(B) LINE_TABLE(C).                                     { A = B; token_chain_append(B, C); }
+table                          ::= LINE_TABLE.
+
+def_citation(A)                ::= LINE_DEF_CITATION(B) para_lines(C) cont_blocks(D).  { A = B; token_chain_append(B, C); token_chain_append(B, D); }
+def_citation(A)                ::= LINE_DEF_CITATION(B) para_lines(C).         { A = B; token_chain_append(B, C); }
+def_citation(A)                ::= LINE_DEF_CITATION(B) cont_blocks(C).        { A = B; token_chain_append(B, C); }
+def_citation           ::= LINE_DEF_CITATION.
+
+def_footnote(A)                ::= LINE_DEF_FOOTNOTE(B) para_lines(C) cont_blocks(D).  { A = B; token_chain_append(B, C); token_chain_append(B, D); }
+def_footnote(A)                ::= LINE_DEF_FOOTNOTE(B) para_lines(C).         { A = B; token_chain_append(B, C); }
+def_footnote(A)                ::= LINE_DEF_FOOTNOTE(B) cont_blocks(C).        { A = B; token_chain_append(B, C); }
+def_footnote           ::= LINE_DEF_FOOTNOTE.
+
+def_link(A)                    ::= LINE_DEF_LINK(B) para_lines(C).                     { A = B; token_chain_append(B, C); }
+def_link                       ::= LINE_DEF_LINK.
+
+html_block(A)          ::= LINE_HTML(B) html_block_lines(C).           { A = B; token_chain_append(B, C); }
+html_block                     ::= LINE_HTML.
+
+
+html_block_lines(A)    ::= html_block_lines(B) html_block_line(C).     { A = B; token_chain_append(B, C); }
+html_block_lines       ::= html_block_line.
+
+html_block_line                ::= LINE_CONTINUATION.
+html_block_line                ::= LINE_HTML.
+
+fenced_block(A)                ::= LINE_FENCE_BACKTICK(B) fenced_lines(C) LINE_FENCE_BACKTICK(D).              { A = B; token_chain_append(B, C); token_chain_append(B, D); D->child->type = CODE_FENCE; }
+fenced_block(A)                ::= LINE_FENCE_BACKTICK(B) fenced_lines(C).                                                             { A = B; token_chain_append(B, C); }
+fenced_block(A)                ::= LINE_FENCE_BACKTICK_START(B) fenced_lines(C) LINE_FENCE_BACKTICK(D).        { A = B; token_chain_append(B, C); token_chain_append(B, D); D->child->type = CODE_FENCE; }
+fenced_block(A)                ::= LINE_FENCE_BACKTICK_START(B) fenced_lines(C).                                                       { A = B; token_chain_append(B, C); }
+
+
+fenced_lines(A)                ::= fenced_lines(B) fenced_line(C).                     { A = B; token_chain_append(B, C); }
+fenced_lines           ::= fenced_line.
+
+fenced_line                    ::= LINE_CONTINUATION.
+fenced_line                    ::= LINE_EMPTY.
+
+//
+// Additional Configuration
+//
+
+%include {
+       #include <assert.h>
+       #include <stdio.h>
+       #include <stdlib.h>
+
+       #include "libMultiMarkdown.h"
+       #include "mmd.h"
+       #include "parser.h"
+       #include "token.h"
+}
+
+
+// Improved error messages for debugging:
+//     http://stackoverflow.com/questions/11705737/expected-token-using-lemon-parser-generator
+
+%syntax_error {
+#ifndef NDEBUG
+       fprintf(stderr,"Parser syntax error.\n");
+       int n = sizeof(yyTokenName) / sizeof(yyTokenName[0]);
+       for (int i = 0; i < n; ++i) {
+               int a = yy_find_shift_action(yypParser, (YYCODETYPE)i);
+               if (a < YYNSTATE + YYNRULE) {
+                       fprintf(stderr,"expected token: %s\n", yyTokenName[i]);
+               }
+       }
+#endif
+}
+
+%parse_failure {
+       fprintf(stderr, "Parser failed to successfully parse.\n");
+}
+
diff --git a/src/rng.c b/src/rng.c
new file mode 100644 (file)
index 0000000..07a8701
--- /dev/null
+++ b/src/rng.c
@@ -0,0 +1,117 @@
+/*    This program by D E Knuth is in the public domain and freely copyable
+ *    AS LONG AS YOU MAKE ABSOLUTELY NO CHANGES!
+ *    It is explained in Seminumerical Algorithms, 3rd edition, Section 3.6
+ *    (or in the errata to the 2nd edition --- see
+ *        http://www-cs-faculty.stanford.edu/~knuth/taocp.html
+ *    in the changes to Volume 2 on pages 171 and following).              */
+
+/*    N.B. The MODIFICATIONS introduced in the 9th printing (2002) are
+      included here; there's no backwards compatibility with the original. */
+
+/*    This version also adopts Brendan McKay's suggestion to
+      accommodate naive users who forget to call ran_start(seed).          */
+
+/*    If you find any bugs, please report them immediately to
+ *                 taocp@cs.stanford.edu
+ *    (and you will be rewarded if the bug is genuine). Thanks!            */
+
+/************ see the book for explanations and caveats! *******************/
+/************ in particular, you need two's complement arithmetic **********/
+
+#define KK 100                     /* the long lag */
+#define LL  37                     /* the short lag */
+#define MM (1L<<30)                 /* the modulus */
+#define mod_diff(x,y) (((x)-(y))&(MM-1)) /* subtraction mod MM */
+
+long ran_x[KK];                    /* the generator state */
+
+#ifdef __STDC__
+void ran_array(long aa[],int n)
+#else
+void ran_array(aa,n)    /* put n new random numbers in aa */
+  long *aa;   /* destination */
+  int n;      /* array length (must be at least KK) */
+#endif
+{
+  register int i,j;
+  for (j=0;j<KK;j++) aa[j]=ran_x[j];
+  for (;j<n;j++) aa[j]=mod_diff(aa[j-KK],aa[j-LL]);
+  for (i=0;i<LL;i++,j++) ran_x[i]=mod_diff(aa[j-KK],aa[j-LL]);
+  for (;i<KK;i++,j++) ran_x[i]=mod_diff(aa[j-KK],ran_x[i-LL]);
+}
+
+/* the following routines are from exercise 3.6--15 */
+/* after calling ran_start, get new randoms by, e.g., "x=ran_arr_next()" */
+
+#define QUALITY 1009 /* recommended quality level for high-res use */
+long ran_arr_buf[QUALITY];
+long ran_arr_dummy=-1, ran_arr_started=-1;
+long *ran_arr_ptr=&ran_arr_dummy; /* the next random number, or -1 */
+
+#define TT  70   /* guaranteed separation between streams */
+#define is_odd(x)  ((x)&1)          /* units bit of x */
+
+#ifdef __STDC__
+void ran_start(long seed)
+#else
+void ran_start(seed)    /* do this before using ran_array */
+  long seed;            /* selector for different streams */
+#endif
+{
+  register int t,j;
+  long x[KK+KK-1];              /* the preparation buffer */
+  register long ss=(seed+2)&(MM-2);
+  for (j=0;j<KK;j++) {
+    x[j]=ss;                      /* bootstrap the buffer */
+    ss<<=1; if (ss>=MM) ss-=MM-2; /* cyclic shift 29 bits */
+  }
+  x[1]++;              /* make x[1] (and only x[1]) odd */
+  for (ss=seed&(MM-1),t=TT-1; t; ) {       
+    for (j=KK-1;j>0;j--) x[j+j]=x[j], x[j+j-1]=0; /* "square" */
+    for (j=KK+KK-2;j>=KK;j--)
+      x[j-(KK-LL)]=mod_diff(x[j-(KK-LL)],x[j]),
+      x[j-KK]=mod_diff(x[j-KK],x[j]);
+    if (is_odd(ss)) {              /* "multiply by z" */
+      for (j=KK;j>0;j--)  x[j]=x[j-1];
+      x[0]=x[KK];            /* shift the buffer cyclically */
+      x[LL]=mod_diff(x[LL],x[KK]);
+    }
+    if (ss) ss>>=1; else t--;
+  }
+  for (j=0;j<LL;j++) ran_x[j+KK-LL]=x[j];
+  for (;j<KK;j++) ran_x[j-LL]=x[j];
+  for (j=0;j<10;j++) ran_array(x,KK+KK-1); /* warm things up */
+  ran_arr_ptr=&ran_arr_started;
+}
+
+#define ran_arr_next() (*ran_arr_ptr>=0? *ran_arr_ptr++: ran_arr_cycle())
+long ran_arr_cycle()
+{
+  if (ran_arr_ptr==&ran_arr_dummy)
+    ran_start(314159L); /* the user forgot to initialize */
+  ran_array(ran_arr_buf,QUALITY);
+  ran_arr_buf[KK]=-1;
+  ran_arr_ptr=ran_arr_buf+1;
+  return ran_arr_buf[0];
+}
+
+/* Tweaked to include as a library - Fletcher T. Penney */
+/*#include <stdio.h>
+int main()
+{
+  register int m; long a[2009]; 
+  ran_start(310952L);
+  for (m=0;m<=2009;m++) ran_array(a,1009);
+  printf("%ld\n", a[0]);             *//* 995235265 */
+/*  ran_start(310952L);
+  for (m=0;m<=1009;m++) ran_array(a,2009);
+  printf("%ld\n", a[0]);             *//* 995235265 */
+/*  printf("%ld\n",ran_arr_next());
+  return 0;
+} */
+
+long ran_num_next()
+{
+       return ran_arr_next();
+}
+
diff --git a/src/scanners.c b/src/scanners.c
new file mode 100644 (file)
index 0000000..3caba93
--- /dev/null
@@ -0,0 +1,8515 @@
+/* Generated by re2c 0.14.3 on Wed Jan 18 22:23:16 2017 */
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file scanners.c
+
+       @brief After text has been tokenized, there are still some constructs that are best
+       interpreted using regular expressions.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+#include <stdlib.h>
+
+#include "scanners.h"
+
+
+
+
+size_t scan_spnl(const char * c) {
+       const char * start = c;
+
+
+{
+       char yych;
+
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy3;
+       case '\n':      goto yy4;
+       case '\r':      goto yy6;
+       default:        goto yy7;
+       }
+yy2:
+       { return (size_t)( c - start ); }
+yy3:
+       yych = *++c;
+       goto yy11;
+yy4:
+       ++c;
+       yych = *c;
+yy5:
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy4;
+       default:        goto yy2;
+       }
+yy6:
+       yych = *++c;
+       switch (yych) {
+       case '\n':      goto yy4;
+       default:        goto yy5;
+       }
+yy7:
+       ++c;
+       { return 0; }
+yy9:
+       yych = *++c;
+       switch (yych) {
+       case '\n':      goto yy4;
+       default:        goto yy5;
+       }
+yy10:
+       ++c;
+       yych = *c;
+yy11:
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy10;
+       case '\n':      goto yy4;
+       case '\r':      goto yy9;
+       default:        goto yy2;
+       }
+}
+       
+}
+
+
+size_t scan_key(const char * c) {
+       const char * start = c;
+
+
+{
+       char yych;
+       yych = *c;
+       switch (yych) {
+       case '\n':      goto yy14;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy15;
+       default:        goto yy17;
+       }
+yy14:
+       { return 0; }
+yy15:
+       ++c;
+       yych = *c;
+       goto yy19;
+yy16:
+       { return (size_t)( c - start ); }
+yy17:
+       yych = *++c;
+       goto yy14;
+yy18:
+       ++c;
+       yych = *c;
+yy19:
+       switch (yych) {
+       case '-':
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy18;
+       default:        goto yy16;
+       }
+}
+       
+}
+
+
+size_t scan_value(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       yych = *c;
+       switch (yych) {
+       case '\n':      goto yy22;
+       case '"':       goto yy23;
+       case '\'':      goto yy24;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy25;
+       default:        goto yy27;
+       }
+yy22:
+       { return 0; }
+yy23:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy22;
+       default:        goto yy35;
+       }
+yy24:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy22;
+       default:        goto yy31;
+       }
+yy25:
+       ++c;
+       yych = *c;
+       goto yy29;
+yy26:
+       { return (size_t)( c - start ); }
+yy27:
+       yych = *++c;
+       goto yy22;
+yy28:
+       ++c;
+       yych = *c;
+yy29:
+       switch (yych) {
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy28;
+       default:        goto yy26;
+       }
+yy30:
+       ++c;
+       yych = *c;
+yy31:
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy32;
+       case '\'':      goto yy33;
+       default:        goto yy30;
+       }
+yy32:
+       c = marker;
+       goto yy22;
+yy33:
+       yych = *++c;
+       goto yy26;
+yy34:
+       ++c;
+       yych = *c;
+yy35:
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy32;
+       case '"':       goto yy33;
+       default:        goto yy34;
+       }
+}
+       
+}
+
+
+size_t scan_attr(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       yych = *(marker = c);
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy39;
+       case '\n':      goto yy40;
+       case '\r':      goto yy43;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy44;
+       default:        goto yy45;
+       }
+yy38:
+       { return 0; }
+yy39:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy60;
+       default:        goto yy38;
+       }
+yy40:
+       ++c;
+       yych = *c;
+yy41:
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy40;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy46;
+       default:        goto yy42;
+       }
+yy42:
+       c = marker;
+       goto yy38;
+yy43:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case ' ':       goto yy40;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy46;
+       default:        goto yy38;
+       }
+yy44:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '-':
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy46;
+       case '=':       goto yy48;
+       default:        goto yy38;
+       }
+yy45:
+       yych = *++c;
+       goto yy38;
+yy46:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '-':
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy46;
+       case '=':       goto yy48;
+       default:        goto yy42;
+       }
+yy48:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy48;
+       case '"':       goto yy50;
+       case '\'':      goto yy52;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy54;
+       default:        goto yy42;
+       }
+yy50:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy42;
+       case '"':       goto yy57;
+       default:        goto yy50;
+       }
+yy52:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy42;
+       case '\'':      goto yy57;
+       default:        goto yy52;
+       }
+yy54:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy54;
+       default:        goto yy56;
+       }
+yy56:
+       { return (size_t)( c - start ); }
+yy57:
+       yych = *++c;
+       goto yy56;
+yy58:
+       yych = *++c;
+       switch (yych) {
+       case '\n':      goto yy40;
+       default:        goto yy41;
+       }
+yy59:
+       ++c;
+       yych = *c;
+yy60:
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy59;
+       case '\n':      goto yy40;
+       case '\r':      goto yy58;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy46;
+       default:        goto yy42;
+       }
+}
+       
+}
+
+
+size_t scan_attributes(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       unsigned int yyaccept = 0;
+       yych = *(marker = c);
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy64;
+       case '\n':      goto yy65;
+       case '\r':      goto yy68;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy69;
+       default:        goto yy70;
+       }
+yy63:
+       { return 0; }
+yy64:
+       yyaccept = 0;
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy83;
+       default:        goto yy63;
+       }
+yy65:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy65;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy71;
+       default:        goto yy67;
+       }
+yy67:
+       c = marker;
+       if (yyaccept == 0) {
+               goto yy63;
+       } else {
+               goto yy81;
+       }
+yy68:
+       yyaccept = 0;
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case ' ':       goto yy65;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy71;
+       default:        goto yy63;
+       }
+yy69:
+       yyaccept = 0;
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '-':
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy71;
+       case '=':       goto yy73;
+       default:        goto yy63;
+       }
+yy70:
+       yych = *++c;
+       goto yy63;
+yy71:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '-':
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy71;
+       case '=':       goto yy73;
+       default:        goto yy67;
+       }
+yy73:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy73;
+       case '"':       goto yy75;
+       case '\'':      goto yy77;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy79;
+       default:        goto yy67;
+       }
+yy75:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy67;
+       case '"':       goto yy87;
+       default:        goto yy75;
+       }
+yy77:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy67;
+       case '\'':      goto yy87;
+       default:        goto yy77;
+       }
+yy79:
+       yyaccept = 1;
+       marker = ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy82;
+       case '\n':      goto yy65;
+       case '\r':      goto yy84;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy79;
+       case ':':
+       case '_':       goto yy71;
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy85;
+       default:        goto yy81;
+       }
+yy81:
+       { return (size_t)( c - start ); }
+yy82:
+       ++c;
+       yych = *c;
+yy83:
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy82;
+       case '\n':      goto yy65;
+       case '\r':      goto yy84;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy71;
+       default:        goto yy67;
+       }
+yy84:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case ' ':       goto yy65;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy71;
+       default:        goto yy67;
+       }
+yy85:
+       yyaccept = 1;
+       marker = ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy82;
+       case '\n':      goto yy65;
+       case '\r':      goto yy84;
+       case '-':
+       case ':':
+       case '_':       goto yy71;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy85;
+       case '=':       goto yy73;
+       default:        goto yy81;
+       }
+yy87:
+       yyaccept = 1;
+       marker = ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy82;
+       case '\n':      goto yy65;
+       case '\r':      goto yy84;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy71;
+       default:        goto yy81;
+       }
+}
+       
+}
+
+
+size_t scan_email(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       yych = *c;
+       switch (yych) {
+       case '\n':      goto yy90;
+       case '!':
+       case '$':
+       case '%':
+       case '+':
+       case '-':
+       case '.':
+       case '/':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':
+       case '~':       goto yy92;
+       case 'M':
+       case 'm':       goto yy91;
+       default:        goto yy93;
+       }
+yy90:
+       { return 0; }
+yy91:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '!':
+       case '$':
+       case '%':
+       case '+':
+       case '-':
+       case '.':
+       case '/':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':
+       case '~':       goto yy96;
+       case '@':       goto yy94;
+       case 'A':
+       case 'a':       goto yy101;
+       default:        goto yy90;
+       }
+yy92:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '!':
+       case '$':
+       case '%':
+       case '+':
+       case '-':
+       case '.':
+       case '/':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case '@':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':
+       case '~':       goto yy97;
+       default:        goto yy90;
+       }
+yy93:
+       yych = *++c;
+       goto yy90;
+yy94:
+       yych = *++c;
+       switch (yych) {
+       case 0x00:
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':
+       case '>':       goto yy95;
+       default:        goto yy98;
+       }
+yy95:
+       c = marker;
+       goto yy90;
+yy96:
+       ++c;
+       yych = *c;
+yy97:
+       switch (yych) {
+       case '!':
+       case '$':
+       case '%':
+       case '+':
+       case '-':
+       case '.':
+       case '/':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':
+       case '~':       goto yy96;
+       case '@':       goto yy94;
+       default:        goto yy95;
+       }
+yy98:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':
+       case '>':       goto yy100;
+       default:        goto yy98;
+       }
+yy100:
+       { return (size_t)( c - start ); }
+yy101:
+       yych = *++c;
+       switch (yych) {
+       case 'I':
+       case 'i':       goto yy102;
+       default:        goto yy97;
+       }
+yy102:
+       yych = *++c;
+       switch (yych) {
+       case 'L':
+       case 'l':       goto yy103;
+       default:        goto yy97;
+       }
+yy103:
+       yych = *++c;
+       switch (yych) {
+       case 'T':
+       case 't':       goto yy104;
+       default:        goto yy97;
+       }
+yy104:
+       yych = *++c;
+       switch (yych) {
+       case 'O':
+       case 'o':       goto yy105;
+       default:        goto yy97;
+       }
+yy105:
+       yych = *++c;
+       switch (yych) {
+       case ':':       goto yy106;
+       default:        goto yy97;
+       }
+yy106:
+       ++c;
+       switch ((yych = *c)) {
+       case '@':       goto yy95;
+       default:        goto yy97;
+       }
+}
+       
+}
+
+
+size_t scan_url(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       yych = *c;
+       switch (yych) {
+       case '\n':      goto yy109;
+       case '!':
+       case '$':
+       case '%':
+       case '+':
+       case '.':
+       case '/':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case '_':
+       case '~':       goto yy111;
+       case '-':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy112;
+       case 'M':
+       case 'm':       goto yy110;
+       default:        goto yy113;
+       }
+yy109:
+       { return 0; }
+yy110:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '!':
+       case '$':
+       case '%':
+       case '+':
+       case '.':
+       case '/':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case '_':
+       case '~':       goto yy119;
+       case '-':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy116;
+       case ':':       goto yy114;
+       case '@':       goto yy118;
+       case 'A':
+       case 'a':       goto yy129;
+       default:        goto yy109;
+       }
+yy111:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '!':
+       case '$':
+       case '%':
+       case '+':
+       case '-':
+       case '.':
+       case '/':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case '@':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':
+       case '~':       goto yy120;
+       default:        goto yy109;
+       }
+yy112:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '!':
+       case '$':
+       case '%':
+       case '+':
+       case '.':
+       case '/':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case '_':
+       case '~':       goto yy119;
+       case '-':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy116;
+       case ':':       goto yy114;
+       case '@':       goto yy118;
+       default:        goto yy109;
+       }
+yy113:
+       yych = *++c;
+       goto yy109;
+yy114:
+       yych = *++c;
+       switch (yych) {
+       case '/':       goto yy124;
+       default:        goto yy115;
+       }
+yy115:
+       c = marker;
+       goto yy109;
+yy116:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '!':
+       case '$':
+       case '%':
+       case '+':
+       case '.':
+       case '/':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case '_':
+       case '~':       goto yy119;
+       case '-':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy116;
+       case ':':       goto yy114;
+       case '@':       goto yy118;
+       default:        goto yy115;
+       }
+yy118:
+       yych = *++c;
+       switch (yych) {
+       case 0x00:
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':
+       case '>':       goto yy115;
+       default:        goto yy121;
+       }
+yy119:
+       ++c;
+       yych = *c;
+yy120:
+       switch (yych) {
+       case '!':
+       case '$':
+       case '%':
+       case '+':
+       case '-':
+       case '.':
+       case '/':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':
+       case '~':       goto yy119;
+       case '@':       goto yy118;
+       default:        goto yy115;
+       }
+yy121:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':
+       case '>':       goto yy123;
+       default:        goto yy121;
+       }
+yy123:
+       { return (size_t)( c - start ); }
+yy124:
+       yych = *++c;
+       switch (yych) {
+       case '/':       goto yy125;
+       default:        goto yy115;
+       }
+yy125:
+       yych = *++c;
+       switch (yych) {
+       case 0x00:
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':
+       case '>':       goto yy115;
+       default:        goto yy126;
+       }
+yy126:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':
+       case '>':       goto yy128;
+       default:        goto yy126;
+       }
+yy128:
+       { return (size_t)( c - start ); }
+yy129:
+       yych = *++c;
+       switch (yych) {
+       case '-':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy116;
+       case ':':       goto yy114;
+       case 'I':
+       case 'i':       goto yy130;
+       default:        goto yy120;
+       }
+yy130:
+       yych = *++c;
+       switch (yych) {
+       case '-':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy116;
+       case ':':       goto yy114;
+       case 'L':
+       case 'l':       goto yy131;
+       default:        goto yy120;
+       }
+yy131:
+       yych = *++c;
+       switch (yych) {
+       case '-':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy116;
+       case ':':       goto yy114;
+       case 'T':
+       case 't':       goto yy132;
+       default:        goto yy120;
+       }
+yy132:
+       yych = *++c;
+       switch (yych) {
+       case '-':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy116;
+       case ':':       goto yy114;
+       case 'O':
+       case 'o':       goto yy133;
+       default:        goto yy120;
+       }
+yy133:
+       yych = *++c;
+       switch (yych) {
+       case '-':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy116;
+       case ':':       goto yy134;
+       default:        goto yy120;
+       }
+yy134:
+       yych = *++c;
+       switch (yych) {
+       case '/':       goto yy135;
+       case '@':       goto yy115;
+       default:        goto yy120;
+       }
+yy135:
+       yych = *++c;
+       switch (yych) {
+       case '/':       goto yy136;
+       default:        goto yy120;
+       }
+yy136:
+       yych = *++c;
+       switch (yych) {
+       case 0x00:
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':
+       case '>':       goto yy115;
+       case '!':
+       case '$':
+       case '%':
+       case '+':
+       case '-':
+       case '.':
+       case '/':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':
+       case '~':       goto yy137;
+       case '@':       goto yy139;
+       default:        goto yy126;
+       }
+yy137:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':
+       case '>':       goto yy128;
+       case '!':
+       case '$':
+       case '%':
+       case '+':
+       case '-':
+       case '.':
+       case '/':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':
+       case '~':       goto yy137;
+       case '@':       goto yy139;
+       default:        goto yy126;
+       }
+yy139:
+       yych = *++c;
+       switch (yych) {
+       case 0x00:
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':
+       case '>':       goto yy128;
+       default:        goto yy140;
+       }
+yy140:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\t':
+       case '\n':
+       case '\r':
+       case ' ':
+       case '>':       goto yy123;
+       default:        goto yy140;
+       }
+}
+       
+}
+
+
+size_t scan_ref_citation(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       yych = *c;
+       switch (yych) {
+       case '\n':      goto yy144;
+       case ' ':       goto yy145;
+       case '[':       goto yy146;
+       default:        goto yy147;
+       }
+yy144:
+       { return 0; }
+yy145:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case ' ':       goto yy157;
+       case '[':       goto yy158;
+       default:        goto yy144;
+       }
+yy146:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '#':       goto yy148;
+       default:        goto yy144;
+       }
+yy147:
+       yych = *++c;
+       goto yy144;
+yy148:
+       yych = *++c;
+       switch (yych) {
+       case ']':       goto yy149;
+       default:        goto yy151;
+       }
+yy149:
+       c = marker;
+       goto yy144;
+yy150:
+       ++c;
+       yych = *c;
+yy151:
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy149;
+       case ']':       goto yy152;
+       default:        goto yy150;
+       }
+yy152:
+       yych = *++c;
+       switch (yych) {
+       case ':':       goto yy153;
+       default:        goto yy149;
+       }
+yy153:
+       yych = *++c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy149;
+       default:        goto yy154;
+       }
+yy154:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy156;
+       default:        goto yy154;
+       }
+yy156:
+       { return (size_t)( c - start ); }
+yy157:
+       yych = *++c;
+       switch (yych) {
+       case ' ':       goto yy159;
+       case '[':       goto yy158;
+       default:        goto yy149;
+       }
+yy158:
+       yych = *++c;
+       switch (yych) {
+       case '#':       goto yy148;
+       default:        goto yy149;
+       }
+yy159:
+       ++c;
+       switch ((yych = *c)) {
+       case '[':       goto yy158;
+       default:        goto yy149;
+       }
+}
+       
+}
+
+size_t scan_ref_foot(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       yych = *c;
+       switch (yych) {
+       case '\n':      goto yy162;
+       case ' ':       goto yy163;
+       case '[':       goto yy164;
+       default:        goto yy165;
+       }
+yy162:
+       { return 0; }
+yy163:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case ' ':       goto yy175;
+       case '[':       goto yy176;
+       default:        goto yy162;
+       }
+yy164:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '^':       goto yy166;
+       default:        goto yy162;
+       }
+yy165:
+       yych = *++c;
+       goto yy162;
+yy166:
+       yych = *++c;
+       switch (yych) {
+       case ']':       goto yy167;
+       default:        goto yy169;
+       }
+yy167:
+       c = marker;
+       goto yy162;
+yy168:
+       ++c;
+       yych = *c;
+yy169:
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy167;
+       case ']':       goto yy170;
+       default:        goto yy168;
+       }
+yy170:
+       yych = *++c;
+       switch (yych) {
+       case ':':       goto yy171;
+       default:        goto yy167;
+       }
+yy171:
+       yych = *++c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy167;
+       default:        goto yy172;
+       }
+yy172:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy174;
+       default:        goto yy172;
+       }
+yy174:
+       { return (size_t)( c - start ); }
+yy175:
+       yych = *++c;
+       switch (yych) {
+       case ' ':       goto yy177;
+       case '[':       goto yy176;
+       default:        goto yy167;
+       }
+yy176:
+       yych = *++c;
+       switch (yych) {
+       case '^':       goto yy166;
+       default:        goto yy167;
+       }
+yy177:
+       ++c;
+       switch ((yych = *c)) {
+       case '[':       goto yy176;
+       default:        goto yy167;
+       }
+}
+       
+}
+
+
+size_t scan_ref_link_no_attributes(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       unsigned int yyaccept = 0;
+       yych = *c;
+       switch (yych) {
+       case '\n':      goto yy180;
+       case ' ':       goto yy181;
+       case '[':       goto yy182;
+       default:        goto yy183;
+       }
+yy180:
+       { return 0; }
+yy181:
+       yyaccept = 0;
+       yych = *(marker = ++c);
+       switch (yych) {
+       case ' ':       goto yy317;
+       case '[':       goto yy318;
+       default:        goto yy180;
+       }
+yy182:
+       yyaccept = 0;
+       yych = *(marker = ++c);
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':
+       case ']':       goto yy180;
+       default:        goto yy184;
+       }
+yy183:
+       yych = *++c;
+       goto yy180;
+yy184:
+       ++c;
+       yych = *c;
+yy185:
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy186;
+       case ']':       goto yy187;
+       default:        goto yy184;
+       }
+yy186:
+       c = marker;
+       if (yyaccept == 0) {
+               goto yy180;
+       } else {
+               goto yy200;
+       }
+yy187:
+       yych = *++c;
+       switch (yych) {
+       case ':':       goto yy188;
+       default:        goto yy186;
+       }
+yy188:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy188;
+       case '\n':      goto yy190;
+       case '\r':      goto yy192;
+       case '<':       goto yy193;
+       default:        goto yy195;
+       }
+yy190:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy186;
+       case '\t':
+       case ' ':       goto yy190;
+       case '<':       goto yy193;
+       default:        goto yy195;
+       }
+yy192:
+       yych = *++c;
+       switch (yych) {
+       case 0x00:
+       case '\r':      goto yy186;
+       case '\t':
+       case '\n':
+       case ' ':       goto yy190;
+       case '<':       goto yy193;
+       default:        goto yy195;
+       }
+yy193:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy197;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy290;
+       case '\'':      goto yy292;
+       case '(':       goto yy294;
+       case '>':       goto yy195;
+       default:        goto yy193;
+       }
+yy195:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy197;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy202;
+       case '\'':      goto yy204;
+       case '(':       goto yy206;
+       default:        goto yy195;
+       }
+yy197:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy197;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy218;
+       case '\'':      goto yy220;
+       case '(':       goto yy222;
+       default:        goto yy186;
+       }
+yy199:
+       yyaccept = 1;
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '"':       goto yy218;
+       case '\'':      goto yy220;
+       case '(':       goto yy222;
+       default:        goto yy200;
+       }
+yy200:
+       { return (size_t)( c - start ); }
+yy201:
+       yyaccept = 1;
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '\n':      goto yy199;
+       case '"':       goto yy218;
+       case '\'':      goto yy220;
+       case '(':       goto yy222;
+       default:        goto yy200;
+       }
+yy202:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy288;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy276;
+       case '\'':      goto yy266;
+       case '(':       goto yy210;
+       default:        goto yy202;
+       }
+yy204:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy286;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy266;
+       case '\'':      goto yy228;
+       case '(':       goto yy212;
+       default:        goto yy204;
+       }
+yy206:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy208;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy210;
+       case '\'':      goto yy212;
+       case ')':       goto yy214;
+       default:        goto yy206;
+       }
+yy208:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy208;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy256;
+       case '\'':      goto yy240;
+       case ')':       goto yy224;
+       default:        goto yy222;
+       }
+yy210:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy278;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy280;
+       case '\'':      goto yy232;
+       case ')':       goto yy276;
+       default:        goto yy210;
+       }
+yy212:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy230;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy232;
+       case '\'':      goto yy234;
+       case ')':       goto yy228;
+       default:        goto yy212;
+       }
+yy214:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy215;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy202;
+       case '\'':      goto yy204;
+       case '(':       goto yy206;
+       default:        goto yy195;
+       }
+yy215:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy215;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy218;
+       case '\'':      goto yy220;
+       case '(':       goto yy222;
+       default:        goto yy186;
+       }
+yy217:
+       yyaccept = 1;
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '\n':      goto yy199;
+       case '"':       goto yy218;
+       case '\'':      goto yy220;
+       case '(':       goto yy222;
+       default:        goto yy200;
+       }
+yy218:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy186;
+       case '"':       goto yy224;
+       default:        goto yy218;
+       }
+yy220:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy186;
+       case '\'':      goto yy224;
+       default:        goto yy220;
+       }
+yy222:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy186;
+       case ')':       goto yy224;
+       default:        goto yy222;
+       }
+yy224:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy224;
+       case '\n':      goto yy226;
+       case '\r':      goto yy227;
+       default:        goto yy186;
+       }
+yy226:
+       yych = *++c;
+       goto yy200;
+yy227:
+       yych = *++c;
+       switch (yych) {
+       case '\n':      goto yy226;
+       default:        goto yy200;
+       }
+yy228:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy274;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy266;
+       case '\'':      goto yy228;
+       case '(':       goto yy212;
+       default:        goto yy204;
+       }
+yy230:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy230;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy242;
+       case '\'':      goto yy244;
+       case ')':       goto yy238;
+       default:        goto yy240;
+       }
+yy232:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy260;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':
+       case '\'':      goto yy258;
+       case ')':       goto yy262;
+       default:        goto yy232;
+       }
+yy234:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy236;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy232;
+       case '\'':      goto yy234;
+       case ')':       goto yy228;
+       default:        goto yy212;
+       }
+yy236:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy236;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy242;
+       case '\'':      goto yy244;
+       case ')':       goto yy238;
+       default:        goto yy240;
+       }
+yy238:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy238;
+       case '\n':      goto yy226;
+       case '\r':      goto yy227;
+       case '\'':      goto yy224;
+       default:        goto yy220;
+       }
+yy240:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy186;
+       case '\'':      goto yy246;
+       case ')':       goto yy238;
+       default:        goto yy240;
+       }
+yy242:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy186;
+       case '"':       goto yy244;
+       case '\'':      goto yy248;
+       case ')':       goto yy250;
+       default:        goto yy242;
+       }
+yy244:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy244;
+       case '\n':      goto yy226;
+       case '\r':      goto yy227;
+       case '\'':      goto yy246;
+       case ')':       goto yy238;
+       default:        goto yy240;
+       }
+yy246:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy246;
+       case '\n':      goto yy226;
+       case '\r':      goto yy227;
+       case ')':       goto yy224;
+       default:        goto yy222;
+       }
+yy248:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy248;
+       case '\n':      goto yy226;
+       case '\r':      goto yy227;
+       case '"':       goto yy246;
+       case ')':       goto yy252;
+       default:        goto yy256;
+       }
+yy250:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy250;
+       case '\n':      goto yy226;
+       case '\r':      goto yy227;
+       case '"':       goto yy238;
+       case '\'':      goto yy252;
+       default:        goto yy254;
+       }
+yy252:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy252;
+       case '\n':      goto yy226;
+       case '\r':      goto yy227;
+       case '"':       goto yy224;
+       default:        goto yy218;
+       }
+yy254:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy186;
+       case '"':       goto yy238;
+       case '\'':      goto yy252;
+       default:        goto yy254;
+       }
+yy256:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy186;
+       case '"':       goto yy246;
+       case ')':       goto yy252;
+       default:        goto yy256;
+       }
+yy258:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy272;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':
+       case '\'':      goto yy258;
+       case ')':       goto yy262;
+       default:        goto yy232;
+       }
+yy260:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy260;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':
+       case '\'':      goto yy270;
+       case ')':       goto yy250;
+       default:        goto yy242;
+       }
+yy262:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy264;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':
+       case '\'':      goto yy262;
+       case '(':       goto yy232;
+       default:        goto yy266;
+       }
+yy264:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy264;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':
+       case '\'':      goto yy250;
+       case '(':       goto yy242;
+       default:        goto yy254;
+       }
+yy266:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy268;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':
+       case '\'':      goto yy262;
+       case '(':       goto yy232;
+       default:        goto yy266;
+       }
+yy268:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy268;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':
+       case '\'':      goto yy250;
+       case '(':       goto yy242;
+       default:        goto yy254;
+       }
+yy270:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy270;
+       case '\n':      goto yy226;
+       case '\r':      goto yy227;
+       case '"':       goto yy244;
+       case '\'':      goto yy248;
+       case ')':       goto yy250;
+       default:        goto yy242;
+       }
+yy272:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy272;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':
+       case '\'':      goto yy270;
+       case ')':       goto yy250;
+       default:        goto yy242;
+       }
+yy274:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy274;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy254;
+       case '\'':      goto yy238;
+       case '(':       goto yy240;
+       default:        goto yy220;
+       }
+yy276:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy284;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy276;
+       case '\'':      goto yy266;
+       case '(':       goto yy210;
+       default:        goto yy202;
+       }
+yy278:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy278;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy248;
+       case '\'':      goto yy242;
+       case ')':       goto yy252;
+       default:        goto yy256;
+       }
+yy280:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy282;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy280;
+       case '\'':      goto yy232;
+       case ')':       goto yy276;
+       default:        goto yy210;
+       }
+yy282:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy282;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy248;
+       case '\'':      goto yy242;
+       case ')':       goto yy252;
+       default:        goto yy256;
+       }
+yy284:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy284;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy252;
+       case '\'':      goto yy254;
+       case '(':       goto yy256;
+       default:        goto yy218;
+       }
+yy286:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy286;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy254;
+       case '\'':      goto yy238;
+       case '(':       goto yy240;
+       default:        goto yy220;
+       }
+yy288:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy288;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy252;
+       case '\'':      goto yy254;
+       case '(':       goto yy256;
+       default:        goto yy218;
+       }
+yy290:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy288;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy313;
+       case '\'':      goto yy311;
+       case '(':       goto yy296;
+       case '>':       goto yy202;
+       default:        goto yy290;
+       }
+yy292:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy286;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy311;
+       case '\'':      goto yy301;
+       case '(':       goto yy298;
+       case '>':       goto yy204;
+       default:        goto yy292;
+       }
+yy294:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy208;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy296;
+       case '\'':      goto yy298;
+       case ')':       goto yy300;
+       case '>':       goto yy206;
+       default:        goto yy294;
+       }
+yy296:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy278;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy315;
+       case '\'':      goto yy303;
+       case ')':       goto yy313;
+       case '>':       goto yy210;
+       default:        goto yy296;
+       }
+yy298:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy230;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':       goto yy303;
+       case '\'':      goto yy305;
+       case ')':       goto yy301;
+       case '>':       goto yy212;
+       default:        goto yy298;
+       }
+yy300:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy215;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy290;
+       case '\'':      goto yy292;
+       case '(':       goto yy294;
+       case '>':       goto yy195;
+       default:        goto yy193;
+       }
+yy301:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy274;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy311;
+       case '\'':      goto yy301;
+       case '(':       goto yy298;
+       case '>':       goto yy204;
+       default:        goto yy292;
+       }
+yy303:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy260;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':
+       case '\'':      goto yy307;
+       case ')':       goto yy309;
+       case '>':       goto yy232;
+       default:        goto yy303;
+       }
+yy305:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy236;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy303;
+       case '\'':      goto yy305;
+       case ')':       goto yy301;
+       case '>':       goto yy212;
+       default:        goto yy298;
+       }
+yy307:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy272;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':
+       case '\'':      goto yy307;
+       case ')':       goto yy309;
+       case '>':       goto yy232;
+       default:        goto yy303;
+       }
+yy309:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy264;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':
+       case '\'':      goto yy309;
+       case '(':       goto yy303;
+       case '>':       goto yy266;
+       default:        goto yy311;
+       }
+yy311:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy268;
+       case '\n':      goto yy199;
+       case '\r':      goto yy201;
+       case '"':
+       case '\'':      goto yy309;
+       case '(':       goto yy303;
+       case '>':       goto yy266;
+       default:        goto yy311;
+       }
+yy313:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy284;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy313;
+       case '\'':      goto yy311;
+       case '(':       goto yy296;
+       case '>':       goto yy202;
+       default:        goto yy290;
+       }
+yy315:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy186;
+       case '\t':
+       case ' ':       goto yy282;
+       case '\n':      goto yy199;
+       case '\r':      goto yy217;
+       case '"':       goto yy315;
+       case '\'':      goto yy303;
+       case ')':       goto yy313;
+       case '>':       goto yy210;
+       default:        goto yy296;
+       }
+yy317:
+       yych = *++c;
+       switch (yych) {
+       case ' ':       goto yy319;
+       case '[':       goto yy318;
+       default:        goto yy186;
+       }
+yy318:
+       yych = *++c;
+       switch (yych) {
+       case ']':       goto yy186;
+       default:        goto yy185;
+       }
+yy319:
+       ++c;
+       switch ((yych = *c)) {
+       case '[':       goto yy318;
+       default:        goto yy186;
+       }
+}
+       
+}
+
+
+size_t scan_ref_link(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       yych = *c;
+       switch (yych) {
+       case '\n':      goto yy322;
+       case ' ':       goto yy323;
+       case '[':       goto yy324;
+       default:        goto yy325;
+       }
+yy322:
+       { return 0; }
+yy323:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case ' ':       goto yy334;
+       case '[':       goto yy335;
+       default:        goto yy322;
+       }
+yy324:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':
+       case ']':       goto yy322;
+       default:        goto yy326;
+       }
+yy325:
+       yych = *++c;
+       goto yy322;
+yy326:
+       ++c;
+       yych = *c;
+yy327:
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy328;
+       case ']':       goto yy329;
+       default:        goto yy326;
+       }
+yy328:
+       c = marker;
+       goto yy322;
+yy329:
+       yych = *++c;
+       switch (yych) {
+       case ':':       goto yy330;
+       default:        goto yy328;
+       }
+yy330:
+       yych = *++c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy328;
+       default:        goto yy331;
+       }
+yy331:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy333;
+       default:        goto yy331;
+       }
+yy333:
+       { return (size_t)( c - start ); }
+yy334:
+       yych = *++c;
+       switch (yych) {
+       case ' ':       goto yy336;
+       case '[':       goto yy335;
+       default:        goto yy328;
+       }
+yy335:
+       yych = *++c;
+       switch (yych) {
+       case ']':       goto yy328;
+       default:        goto yy327;
+       }
+yy336:
+       ++c;
+       switch ((yych = *c)) {
+       case '[':       goto yy335;
+       default:        goto yy328;
+       }
+}
+       
+}
+
+
+size_t scan_html(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       yych = *c;
+       switch (yych) {
+       case '\n':      goto yy339;
+       case '<':       goto yy340;
+       default:        goto yy341;
+       }
+yy339:
+       { return 0; }
+yy340:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '!':       goto yy342;
+       case '/':       goto yy344;
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy345;
+       default:        goto yy339;
+       }
+yy341:
+       yych = *++c;
+       goto yy339;
+yy342:
+       yych = *++c;
+       switch (yych) {
+       case '-':       goto yy373;
+       default:        goto yy343;
+       }
+yy343:
+       c = marker;
+       goto yy339;
+yy344:
+       yych = *++c;
+       switch (yych) {
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy369;
+       default:        goto yy343;
+       }
+yy345:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy349;
+       case '\n':      goto yy351;
+       case '\r':      goto yy353;
+       case '-':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy345;
+       case '/':       goto yy358;
+       case ':':
+       case '_':       goto yy354;
+       case '>':       goto yy356;
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy347;
+       default:        goto yy343;
+       }
+yy347:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy349;
+       case '\n':      goto yy351;
+       case '\r':      goto yy353;
+       case '-':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy347;
+       case '.':
+       case ':':
+       case '_':       goto yy354;
+       case '/':       goto yy358;
+       case '=':       goto yy359;
+       case '>':       goto yy356;
+       default:        goto yy343;
+       }
+yy349:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy349;
+       case '\n':      goto yy351;
+       case '\r':      goto yy353;
+       case '/':       goto yy358;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy354;
+       case '>':       goto yy356;
+       default:        goto yy343;
+       }
+yy351:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy351;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy354;
+       default:        goto yy343;
+       }
+yy353:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case ' ':       goto yy351;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy354;
+       default:        goto yy343;
+       }
+yy354:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '-':
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy354;
+       case '=':       goto yy359;
+       default:        goto yy343;
+       }
+yy356:
+       ++c;
+       { return (size_t)( c - start ); }
+yy358:
+       yych = *++c;
+       switch (yych) {
+       case '>':       goto yy356;
+       default:        goto yy343;
+       }
+yy359:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy359;
+       case '"':       goto yy361;
+       case '\'':      goto yy363;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy365;
+       default:        goto yy343;
+       }
+yy361:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy343;
+       case '"':       goto yy349;
+       default:        goto yy361;
+       }
+yy363:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy343;
+       case '\'':      goto yy349;
+       default:        goto yy363;
+       }
+yy365:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy349;
+       case '\n':      goto yy351;
+       case '\r':      goto yy353;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy365;
+       case '/':       goto yy358;
+       case ':':
+       case '_':       goto yy354;
+       case '>':       goto yy356;
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy367;
+       default:        goto yy343;
+       }
+yy367:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy349;
+       case '\n':      goto yy351;
+       case '\r':      goto yy353;
+       case '-':
+       case ':':
+       case '_':       goto yy354;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy367;
+       case '/':       goto yy358;
+       case '=':       goto yy359;
+       case '>':       goto yy356;
+       default:        goto yy343;
+       }
+yy369:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy371;
+       case '-':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy369;
+       case '>':       goto yy356;
+       default:        goto yy343;
+       }
+yy371:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy371;
+       case '>':       goto yy356;
+       default:        goto yy343;
+       }
+yy373:
+       yych = *++c;
+       switch (yych) {
+       case '-':       goto yy374;
+       default:        goto yy343;
+       }
+yy374:
+       yych = *++c;
+       switch (yych) {
+       case '-':       goto yy343;
+       default:        goto yy376;
+       }
+yy375:
+       ++c;
+       yych = *c;
+yy376:
+       switch (yych) {
+       case 0x00:
+       case '>':       goto yy343;
+       case '-':       goto yy377;
+       default:        goto yy375;
+       }
+yy377:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '>':       goto yy343;
+       case '-':       goto yy378;
+       default:        goto yy375;
+       }
+yy378:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy343;
+       case '-':       goto yy378;
+       case '>':       goto yy356;
+       default:        goto yy375;
+       }
+}
+       
+}
+
+
+size_t scan_html_block(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       yych = *c;
+       switch (yych) {
+       case '\n':      goto yy382;
+       case '<':       goto yy383;
+       default:        goto yy384;
+       }
+yy382:
+       { return 0; }
+yy383:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '/':       goto yy385;
+       case 'A':
+       case 'a':       goto yy388;
+       case 'B':
+       case 'b':       goto yy389;
+       case 'C':
+       case 'c':       goto yy390;
+       case 'D':
+       case 'd':       goto yy391;
+       case 'F':
+       case 'f':       goto yy392;
+       case 'H':
+       case 'h':       goto yy393;
+       case 'I':
+       case 'i':       goto yy394;
+       case 'L':
+       case 'l':       goto yy395;
+       case 'M':
+       case 'm':       goto yy396;
+       case 'N':
+       case 'n':       goto yy397;
+       case 'O':
+       case 'o':       goto yy398;
+       case 'P':
+       case 'p':       goto yy387;
+       case 'S':
+       case 's':       goto yy399;
+       case 'T':
+       case 't':       goto yy400;
+       case 'U':
+       case 'u':       goto yy401;
+       case 'V':
+       case 'v':       goto yy402;
+       default:        goto yy382;
+       }
+yy384:
+       yych = *++c;
+       goto yy382;
+yy385:
+       yych = *++c;
+       switch (yych) {
+       case 'A':
+       case 'a':       goto yy388;
+       case 'B':
+       case 'b':       goto yy389;
+       case 'C':
+       case 'c':       goto yy390;
+       case 'D':
+       case 'd':       goto yy391;
+       case 'F':
+       case 'f':       goto yy392;
+       case 'H':
+       case 'h':       goto yy393;
+       case 'I':
+       case 'i':       goto yy394;
+       case 'L':
+       case 'l':       goto yy395;
+       case 'M':
+       case 'm':       goto yy396;
+       case 'N':
+       case 'n':       goto yy397;
+       case 'O':
+       case 'o':       goto yy398;
+       case 'P':
+       case 'p':       goto yy387;
+       case 'S':
+       case 's':       goto yy399;
+       case 'T':
+       case 't':       goto yy400;
+       case 'U':
+       case 'u':       goto yy401;
+       case 'V':
+       case 'v':       goto yy402;
+       default:        goto yy386;
+       }
+yy386:
+       c = marker;
+       goto yy382;
+yy387:
+       yych = *++c;
+       switch (yych) {
+       case '/':       goto yy414;
+       case '>':       goto yy415;
+       case 'R':
+       case 'r':       goto yy534;
+       default:        goto yy408;
+       }
+yy388:
+       yych = *++c;
+       switch (yych) {
+       case 'D':
+       case 'd':       goto yy523;
+       case 'R':
+       case 'r':       goto yy522;
+       case 'S':
+       case 's':       goto yy521;
+       default:        goto yy386;
+       }
+yy389:
+       yych = *++c;
+       switch (yych) {
+       case 'L':
+       case 'l':       goto yy513;
+       default:        goto yy386;
+       }
+yy390:
+       yych = *++c;
+       switch (yych) {
+       case 'A':
+       case 'a':       goto yy506;
+       case 'E':
+       case 'e':       goto yy505;
+       default:        goto yy386;
+       }
+yy391:
+       yych = *++c;
+       switch (yych) {
+       case 'D':
+       case 'L':
+       case 'T':
+       case 'd':
+       case 'l':
+       case 't':       goto yy406;
+       case 'I':
+       case 'i':       goto yy504;
+       default:        goto yy386;
+       }
+yy392:
+       yych = *++c;
+       switch (yych) {
+       case 'I':
+       case 'i':       goto yy480;
+       case 'O':
+       case 'o':       goto yy479;
+       case 'R':
+       case 'r':       goto yy478;
+       default:        goto yy386;
+       }
+yy393:
+       yych = *++c;
+       switch (yych) {
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case 'R':
+       case 'r':       goto yy406;
+       case 'E':
+       case 'e':       goto yy471;
+       case 'G':
+       case 'g':       goto yy470;
+       default:        goto yy386;
+       }
+yy394:
+       yych = *++c;
+       switch (yych) {
+       case 'S':
+       case 's':       goto yy465;
+       default:        goto yy386;
+       }
+yy395:
+       yych = *++c;
+       switch (yych) {
+       case 'I':
+       case 'i':       goto yy406;
+       default:        goto yy386;
+       }
+yy396:
+       yych = *++c;
+       switch (yych) {
+       case 'A':
+       case 'a':       goto yy462;
+       case 'E':
+       case 'e':       goto yy461;
+       default:        goto yy386;
+       }
+yy397:
+       yych = *++c;
+       switch (yych) {
+       case 'A':
+       case 'a':       goto yy450;
+       case 'O':
+       case 'o':       goto yy449;
+       default:        goto yy386;
+       }
+yy398:
+       yych = *++c;
+       switch (yych) {
+       case 'L':
+       case 'l':       goto yy406;
+       case 'U':
+       case 'u':       goto yy445;
+       default:        goto yy386;
+       }
+yy399:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy440;
+       default:        goto yy386;
+       }
+yy400:
+       yych = *++c;
+       switch (yych) {
+       case 'A':
+       case 'a':       goto yy430;
+       case 'B':
+       case 'b':       goto yy429;
+       case 'D':
+       case 'R':
+       case 'd':
+       case 'r':       goto yy406;
+       case 'F':
+       case 'f':       goto yy428;
+       case 'H':
+       case 'h':       goto yy427;
+       default:        goto yy386;
+       }
+yy401:
+       yych = *++c;
+       switch (yych) {
+       case 'L':
+       case 'l':       goto yy406;
+       default:        goto yy386;
+       }
+yy402:
+       yych = *++c;
+       switch (yych) {
+       case 'I':
+       case 'i':       goto yy403;
+       default:        goto yy386;
+       }
+yy403:
+       yych = *++c;
+       switch (yych) {
+       case 'D':
+       case 'd':       goto yy404;
+       default:        goto yy386;
+       }
+yy404:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy405;
+       default:        goto yy386;
+       }
+yy405:
+       yych = *++c;
+       switch (yych) {
+       case 'O':
+       case 'o':       goto yy406;
+       default:        goto yy386;
+       }
+yy406:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy407;
+       case '\n':      goto yy409;
+       case '\r':      goto yy411;
+       case '/':       goto yy414;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy412;
+       case '>':       goto yy415;
+       default:        goto yy386;
+       }
+yy407:
+       ++c;
+       yych = *c;
+yy408:
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy407;
+       case '\n':      goto yy409;
+       case '\r':      goto yy411;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy412;
+       default:        goto yy386;
+       }
+yy409:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy409;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy412;
+       default:        goto yy386;
+       }
+yy411:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case ' ':       goto yy409;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy412;
+       default:        goto yy386;
+       }
+yy412:
+       ++c;
+       yych = *c;
+yy413:
+       switch (yych) {
+       case '-':
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy412;
+       case '=':       goto yy417;
+       default:        goto yy386;
+       }
+yy414:
+       yych = *++c;
+       switch (yych) {
+       case '>':       goto yy415;
+       default:        goto yy386;
+       }
+yy415:
+       ++c;
+       { return (size_t)( c - start ); }
+yy417:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy417;
+       case '"':       goto yy419;
+       case '\'':      goto yy421;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy423;
+       default:        goto yy386;
+       }
+yy419:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy386;
+       case '"':       goto yy406;
+       default:        goto yy419;
+       }
+yy421:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy386;
+       case '\'':      goto yy406;
+       default:        goto yy421;
+       }
+yy423:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy407;
+       case '\n':      goto yy409;
+       case '\r':      goto yy411;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy423;
+       case '/':       goto yy414;
+       case ':':
+       case '_':       goto yy412;
+       case '>':       goto yy415;
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy425;
+       default:        goto yy386;
+       }
+yy425:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy407;
+       case '\n':      goto yy409;
+       case '\r':      goto yy411;
+       case '-':
+       case ':':
+       case '_':       goto yy412;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy425;
+       case '/':       goto yy414;
+       case '=':       goto yy417;
+       case '>':       goto yy415;
+       default:        goto yy386;
+       }
+yy427:
+       yych = *++c;
+       switch (yych) {
+       case '/':       goto yy414;
+       case '>':       goto yy415;
+       case 'E':
+       case 'e':       goto yy437;
+       default:        goto yy408;
+       }
+yy428:
+       yych = *++c;
+       switch (yych) {
+       case 'O':
+       case 'o':       goto yy435;
+       default:        goto yy386;
+       }
+yy429:
+       yych = *++c;
+       switch (yych) {
+       case 'O':
+       case 'o':       goto yy433;
+       default:        goto yy386;
+       }
+yy430:
+       yych = *++c;
+       switch (yych) {
+       case 'B':
+       case 'b':       goto yy431;
+       default:        goto yy386;
+       }
+yy431:
+       yych = *++c;
+       switch (yych) {
+       case 'L':
+       case 'l':       goto yy432;
+       default:        goto yy386;
+       }
+yy432:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy406;
+       default:        goto yy386;
+       }
+yy433:
+       yych = *++c;
+       switch (yych) {
+       case 'D':
+       case 'd':       goto yy434;
+       default:        goto yy386;
+       }
+yy434:
+       yych = *++c;
+       switch (yych) {
+       case 'Y':
+       case 'y':       goto yy406;
+       default:        goto yy386;
+       }
+yy435:
+       yych = *++c;
+       switch (yych) {
+       case 'O':
+       case 'o':       goto yy436;
+       default:        goto yy386;
+       }
+yy436:
+       yych = *++c;
+       switch (yych) {
+       case 'T':
+       case 't':       goto yy406;
+       default:        goto yy386;
+       }
+yy437:
+       yych = *++c;
+       switch (yych) {
+       case 'A':
+       case 'a':       goto yy438;
+       default:        goto yy413;
+       }
+yy438:
+       yych = *++c;
+       switch (yych) {
+       case 'D':
+       case 'd':       goto yy439;
+       default:        goto yy413;
+       }
+yy439:
+       yych = *++c;
+       switch (yych) {
+       case '-':
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy412;
+       case '/':       goto yy414;
+       case '=':       goto yy417;
+       case '>':       goto yy415;
+       default:        goto yy408;
+       }
+yy440:
+       yych = *++c;
+       switch (yych) {
+       case 'C':
+       case 'c':       goto yy441;
+       default:        goto yy386;
+       }
+yy441:
+       yych = *++c;
+       switch (yych) {
+       case 'T':
+       case 't':       goto yy442;
+       default:        goto yy386;
+       }
+yy442:
+       yych = *++c;
+       switch (yych) {
+       case 'I':
+       case 'i':       goto yy443;
+       default:        goto yy386;
+       }
+yy443:
+       yych = *++c;
+       switch (yych) {
+       case 'O':
+       case 'o':       goto yy444;
+       default:        goto yy386;
+       }
+yy444:
+       yych = *++c;
+       switch (yych) {
+       case 'N':
+       case 'n':       goto yy406;
+       default:        goto yy386;
+       }
+yy445:
+       yych = *++c;
+       switch (yych) {
+       case 'T':
+       case 't':       goto yy446;
+       default:        goto yy386;
+       }
+yy446:
+       yych = *++c;
+       switch (yych) {
+       case 'P':
+       case 'p':       goto yy447;
+       default:        goto yy386;
+       }
+yy447:
+       yych = *++c;
+       switch (yych) {
+       case 'U':
+       case 'u':       goto yy448;
+       default:        goto yy386;
+       }
+yy448:
+       yych = *++c;
+       switch (yych) {
+       case 'T':
+       case 't':       goto yy406;
+       default:        goto yy386;
+       }
+yy449:
+       yych = *++c;
+       switch (yych) {
+       case 'F':
+       case 'f':       goto yy451;
+       case 'S':
+       case 's':       goto yy452;
+       default:        goto yy386;
+       }
+yy450:
+       yych = *++c;
+       switch (yych) {
+       case 'V':
+       case 'v':       goto yy406;
+       default:        goto yy386;
+       }
+yy451:
+       yych = *++c;
+       switch (yych) {
+       case 'R':
+       case 'r':       goto yy457;
+       default:        goto yy386;
+       }
+yy452:
+       yych = *++c;
+       switch (yych) {
+       case 'C':
+       case 'c':       goto yy453;
+       default:        goto yy386;
+       }
+yy453:
+       yych = *++c;
+       switch (yych) {
+       case 'R':
+       case 'r':       goto yy454;
+       default:        goto yy386;
+       }
+yy454:
+       yych = *++c;
+       switch (yych) {
+       case 'I':
+       case 'i':       goto yy455;
+       default:        goto yy386;
+       }
+yy455:
+       yych = *++c;
+       switch (yych) {
+       case 'P':
+       case 'p':       goto yy456;
+       default:        goto yy386;
+       }
+yy456:
+       yych = *++c;
+       switch (yych) {
+       case 'T':
+       case 't':       goto yy406;
+       default:        goto yy386;
+       }
+yy457:
+       yych = *++c;
+       switch (yych) {
+       case 'A':
+       case 'a':       goto yy458;
+       default:        goto yy386;
+       }
+yy458:
+       yych = *++c;
+       switch (yych) {
+       case 'M':
+       case 'm':       goto yy459;
+       default:        goto yy386;
+       }
+yy459:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy460;
+       default:        goto yy386;
+       }
+yy460:
+       yych = *++c;
+       switch (yych) {
+       case 'S':
+       case 's':       goto yy406;
+       default:        goto yy386;
+       }
+yy461:
+       yych = *++c;
+       switch (yych) {
+       case 'N':
+       case 'n':       goto yy464;
+       default:        goto yy386;
+       }
+yy462:
+       yych = *++c;
+       switch (yych) {
+       case 'I':
+       case 'i':       goto yy463;
+       default:        goto yy386;
+       }
+yy463:
+       yych = *++c;
+       switch (yych) {
+       case 'N':
+       case 'n':       goto yy406;
+       default:        goto yy386;
+       }
+yy464:
+       yych = *++c;
+       switch (yych) {
+       case 'U':
+       case 'u':       goto yy406;
+       default:        goto yy386;
+       }
+yy465:
+       yych = *++c;
+       switch (yych) {
+       case 'I':
+       case 'i':       goto yy466;
+       default:        goto yy386;
+       }
+yy466:
+       yych = *++c;
+       switch (yych) {
+       case 'N':
+       case 'n':       goto yy467;
+       default:        goto yy386;
+       }
+yy467:
+       yych = *++c;
+       switch (yych) {
+       case 'D':
+       case 'd':       goto yy468;
+       default:        goto yy386;
+       }
+yy468:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy469;
+       default:        goto yy386;
+       }
+yy469:
+       yych = *++c;
+       switch (yych) {
+       case 'X':
+       case 'x':       goto yy406;
+       default:        goto yy386;
+       }
+yy470:
+       yych = *++c;
+       switch (yych) {
+       case 'R':
+       case 'r':       goto yy475;
+       default:        goto yy386;
+       }
+yy471:
+       yych = *++c;
+       switch (yych) {
+       case 'A':
+       case 'a':       goto yy472;
+       default:        goto yy386;
+       }
+yy472:
+       yych = *++c;
+       switch (yych) {
+       case 'D':
+       case 'd':       goto yy473;
+       default:        goto yy386;
+       }
+yy473:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy474;
+       default:        goto yy386;
+       }
+yy474:
+       yych = *++c;
+       switch (yych) {
+       case 'R':
+       case 'r':       goto yy406;
+       default:        goto yy386;
+       }
+yy475:
+       yych = *++c;
+       switch (yych) {
+       case 'O':
+       case 'o':       goto yy476;
+       default:        goto yy386;
+       }
+yy476:
+       yych = *++c;
+       switch (yych) {
+       case 'U':
+       case 'u':       goto yy477;
+       default:        goto yy386;
+       }
+yy477:
+       yych = *++c;
+       switch (yych) {
+       case 'P':
+       case 'p':       goto yy406;
+       default:        goto yy386;
+       }
+yy478:
+       yych = *++c;
+       switch (yych) {
+       case 'A':
+       case 'a':       goto yy499;
+       default:        goto yy386;
+       }
+yy479:
+       yych = *++c;
+       switch (yych) {
+       case 'O':
+       case 'o':       goto yy495;
+       case 'R':
+       case 'r':       goto yy496;
+       default:        goto yy386;
+       }
+yy480:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy481;
+       case 'G':
+       case 'g':       goto yy482;
+       default:        goto yy386;
+       }
+yy481:
+       yych = *++c;
+       switch (yych) {
+       case 'L':
+       case 'l':       goto yy491;
+       default:        goto yy386;
+       }
+yy482:
+       yych = *++c;
+       switch (yych) {
+       case 'C':
+       case 'c':       goto yy484;
+       case 'U':
+       case 'u':       goto yy483;
+       default:        goto yy386;
+       }
+yy483:
+       yych = *++c;
+       switch (yych) {
+       case 'R':
+       case 'r':       goto yy490;
+       default:        goto yy386;
+       }
+yy484:
+       yych = *++c;
+       switch (yych) {
+       case 'A':
+       case 'a':       goto yy485;
+       default:        goto yy386;
+       }
+yy485:
+       yych = *++c;
+       switch (yych) {
+       case 'P':
+       case 'p':       goto yy486;
+       default:        goto yy386;
+       }
+yy486:
+       yych = *++c;
+       switch (yych) {
+       case 'T':
+       case 't':       goto yy487;
+       default:        goto yy386;
+       }
+yy487:
+       yych = *++c;
+       switch (yych) {
+       case 'I':
+       case 'i':       goto yy488;
+       default:        goto yy386;
+       }
+yy488:
+       yych = *++c;
+       switch (yych) {
+       case 'O':
+       case 'o':       goto yy489;
+       default:        goto yy386;
+       }
+yy489:
+       yych = *++c;
+       switch (yych) {
+       case 'N':
+       case 'n':       goto yy406;
+       default:        goto yy386;
+       }
+yy490:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy406;
+       default:        goto yy386;
+       }
+yy491:
+       yych = *++c;
+       switch (yych) {
+       case 'D':
+       case 'd':       goto yy492;
+       default:        goto yy386;
+       }
+yy492:
+       yych = *++c;
+       switch (yych) {
+       case 'S':
+       case 's':       goto yy493;
+       default:        goto yy386;
+       }
+yy493:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy494;
+       default:        goto yy386;
+       }
+yy494:
+       yych = *++c;
+       switch (yych) {
+       case 'T':
+       case 't':       goto yy406;
+       default:        goto yy386;
+       }
+yy495:
+       yych = *++c;
+       switch (yych) {
+       case 'T':
+       case 't':       goto yy497;
+       default:        goto yy386;
+       }
+yy496:
+       yych = *++c;
+       switch (yych) {
+       case 'M':
+       case 'm':       goto yy406;
+       default:        goto yy386;
+       }
+yy497:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy498;
+       default:        goto yy386;
+       }
+yy498:
+       yych = *++c;
+       switch (yych) {
+       case 'R':
+       case 'r':       goto yy406;
+       default:        goto yy386;
+       }
+yy499:
+       yych = *++c;
+       switch (yych) {
+       case 'M':
+       case 'm':       goto yy500;
+       default:        goto yy386;
+       }
+yy500:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy501;
+       default:        goto yy386;
+       }
+yy501:
+       yych = *++c;
+       switch (yych) {
+       case 'S':
+       case 's':       goto yy502;
+       default:        goto yy386;
+       }
+yy502:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy503;
+       default:        goto yy386;
+       }
+yy503:
+       yych = *++c;
+       switch (yych) {
+       case 'T':
+       case 't':       goto yy406;
+       default:        goto yy386;
+       }
+yy504:
+       yych = *++c;
+       switch (yych) {
+       case 'R':
+       case 'V':
+       case 'r':
+       case 'v':       goto yy406;
+       default:        goto yy386;
+       }
+yy505:
+       yych = *++c;
+       switch (yych) {
+       case 'N':
+       case 'n':       goto yy510;
+       default:        goto yy386;
+       }
+yy506:
+       yych = *++c;
+       switch (yych) {
+       case 'N':
+       case 'n':       goto yy507;
+       default:        goto yy386;
+       }
+yy507:
+       yych = *++c;
+       switch (yych) {
+       case 'V':
+       case 'v':       goto yy508;
+       default:        goto yy386;
+       }
+yy508:
+       yych = *++c;
+       switch (yych) {
+       case 'A':
+       case 'a':       goto yy509;
+       default:        goto yy386;
+       }
+yy509:
+       yych = *++c;
+       switch (yych) {
+       case 'S':
+       case 's':       goto yy406;
+       default:        goto yy386;
+       }
+yy510:
+       yych = *++c;
+       switch (yych) {
+       case 'T':
+       case 't':       goto yy511;
+       default:        goto yy386;
+       }
+yy511:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy512;
+       default:        goto yy386;
+       }
+yy512:
+       yych = *++c;
+       switch (yych) {
+       case 'R':
+       case 'r':       goto yy406;
+       default:        goto yy386;
+       }
+yy513:
+       yych = *++c;
+       switch (yych) {
+       case 'O':
+       case 'o':       goto yy514;
+       default:        goto yy386;
+       }
+yy514:
+       yych = *++c;
+       switch (yych) {
+       case 'C':
+       case 'c':       goto yy515;
+       default:        goto yy386;
+       }
+yy515:
+       yych = *++c;
+       switch (yych) {
+       case 'K':
+       case 'k':       goto yy516;
+       default:        goto yy386;
+       }
+yy516:
+       yych = *++c;
+       switch (yych) {
+       case 'Q':
+       case 'q':       goto yy517;
+       default:        goto yy386;
+       }
+yy517:
+       yych = *++c;
+       switch (yych) {
+       case 'U':
+       case 'u':       goto yy518;
+       default:        goto yy386;
+       }
+yy518:
+       yych = *++c;
+       switch (yych) {
+       case 'O':
+       case 'o':       goto yy519;
+       default:        goto yy386;
+       }
+yy519:
+       yych = *++c;
+       switch (yych) {
+       case 'T':
+       case 't':       goto yy520;
+       default:        goto yy386;
+       }
+yy520:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy406;
+       default:        goto yy386;
+       }
+yy521:
+       yych = *++c;
+       switch (yych) {
+       case 'I':
+       case 'i':       goto yy532;
+       default:        goto yy386;
+       }
+yy522:
+       yych = *++c;
+       switch (yych) {
+       case 'T':
+       case 't':       goto yy528;
+       default:        goto yy386;
+       }
+yy523:
+       yych = *++c;
+       switch (yych) {
+       case 'D':
+       case 'd':       goto yy524;
+       default:        goto yy386;
+       }
+yy524:
+       yych = *++c;
+       switch (yych) {
+       case 'R':
+       case 'r':       goto yy525;
+       default:        goto yy386;
+       }
+yy525:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy526;
+       default:        goto yy386;
+       }
+yy526:
+       yych = *++c;
+       switch (yych) {
+       case 'S':
+       case 's':       goto yy527;
+       default:        goto yy386;
+       }
+yy527:
+       yych = *++c;
+       switch (yych) {
+       case 'S':
+       case 's':       goto yy406;
+       default:        goto yy386;
+       }
+yy528:
+       yych = *++c;
+       switch (yych) {
+       case 'I':
+       case 'i':       goto yy529;
+       default:        goto yy386;
+       }
+yy529:
+       yych = *++c;
+       switch (yych) {
+       case 'C':
+       case 'c':       goto yy530;
+       default:        goto yy386;
+       }
+yy530:
+       yych = *++c;
+       switch (yych) {
+       case 'L':
+       case 'l':       goto yy531;
+       default:        goto yy386;
+       }
+yy531:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy406;
+       default:        goto yy386;
+       }
+yy532:
+       yych = *++c;
+       switch (yych) {
+       case 'D':
+       case 'd':       goto yy533;
+       default:        goto yy386;
+       }
+yy533:
+       yych = *++c;
+       switch (yych) {
+       case 'E':
+       case 'e':       goto yy406;
+       default:        goto yy386;
+       }
+yy534:
+       ++c;
+       switch ((yych = *c)) {
+       case 'E':
+       case 'e':       goto yy439;
+       default:        goto yy413;
+       }
+}
+       
+}
+
+
+size_t scan_html_line(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       yych = *c;
+       switch (yych) {
+       case '\n':      goto yy537;
+       case '<':       goto yy538;
+       default:        goto yy539;
+       }
+yy537:
+       { return 0; }
+yy538:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '!':       goto yy540;
+       case '/':       goto yy542;
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy543;
+       default:        goto yy537;
+       }
+yy539:
+       yych = *++c;
+       goto yy537;
+yy540:
+       yych = *++c;
+       switch (yych) {
+       case '-':       goto yy574;
+       default:        goto yy541;
+       }
+yy541:
+       c = marker;
+       goto yy537;
+yy542:
+       yych = *++c;
+       switch (yych) {
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy570;
+       default:        goto yy541;
+       }
+yy543:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy547;
+       case '\n':      goto yy549;
+       case '\r':      goto yy551;
+       case '-':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy543;
+       case '/':       goto yy556;
+       case ':':
+       case '_':       goto yy552;
+       case '>':       goto yy554;
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy545;
+       default:        goto yy541;
+       }
+yy545:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy547;
+       case '\n':      goto yy549;
+       case '\r':      goto yy551;
+       case '-':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy545;
+       case '.':
+       case ':':
+       case '_':       goto yy552;
+       case '/':       goto yy556;
+       case '=':       goto yy560;
+       case '>':       goto yy554;
+       default:        goto yy541;
+       }
+yy547:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy547;
+       case '\n':      goto yy549;
+       case '\r':      goto yy551;
+       case '/':       goto yy556;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy552;
+       case '>':       goto yy554;
+       default:        goto yy541;
+       }
+yy549:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy549;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy552;
+       default:        goto yy541;
+       }
+yy551:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case '\n':
+       case ' ':       goto yy549;
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy552;
+       default:        goto yy541;
+       }
+yy552:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '-':
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case ':':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case '_':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy552;
+       case '=':       goto yy560;
+       default:        goto yy541;
+       }
+yy554:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy554;
+       case '\n':      goto yy557;
+       case '\r':      goto yy559;
+       default:        goto yy541;
+       }
+yy556:
+       yych = *++c;
+       switch (yych) {
+       case '>':       goto yy554;
+       default:        goto yy541;
+       }
+yy557:
+       ++c;
+yy558:
+       { return (size_t)( c - start ); }
+yy559:
+       yych = *++c;
+       switch (yych) {
+       case '\n':      goto yy557;
+       default:        goto yy558;
+       }
+yy560:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy560;
+       case '"':       goto yy562;
+       case '\'':      goto yy564;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy566;
+       default:        goto yy541;
+       }
+yy562:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy541;
+       case '"':       goto yy547;
+       default:        goto yy562;
+       }
+yy564:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':      goto yy541;
+       case '\'':      goto yy547;
+       default:        goto yy564;
+       }
+yy566:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy547;
+       case '\n':      goto yy549;
+       case '\r':      goto yy551;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy566;
+       case '/':       goto yy556;
+       case ':':
+       case '_':       goto yy552;
+       case '>':       goto yy554;
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy568;
+       default:        goto yy541;
+       }
+yy568:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy547;
+       case '\n':      goto yy549;
+       case '\r':      goto yy551;
+       case '-':
+       case ':':
+       case '_':       goto yy552;
+       case '.':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy568;
+       case '/':       goto yy556;
+       case '=':       goto yy560;
+       case '>':       goto yy554;
+       default:        goto yy541;
+       }
+yy570:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy572;
+       case '-':
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':       goto yy570;
+       case '>':       goto yy554;
+       default:        goto yy541;
+       }
+yy572:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy572;
+       case '>':       goto yy554;
+       default:        goto yy541;
+       }
+yy574:
+       yych = *++c;
+       switch (yych) {
+       case '-':       goto yy575;
+       default:        goto yy541;
+       }
+yy575:
+       yych = *++c;
+       switch (yych) {
+       case '-':       goto yy541;
+       default:        goto yy577;
+       }
+yy576:
+       ++c;
+       yych = *c;
+yy577:
+       switch (yych) {
+       case 0x00:
+       case '>':       goto yy541;
+       case '-':       goto yy578;
+       default:        goto yy576;
+       }
+yy578:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '>':       goto yy541;
+       case '-':       goto yy579;
+       default:        goto yy576;
+       }
+yy579:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:      goto yy541;
+       case '-':       goto yy579;
+       case '>':       goto yy554;
+       default:        goto yy576;
+       }
+}
+       
+}
+
+
+size_t scan_fence_start(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       yych = *c;
+       switch (yych) {
+       case '\n':      goto yy583;
+       case ' ':       goto yy584;
+       case '`':
+       case '~':       goto yy585;
+       default:        goto yy586;
+       }
+yy583:
+       { return 0; }
+yy584:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case ' ':       goto yy597;
+       case '`':
+       case '~':       goto yy598;
+       default:        goto yy583;
+       }
+yy585:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '`':
+       case '~':       goto yy587;
+       default:        goto yy583;
+       }
+yy586:
+       yych = *++c;
+       goto yy583;
+yy587:
+       yych = *++c;
+       switch (yych) {
+       case '`':
+       case '~':       goto yy589;
+       default:        goto yy588;
+       }
+yy588:
+       c = marker;
+       goto yy583;
+yy589:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\n':
+       case '\r':
+       case '\'':      goto yy588;
+       case '`':       goto yy589;
+       case '~':       goto yy592;
+       default:        goto yy591;
+       }
+yy591:
+       yych = *++c;
+       switch (yych) {
+       case '\n':      goto yy594;
+       case '\r':      goto yy596;
+       default:        goto yy588;
+       }
+yy592:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case 0x00:
+       case '\'':      goto yy588;
+       case '\n':      goto yy594;
+       case '\r':      goto yy596;
+       case '`':       goto yy589;
+       case '~':       goto yy592;
+       default:        goto yy591;
+       }
+yy594:
+       ++c;
+yy595:
+       { return (size_t)( c - start ); }
+yy596:
+       yych = *++c;
+       switch (yych) {
+       case '\n':      goto yy594;
+       default:        goto yy595;
+       }
+yy597:
+       yych = *++c;
+       switch (yych) {
+       case ' ':       goto yy599;
+       case '`':
+       case '~':       goto yy598;
+       default:        goto yy588;
+       }
+yy598:
+       yych = *++c;
+       switch (yych) {
+       case '`':
+       case '~':       goto yy587;
+       default:        goto yy588;
+       }
+yy599:
+       ++c;
+       switch ((yych = *c)) {
+       case '`':
+       case '~':       goto yy598;
+       default:        goto yy588;
+       }
+}
+       
+}
+
+
+size_t scan_fence_end(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+
+{
+       char yych;
+       yych = *c;
+       switch (yych) {
+       case '\n':      goto yy602;
+       case ' ':       goto yy603;
+       case '`':
+       case '~':       goto yy604;
+       default:        goto yy605;
+       }
+yy602:
+       { return 0; }
+yy603:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case ' ':       goto yy615;
+       case '`':
+       case '~':       goto yy616;
+       default:        goto yy602;
+       }
+yy604:
+       yych = *(marker = ++c);
+       switch (yych) {
+       case '`':
+       case '~':       goto yy606;
+       default:        goto yy602;
+       }
+yy605:
+       yych = *++c;
+       goto yy602;
+yy606:
+       yych = *++c;
+       switch (yych) {
+       case '`':
+       case '~':       goto yy608;
+       default:        goto yy607;
+       }
+yy607:
+       c = marker;
+       goto yy602;
+yy608:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy610;
+       case '\n':      goto yy612;
+       case '\r':      goto yy614;
+       case '`':
+       case '~':       goto yy608;
+       default:        goto yy607;
+       }
+yy610:
+       ++c;
+       yych = *c;
+       switch (yych) {
+       case '\t':
+       case ' ':       goto yy610;
+       case '\n':      goto yy612;
+       case '\r':      goto yy614;
+       default:        goto yy607;
+       }
+yy612:
+       ++c;
+yy613:
+       { return (size_t)( c - start ); }
+yy614:
+       yych = *++c;
+       switch (yych) {
+       case '\n':      goto yy612;
+       default:        goto yy613;
+       }
+yy615:
+       yych = *++c;
+       switch (yych) {
+       case ' ':       goto yy617;
+       case '`':
+       case '~':       goto yy616;
+       default:        goto yy607;
+       }
+yy616:
+       yych = *++c;
+       switch (yych) {
+       case '`':
+       case '~':       goto yy606;
+       default:        goto yy607;
+       }
+yy617:
+       ++c;
+       switch ((yych = *c)) {
+       case '`':
+       case '~':       goto yy616;
+       default:        goto yy607;
+       }
+}
+       
+}
+
+
+#ifdef TEST
+void Test_scan_url(CuTest* tc) {
+       int url_len;
+
+       url_len = (int) scan_url("mailto:foo@bar.com");
+       CuAssertIntEquals(tc, 18, url_len);
+       url_len = (int) scan_email("mailto:foo@bar.com");
+       CuAssertIntEquals(tc, 18, url_len);
+
+       url_len = (int) scan_url("http://test.com/");
+       CuAssertIntEquals(tc, 16, url_len);
+       url_len = (int) scan_email("mailto:foo@bar.com");
+       CuAssertIntEquals(tc, 0, url_len);
+
+       url_len = (int) scan_url("foo@bar.com  ");
+       CuAssertIntEquals(tc, 12, url_len);
+       url_len = (int) scan_email("mailto:foo@bar.com");
+       CuAssertIntEquals(tc, 12, url_len);
+}
+#endif
+
diff --git a/src/scanners.h b/src/scanners.h
new file mode 100644 (file)
index 0000000..3be8a58
--- /dev/null
@@ -0,0 +1,81 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file scanners.h
+
+       @brief After text has been tokenized, there are still some constructs that are best
+       interpreted using regular expressions.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+
+#ifndef SCANNERS_MULTIMARKDOWN_H
+#define SCANNERS_MULTIMARKDOWN_H
+
+#ifdef TEST
+#include "CuTest.h"
+#endif
+
+size_t scan_attr(const char * c);
+size_t scan_attributes(const char * c);
+size_t scan_email(const char * c);
+size_t scan_fence_start(const char * c);
+size_t scan_fence_end(const char * c);
+size_t scan_html(const char * c);
+size_t scan_html_block(const char * c);
+size_t scan_html_line(const char * c);
+size_t scan_key(const char * c);
+size_t scan_ref_citation(const char * c);
+size_t scan_ref_foot(const char * c);
+size_t scan_ref_link(const char * c);
+size_t scan_ref_link_no_attributes(const char * c);
+size_t scan_spnl(const char * c);
+size_t scan_url(const char * c);
+size_t scan_value(const char * c);
+
+#endif
diff --git a/src/scanners.re b/src/scanners.re
new file mode 100644 (file)
index 0000000..b0e7b23
--- /dev/null
@@ -0,0 +1,330 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file scanners.c
+
+       @brief After text has been tokenized, there are still some constructs that are best
+       interpreted using regular expressions.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+#include <stdlib.h>
+
+#include "scanners.h"
+
+/*!re2c
+
+       re2c:define:YYCTYPE = "char";
+       re2c:define:YYCURSOR = c;
+       re2c:define:YYMARKER = marker;
+       re2c:define:YYCTXMARKER = marker;
+       re2c:yyfill:enable = 0;
+
+       nl                      = ( '\n' | '\r' '\n'?);
+       sp                      = [ \t]*;
+       spnl            = sp (nl sp)?;
+       non_indent      = ' '{0,3};
+
+       email           = 'mailto:'? [-A-Za-z0-9+_./!%~$]+ '@' [^ \t\n\r\x00>]+;
+
+       url                     = [A-Za-z\-]+ '://' [^ \t\n\r\x00>]+;
+
+       name            = [A-Za-z_:] [A-Za-z0-9_.:-]*;
+       quoted_d        = '"' [^"\n\r\x00]* '"';
+       quoted_s        = "'" [^'\n\r\x00]* "'";
+       quoted_p        = "(" [^)\n\r\x00]* ")";
+       unquoted        = [\.A-Za-z0-9]+;
+
+       value           = (quoted_d | quoted_s | unquoted);
+       attr            = spnl name '=' sp value;
+       attributes      = (attr)+;
+       title           = (quoted_d | quoted_s | quoted_p);
+
+       label           = [^\]\n\r\x00]+;
+       finish_line     = [^\n\r\x00]+;
+
+       ref_citation    = non_indent '[#' label ']' ':' finish_line;
+
+       ref_foot        = non_indent '[^' label ']' ':' finish_line;
+
+       ref_link        = non_indent '[' label ']' ':' finish_line;
+
+       destination     = ('<' [^ \t\n\r\x00>]* '>') | [^ \t\n\r\x00]+;
+
+       ref_link_no_attributes  = non_indent '[' label ']' ':' spnl destination sp (nl | (nl? (title) sp) nl);
+
+       tag_name        = [A-Za-z] [A-Za-z0-9\-]*;
+
+       tag_start       = '<' tag_name attributes? sp '>';
+
+       tag_empty       = '<' tag_name attributes? sp '/>';
+
+       tag_end         = '</' tag_name sp '>';
+
+       // We limit comments to exclude '>' character to minimize backtracking
+       comment         = [^>\-\x00] [^>\x00]*;
+
+       tag_comment     = '<!--' comment '-->';
+
+       html            = tag_start | tag_empty | tag_end | tag_comment;
+
+       html_line       = html sp nl;
+
+//     http://www.cs.sfu.ca/CourseCentral/165/sbrown1/wdgxhtml10/block.html
+//     https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements
+
+       block_tag       = 'address' | 'article' | 'aside' | 'blockquote' | 'canvas' | 'center' | 'dd' |
+                                       'dir' | 'div' | 'dl' | 'dt' | 'fieldset' | 'figcaption' | 'figure' |
+                                       'footer' | 'form' | 'frameset' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' |
+                                       'header' | 'hgroup' | 'hr' | 'isindex' | 'li' | 'main' | 'menu' | 'nav' |
+                                       'noframes' | 'noscript' | 'ol' | 'output' | 'p' | 'pre' | 'section' |
+                                       'table' | 'tbody' | 'td' | 'tfoot' | 'th' | 'thead' | 'tr' | 'ul' | 'video';
+
+       html_block      = '<' '/'? block_tag attributes? '/'? '>';
+
+       fence_start     = non_indent [`~]{3,} [^`'\n\r\x00] nl;
+
+       fence_end       = non_indent [`~]{3,} sp nl;
+*/
+
+
+size_t scan_spnl(const char * c) {
+       const char * start = c;
+
+/*!re2c
+       spnl            { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_key(const char * c) {
+       const char * start = c;
+
+/*!re2c
+       name            { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_value(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       value           { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_attr(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       attr            { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_attributes(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       attributes      { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_email(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       email           { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_url(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       email           { return (size_t)( c - start ); }
+       url                     { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_ref_citation(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       ref_citation    { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+size_t scan_ref_foot(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       ref_foot        { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_ref_link_no_attributes(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       ref_link_no_attributes  { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_ref_link(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       ref_link        { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_html(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       html            { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_html_block(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       html_block      { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_html_line(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       html_line       { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_fence_start(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       fence_start     { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+size_t scan_fence_end(const char * c) {
+       const char * marker = NULL;
+       const char * start = c;
+
+/*!re2c
+       fence_end       { return (size_t)( c - start ); }
+       .?                      { return 0; }
+*/     
+}
+
+
+#ifdef TEST
+void Test_scan_url(CuTest* tc) {
+       int url_len;
+
+       url_len = (int) scan_url("mailto:foo@bar.com");
+       CuAssertIntEquals(tc, 18, url_len);
+       url_len = (int) scan_email("mailto:foo@bar.com");
+       CuAssertIntEquals(tc, 18, url_len);
+
+       url_len = (int) scan_url("http://test.com/");
+       CuAssertIntEquals(tc, 16, url_len);
+       url_len = (int) scan_email("mailto:foo@bar.com");
+       CuAssertIntEquals(tc, 0, url_len);
+
+       url_len = (int) scan_url("foo@bar.com  ");
+       CuAssertIntEquals(tc, 12, url_len);
+       url_len = (int) scan_email("mailto:foo@bar.com");
+       CuAssertIntEquals(tc, 12, url_len);
+}
+#endif
+
diff --git a/src/stack.c b/src/stack.c
new file mode 100644 (file)
index 0000000..5b1864f
--- /dev/null
@@ -0,0 +1,132 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file stack.c
+
+       @brief Create a dynamic array that stores pointers in a LIFO order.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "stack.h"
+
+#define kStackStartingSize 64
+
+
+/// Create a new stack with dynamic storage with an
+/// initial capacity (0 to use default capacity)
+stack * stack_new(int startingSize) {
+       stack * s = malloc(sizeof(stack));
+       
+       if (s) {
+               if (startingSize <= 0)
+                       startingSize = kStackStartingSize;
+
+               s->element = malloc(sizeof(void *) * startingSize);
+
+               if (!s->element) {
+                       free(s);
+                       return NULL;
+               }
+
+               s->size = 0;
+               s->capacity = startingSize;
+       }
+
+       return s;
+}
+
+
+/// Free the stack
+void stack_free(stack * s) {
+       free(s->element);
+       free(s);
+}
+
+
+/// Add a new pointer to the stack
+void stack_push(stack * s, void * element) {
+       if (s->size == s->capacity) {
+               s->capacity *= 2;
+               s->element = realloc(s->element, s->capacity * sizeof(void *));
+       }
+
+       s->element[s->size++] = element;
+}
+
+
+/// Pop the top item off the stack
+void * stack_pop(stack * s) {
+       void * last = stack_peek(s);
+
+       if (s->size != 0)
+               s->size--;
+
+       return last;
+}
+
+
+/// Peek at the top item on the stack
+void * stack_peek(stack * s) {
+       if (s->size == 0)
+               return NULL;
+
+       return s->element[(s->size) - 1];
+}
+
+
+/// Peek at a specific index in the stack
+void * stack_peek_index(stack * s, size_t index) {
+       if (index >= s->size)
+               return NULL;
+
+       return s->element[index];
+}
+
diff --git a/src/stack.h b/src/stack.h
new file mode 100644 (file)
index 0000000..5248a59
--- /dev/null
@@ -0,0 +1,110 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file stack.h
+
+       @brief Create a dynamic array that stores pointers in a LIFO order.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+
+#ifndef STACK_SMART_STRING_H
+#define STACK_SMART_STRING_H
+
+#include <stdlib.h>
+
+/// Structure for a stack
+struct stack {
+       size_t          size;                           //!< Number of objects currently in stack
+       size_t          capacity;                       //!< Total current capacity for stack
+       void **         element;                        //!< Array of pointers to objects in stack
+};
+
+typedef struct stack stack;
+
+
+/// Create a new stack with dynamic storage with an
+/// initial capacity (0 to use default capacity)
+stack * stack_new(
+       int startingSize                                //!< Default capacity for stack
+);
+
+
+/// Free the stack
+void stack_free(
+       stack * s                                               //!< Stack to be freed
+);
+
+
+/// Add a new pointer to the stack
+void stack_push(
+       stack * s,                                              //!< Stack to use
+       void * element                                  //!< Pointer to push onto stack
+);
+
+
+/// Pop the top pointer off the stack and return it
+void * stack_pop(
+       stack * s                                               //!< Stack to examine
+);
+
+
+/// Peek at the top pointer on the stack (but don't remove it from stack)
+void * stack_peek(
+       stack * s                                               //!< Stack to examine
+);
+
+
+/// Peek at a specific index in the stack
+void * stack_peek_index(
+       stack * s,                                              //!< Stack to examine
+       size_t index                                    //!< Index to peek at (0 is first pointer on stack)
+);
+
+
+#endif
diff --git a/src/token.c b/src/token.c
new file mode 100644 (file)
index 0000000..17cd427
--- /dev/null
@@ -0,0 +1,619 @@
+/**
+
+       Parser-Template -- Boilerplate parser example using re2c lexer and lemon parser.
+
+       @file token.c
+
+       @brief Structure and functions to manage tokens representing portions of a
+       text string.
+
+
+       @author Fletcher T. Penney
+
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "char.h"
+#include "token.h"
+
+
+#ifdef kUseObjectPool
+//!< Use an object pool to allocate tokens more efficiently to improve
+//!< performance.
+
+#include "object_pool.h"
+
+static pool * token_pool = NULL;
+
+/// Intialize object pool for token allocation
+void token_pool_init(void) {
+       if (token_pool == NULL) {
+               // No pool exists
+               token_pool = pool_new(sizeof(token));
+       } else {
+               // Pool exists, ensure it's drained
+               // NOTE: This invalidates any tokens currently in use.
+               token_pool_drain();
+       }
+}
+
+
+/// Drain token allocator pool to prepare for another parse
+void token_pool_drain(void) {
+       pool_drain(token_pool);
+}
+
+
+/// Free token allocator pool
+void token_pool_free(void) {
+       pool_free(token_pool);
+       token_pool = NULL;
+}
+
+#endif
+
+
+/// Get pointer to a new token
+token * token_new(unsigned short type, size_t start, size_t len) {
+
+
+#ifdef kUseObjectPool
+       token * t = pool_allocate_object(token_pool);
+#else
+       //token * t = calloc(1, sizeof(token));
+       token * t = malloc(sizeof(token));
+#endif
+
+       if (t) {
+               t->type = type;
+               t->start = start;
+               t->len = len;
+
+               t->next = NULL;
+               t->prev = NULL;
+               t->child = NULL;
+
+               t->tail = t;
+
+               t->can_open = true;                     //!< Default to true -- we assume openers can open and closers can close
+               t->can_close = true;            //!< unless specified otherwise (e.g. for ambidextrous tokens)
+               t->unmatched = true;
+
+               t->mate = NULL;
+       }
+
+       return t;
+}
+
+
+/// Create a parent for a chain of tokens
+token * token_new_parent(token * child, unsigned short type) {
+       token * t = token_new(type, child->start, 0);
+       t->child = child;
+       child->prev = NULL;
+
+       // Ensure that parent length correctly includes children
+       if (child == NULL) {
+               t->len = 0;
+       } else if (child->next == NULL) {
+               t->len = child->len;
+       } else {
+               while (child->next != NULL)
+                       child = child->next;
+
+               t->len = child->start + child->len - t->start;
+       }
+
+       return t;
+}
+
+
+/// Add a new token to the end of a token chain.  The new token
+/// may or may not also be the start of a chain
+void token_chain_append(token * chain_start, token * t) {
+       if ((chain_start == NULL) ||
+               (t == NULL))
+               return;
+
+       // Append t
+       chain_start->tail->next = t;
+       t->prev = chain_start->tail;
+
+       // Adjust tail marker
+       chain_start->tail = t->tail;
+}
+
+
+/// Add a new token to the end of a parent's child
+/// token chain.  The new token may or may not be
+/// the start of a chain.
+void token_append_child(token * parent, token * t) {
+       if ((parent == NULL) || (t == NULL))
+               return;
+
+       if (parent->child == NULL) {
+               // Parent has no children
+               parent->child = t;
+       } else {
+               // Append to to existing child chain
+               token_chain_append(parent->child, t);
+       }
+
+       // Set len on parent
+       parent->len = parent->child->tail->start + parent->child->tail->len - parent->start;
+}
+
+
+/// Remove the first child of a token
+void token_remove_first_child(token * parent) {
+       if ((parent == NULL) || (parent->child == NULL))
+               return;
+
+       token * t = parent->child;
+       parent->child = t->next;
+
+       if (parent->child) {
+               parent->child->prev = NULL;
+               parent->child->tail = t->tail;
+       }
+
+       token_free(t);
+}
+
+
+/// Remove the last child of a token
+void token_remove_last_child(token * parent) {
+       if ((parent == NULL) || (parent->child == NULL))
+               return;
+
+       token * t = parent->child->tail;
+
+       if (t->prev) {
+               t->prev->next = NULL;
+               parent->child->tail = t->prev;
+       }
+
+       token_free(t);
+}
+
+
+/// Remove the last token in a chain
+void token_remove_tail(token * head) {
+       if ((head == NULL) || (head->tail == head))
+               return;
+
+       token * t = head->tail;
+
+       if (t->prev) {
+               t->prev->next = NULL;
+               head->tail = t->prev;
+       }
+
+       token_free(t);
+}
+
+
+/// Pop token out of it's chain, connecting head and tail of chain back together.
+/// Token must be freed if it is no longer needed.
+/// \todo: If t is the tail token of a chain, the tail is no longer correct on the start of chain.
+void token_pop_link_from_chain(token * t) {
+       if (t == NULL)
+               return;
+
+       token * prev = t->prev;
+       token * next = t->next;
+
+       t->next = NULL;
+       t->prev = NULL;
+       t->tail = t;
+
+       if (prev) {
+               prev->next = next;
+       }
+
+       if (next) {
+               next->prev = prev;
+       }
+}
+
+
+/// Remove one or more tokens from chain
+void tokens_prune(token * first, token * last) {
+       if (first == NULL || last == NULL)
+               return;
+
+       token * prev = first->prev;
+       token * next = last->next;
+
+       if (prev != NULL)
+               prev->next = next;
+       
+       if (next != NULL)
+               next->prev = prev;
+
+    first->prev = NULL;
+    last->next = NULL;
+    
+       token_tree_free(first);
+}
+
+
+/// Given a start/stop point in token chain, create a new container token.
+/// Return pointer to new container token.
+token * token_prune_graft(token * first, token * last, unsigned short container_type) {
+       if (first == NULL || last == NULL)
+               return first;
+
+       token * prev = first->prev;
+       token * next = last->next;
+       
+       // If we are head of chain, remember tail
+       token * tail = NULL;
+       if (prev == NULL)
+               tail = first->tail;
+
+
+       token * container = token_new(container_type, first->start, last->start + last->len - first->start);
+       
+       container->child = first;
+       container->next = next;
+       container->prev = prev;
+       container->can_close = 0;
+       container->can_open = 0;
+
+       if (tail)
+               container->tail = tail;
+
+       if (prev)
+               prev->next = container;
+
+       first->prev = NULL;
+
+       last->next = NULL;
+
+       if (next)
+               next->prev = container;
+
+       return container;
+}
+
+
+/// Free token
+void token_free(token * t) {
+#ifdef kUseObjectPool
+       return;
+#else
+       if (t == NULL)
+               return;
+       
+       token_tree_free(t->child);
+
+       free(t);
+#endif
+}
+
+
+/// Free token chain
+void token_tree_free(token * t) {
+#ifdef kUseObjectPool
+       return;
+#else
+       token * n;
+
+       while (t != NULL) {
+               n = t->next;
+               token_free(t);
+
+               t = n;
+       }
+#endif
+}
+
+
+/// Forward declaration
+void print_token_tree(token * t, unsigned short depth, const char * string);
+
+
+/// Print contents of the token based on specified string
+void print_token(token * t, unsigned short depth, const char * string) {
+       if (t != NULL) {
+               for (int i = 0; i < depth; ++i)
+               {
+                       fprintf(stderr, "\t");
+               }
+               if (string == NULL) {
+                       fprintf(stderr, "* (%d) %lu:%lu\n", t->type, t->start, t->len);
+               } else {
+                       fprintf(stderr, "* (%d) %lu:%lu\t'%.*s'\n", t->type, t->start, t->len, (int)t->len, &string[t->start]);
+               }
+
+               if (t->child != NULL)
+                       print_token_tree(t->child, depth + 1, string);
+       }
+}
+
+
+/// Print contents of the token tree based on specified string
+void print_token_tree(token * t, unsigned short depth, const char * string) {
+       while (t != NULL) {
+               print_token(t, depth, string);
+
+               t = t->next;
+       }
+}
+
+
+/// Print a description of the token based on specified string
+void token_describe(token * t, const char * string) {
+       print_token(t, 0, string);
+}
+
+
+/// Print a description of the token tree based on specified string
+void token_tree_describe(token * t, const char * string) {
+       fprintf(stderr, "=====>\n");
+       while (t != NULL) {
+               print_token(t, 0, string);
+
+               t = t->next;
+       }
+       fprintf(stderr, "<=====\n");
+}
+
+
+/// Find the child node of a given parent that contains the specified
+/// offset position.
+token * token_child_for_offset(
+       token * parent,                                         //!< Pointer to parent token
+       size_t offset                                           //!< Search position
+) {
+       if (parent == NULL)
+               return NULL;
+
+       if ((parent->start > offset) ||
+               (parent->start + parent->len < offset))
+               return NULL;
+
+       token * walker = parent->child;
+
+       while (walker != NULL) {
+               if (walker->start <= offset) {
+                       if (walker->start + walker->len > offset) {
+                               return walker;
+                       }
+               }
+               if (walker->start > offset)
+                       return NULL;
+               
+               walker = walker->next;
+       }
+
+       return NULL;
+}
+
+
+/// Given two character ranges, see if they intersect (touching doesn't count)
+static bool ranges_intersect(size_t start1, size_t len1, size_t start2, size_t len2) {
+       return ((start1 < start2 + len2) && (start2 < start1 + len1)) ? true : false;
+}
+
+/// Find first child node of a given parent that intersects the specified
+/// offset range.
+token * token_first_child_in_range(
+       token * parent,                                         //!< Pointer to parent token
+       size_t start,                                           //!< Start search position
+       size_t len                                                      //!< Search length
+) {
+       if (parent == NULL)
+               return NULL;
+
+       if ((parent->start > start + len) ||
+               (parent->start + parent->len < start))
+               return NULL;
+
+       token * walker = parent->child;
+
+       while (walker != NULL) {
+               if (ranges_intersect(start, len, walker->start, walker->len))
+                       return walker;
+
+               if (walker->start > start)
+                       return NULL;
+
+               walker = walker->next;
+       }
+
+       return NULL;
+}
+
+
+/// Find last child node of a given parent that intersects the specified
+/// offset range.
+token * token_last_child_in_range(
+       token * parent,                                         //!< Pointer to parent token
+       size_t start,                                           //!< Start search position
+       size_t len                                                      //!< Search length
+) {
+       if (parent == NULL)
+               return NULL;
+
+       if ((parent->start > start + len) ||
+               (parent->start + parent->len < start))
+               return NULL;
+
+       token * walker = parent->child;
+       token * last = NULL;
+
+       while (walker != NULL) {
+               if (ranges_intersect(start, len, walker->start, walker->len))
+                       last = walker;
+
+               if (walker->start > start + len)
+                       return last;
+
+               walker = walker->next;
+       }
+
+       return last;
+}
+
+
+void token_trim_leading_whitespace(token * t, const char * string) {
+       while (t->len && char_is_whitespace(string[t->start])) {
+               t->start++;
+               t->len--;
+       }
+}
+
+
+void token_trim_trailing_whitespace(token * t, const char * string) {
+       while (t->len && char_is_whitespace(string[t->start + t->len - 1])) {
+               t->len--;
+       }
+}
+
+
+void token_trim_whitespace(token * t, const char * string) {
+       token_trim_leading_whitespace(t, string);
+       token_trim_trailing_whitespace(t, string);
+}
+
+
+/// Check whether first token in the chain matches the given type.
+/// If so, return and advance the chain.
+token * token_chain_accept(token ** t, short type) {
+       token * result = NULL;
+
+       if (t && *t && ((*t)->type == type)) {
+               result = *t;
+               *t = (*t)->next;
+       }
+
+       return result;
+}
+
+
+/// Allow checking for multiple token types
+token * token_chain_accept_multiple(token ** t, int n, ...) {
+       token * result = NULL;
+       va_list valist;
+
+       va_start(valist, n);
+
+       for (int i = 0; i < n; ++i)
+       {
+               result = token_chain_accept(t, va_arg(valist, int));
+               if (result)
+                       break;
+       }
+
+       va_end(valist);
+
+       return result;
+}
+
+
+void token_skip_until_type(token ** t, short type) {
+       while ((*t) && ((*t)->type != type))
+               *t = (*t)->next;
+}
+
+
+/// Allow checking for multiple token types
+void token_skip_until_type_multiple(token ** t, int n, ...) {
+       va_list valist;
+       int type[n];
+
+       va_start(valist, n);
+
+       // Load target types
+       for (int i = 0; i < n; ++i)
+       {
+               type[i] = va_arg(valist, int);
+       }
+
+       // 
+       while (*t) {
+               for (int i = 0; i < n; ++i)
+               {
+                       if ((*t)->type == type[i])
+                               return;
+               }
+
+               *t = (*t)->next;
+       }
+
+       va_end(valist);
+}
+
+
+void token_split_on_char(token * t, const char * source, const char c) {
+       if (!t)
+               return;
+
+       size_t start = t->start;
+       size_t pos = 0;
+       size_t stop = t->len;
+       token * new = NULL;
+
+       while (pos + 1 < stop) {
+               if (source[start + pos] == c){
+                       new = token_new(t->type, start + pos + 1, stop - (pos + 1));
+                       new->next = t->next;
+                       t->next = new;
+                       
+                       t->len = pos;
+                       
+                       t = t->next;
+               }
+
+               pos++;
+       }
+}
+
diff --git a/src/token.h b/src/token.h
new file mode 100644 (file)
index 0000000..080f635
--- /dev/null
@@ -0,0 +1,223 @@
+/**
+
+       Parser-Template -- Boilerplate parser example using re2c lexer and lemon parser.
+
+       @file token.h
+
+       @brief Structure and functions to manage tokens representing portions of a
+       text string.
+
+
+       @author Fletcher T. Penney
+
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+#ifndef TOKEN_PARSER_TEMPLATE_H
+#define TOKEN_PARSER_TEMPLATE_H
+
+
+#define kUseObjectPool 1               //!< Use an object pool to allocate tokens to improve
+                                                                               //!< performance in memory allocation. Frees all
+                                                                               //!< tokens at once, however, at end of parsing.
+
+
+#ifdef kUseObjectPool
+void token_pool_init(void);                            //!< Initialize object pool for allocating tokens
+void token_pool_drain(void);                   //!< Drain pool to free memory when parse complete
+void token_pool_free(void);                            //!< Free the token object pool
+#endif
+
+
+/// Definition for token node struct.  This can be used to match an
+/// abstract syntax tree with the appropriate spans in the original
+/// source string.
+struct token {
+       unsigned short          type;                   //!< Type for the token
+       short                           can_open;               //!< Can token open a matched pair?
+       short                           can_close;              //!< Can token close a matched pair?
+       short                           unmatched;              //!< Has token been matched yet?
+
+       size_t                          start;                  //!< Starting offset in the source string
+       size_t                          len;                    //!< Length of the token in the source string
+
+       struct token *          next;                   //!< Pointer to next token in the chain
+       struct token *          prev;                   //!< Pointer to previous marker in the chain
+       struct token *          child;                  //!< Pointer to child chain
+
+       struct token *          tail;                   //!< Pointer to last token in the chain
+
+       struct token *          mate;                   //!< Pointer to other token in matched pair
+};
+
+typedef struct token token;
+
+
+/// Get pointer to a new token
+token * token_new(
+       unsigned short type,                            //!< Type for new token
+       size_t start,                                           //!< Starting offset for token
+       size_t len                                                      //!< Len of token
+);
+
+/// Create a parent for a chain of tokens
+token * token_new_parent(
+       token * child,                                          //!< Pointer to child token chain
+       unsigned short type                                     //!< Type for new token
+);
+
+/// Add a new token to the end of a token chain.  The new token
+/// may or may not also be the start of a chain
+void token_chain_append(
+       token * chain_start,                            //!< Pointer to start of token chain
+       token * t                                                       //!< Pointer to token to append
+);
+
+/// Add a new token to the end of a parent's child
+/// token chain.  The new token may or may not be
+/// the start of a chain.
+void token_append_child(
+       token * parent,                                         //!< Pointer to parent node
+       token * t                                                       //!< Pointer to token to append
+);
+
+/// Remove the first child of a token
+void token_remove_first_child(
+       token * parent                                          //!< Pointer to parent node
+);
+
+/// Remove the last child of a token
+void token_remove_last_child(
+       token * parent                                          //!< Pointer to parent node
+);
+
+/// Remove the last token in a chain
+void token_remove_tail(token * head);
+
+/// Pop token out of it's chain, connecting head and tail of chain back together.
+/// Token must be freed if it is no longer needed.
+void token_pop_link_from_chain(
+       token * t                                                       //!< Pointer to token to remove
+);
+
+/// Remove one or more tokens from chain
+void tokens_prune(
+       token * first,                                          //!< Pointer to first node to be removed
+       token * last                                            //!< Pointer to last node to be removed
+);
+
+/// Given a start/stop point in token chain, create a new parent token.
+/// Reinsert the new parent in place of the removed segment.
+/// Return pointer to new container token.
+token * token_prune_graft(
+       token * first,                                          //!< Pointer to first node to be removed
+       token * last,                                           //!< Pointer to last node to be removed
+       unsigned short container_type           //!< Type for new parent node for removed section
+);
+
+/// Free token
+void token_free(
+       token * t                                                       //!< Pointer to token to be freed
+);
+
+/// Free token tree
+void token_tree_free(
+       token * t                                                       //!< Pointer to token to be freed
+);
+
+/// Print a description of the token based on specified string
+void token_describe(
+       token * t,                                                      //!< Pointer to token to described
+       const char * string                                     //!< Source string
+);
+
+/// Print a description of the token tree based on specified string
+void token_tree_describe(
+       token * t,                                                      //!< Pointer to token to described
+       const char * string                                     //!< Source string
+);
+
+/// Find the child node of a given parent that contains the specified
+/// offset position.
+token * token_child_for_offset(
+       token * parent,                                         //!< Pointer to parent token
+       size_t offset                                           //!< Search position
+);
+
+/// Find first child node of a given parent that intersects the specified
+/// offset range.
+token * token_first_child_in_range(
+       token * parent,                                         //!< Pointer to parent token
+       size_t start,                                           //!< Start search position
+       size_t len                                                      //!< Search length
+);
+
+/// Find last child node of a given parent that intersects the specified
+/// offset range.
+token * token_last_child_in_range(
+       token * parent,                                         //!< Pointer to parent token
+       size_t start,                                           //!< Start search position
+       size_t len                                                      //!< Search length
+);
+
+void token_trim_leading_whitespace(token * t, const char * string);
+
+void token_trim_trailing_whitespace(token * t, const char * string);
+
+void token_trim_whitespace(token * t, const char * string);
+
+
+///
+token * token_chain_accept(token ** t, short type);
+
+token * token_chain_accept_multiple(token ** t, int n, ...);
+
+void token_skip_until_type(token ** t, short type);
+
+void token_skip_until_type_multiple(token ** t, int n, ...);
+
+void token_split_on_char(token * t, const char * source, const char c);
+
+#endif
+
diff --git a/src/token_pairs.c b/src/token_pairs.c
new file mode 100644 (file)
index 0000000..29dd3da
--- /dev/null
@@ -0,0 +1,230 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file token_pairs.c
+
+       @brief  Allow for pairing certain tokens together (e.g. '[' and ']') to create
+       more meaningful token trees.
+
+
+       @author Fletcher T. Penney
+       @bug
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stack.h"
+#include "token.h"
+#include "token_pairs.h"
+
+
+/// Create a new token pair engine
+token_pair_engine * token_pair_engine_new(void) {
+       token_pair_engine * e = malloc(sizeof(token_pair_engine));
+
+       if (e) {
+               unsigned short empty[kMaxTokenTypes] = {0};
+               unsigned short empty2[kMaxTokenTypes][kMaxTokenTypes] = {{0}};
+
+               memcpy(e->can_open_pair, empty, sizeof(unsigned short) * kMaxTokenTypes);
+               memcpy(e->can_close_pair, empty, sizeof(unsigned short) * kMaxTokenTypes);
+
+               memcpy(e->pair_type, empty2, sizeof(unsigned short) * kMaxTokenTypes * kMaxTokenTypes);
+
+               memcpy(e->empty_allowed, empty, sizeof(unsigned short) * kMaxTokenTypes);
+               memcpy(e->match_len, empty, sizeof(unsigned short) * kMaxTokenTypes);
+               memcpy(e->should_prune, empty, sizeof(unsigned short) * kMaxTokenTypes);
+       }
+
+       return e;
+}
+
+
+/// Free existing token pair engine
+void token_pair_engine_free(token_pair_engine * e) {
+       if (e == NULL)
+               return;
+
+       free(e);
+}
+
+
+/// Add a new pairing configuration to a token pair engine
+void token_pair_engine_add_pairing(token_pair_engine * e, unsigned short open_type, unsigned short close_type,
+       unsigned short pair_type, int options) {
+       // \todo: This needs to be more sophisticated
+       e->can_open_pair[open_type] = 1;
+       e->can_close_pair[close_type] = 1;
+       (e->pair_type)[open_type][close_type] = pair_type;
+
+       if (options & PAIRING_ALLOW_EMPTY)
+               e->empty_allowed[pair_type] = true;
+
+       if (options & PAIRING_MATCH_LENGTH)
+               e->match_len[pair_type] = true;
+
+       if (options & PAIRING_PRUNE_MATCH)
+               e->should_prune[pair_type] = true;
+
+}
+
+
+/// Mate opener and closer together
+void token_pair_mate(token * a, token * b) {
+       if (a == NULL | b  == NULL)
+               return;
+
+       a->mate = b;
+       a->unmatched = false;
+
+       b->mate = a;
+       b->unmatched = false;
+}
+
+
+/// Search a token's childen for matching pairs
+void token_pairs_match_pairs_inside_token(token * parent, token_pair_engine * e, stack * s) {
+//     if ((parent == NULL) || 
+//             (parent->child == NULL) ||
+//             (e == NULL)) {
+//             return;
+//     }
+
+       // Walk the child chain
+       token * walker = parent->child;
+
+       // Counter
+       size_t start_counter = s->size;
+       size_t i = start_counter;                       // We're sharing one stack, so any opener earlier than this belongs to a parent
+
+       token * peek;
+       unsigned short pair_type;
+
+       while (walker != NULL) {
+
+               if (walker->child) {
+                       token_pairs_match_pairs_inside_token(walker, e, s);
+               }
+
+               // Is this a closer?
+               if (e->can_close_pair[walker->type] && walker->can_close && walker->unmatched ) {
+                       // Do we have a valid opener in the stack?
+                       i = s->size;
+
+                       while (i > start_counter) {
+                               peek = stack_peek_index(s, i - 1);
+
+                               pair_type = e->pair_type[peek->type][walker->type];
+
+                               if (pair_type) {
+                                       if (!e->empty_allowed[pair_type]) {
+                                               // Make sure they aren't consecutive tokens
+                                               if ((peek->next == walker) &&
+                                                       (peek->start + peek->len == walker->start)) {
+                                                       // i--;
+                                                       i = start_counter;      // In this situation, we can't use this token as a closer
+                                                       continue;
+                                               }
+                                       }
+
+                                       if (e->match_len[pair_type]) {
+                                               // Lengths must match
+                                               if (peek->len != walker->len) {
+                                                       i--;
+                                                       continue;
+                                               }
+                                       }
+
+                                       token_pair_mate(peek, walker);
+
+                                       // Clear portion of stack between opener and closer as they are now unavailable for mating
+                                       s->size = i - 1;
+#ifndef NDEBUG
+                                       fprintf(stderr, "stack now sized %lu\n", s->size);
+#endif
+                                       // Prune matched section
+
+                                       if (e->should_prune[pair_type]) {
+                                               if (peek->prev == NULL) {
+                                                       walker = token_prune_graft(peek, walker, e->pair_type[peek->type][walker->type]);
+                                                       parent->child = walker;
+                                               } else {
+                                                       walker = token_prune_graft(peek, walker, e->pair_type[peek->type][walker->type]);
+                                               }
+                                       }
+
+                                       break;
+                               }
+#ifndef NDEBUG
+                               else {
+                                       fprintf(stderr, "token type %d failed to match stack element\n", walker->type);
+                               }
+#endif
+                               i--;
+                       }
+               }
+
+               // Is this an opener?
+               // \todo: Need to verify that token->type is a valid opening token for some pairing
+               if (e->can_open_pair[walker->type] && walker->can_open && walker->unmatched) {
+                       stack_push(s, walker);
+#ifndef NDEBUG
+               fprintf(stderr, "push token type %d to stack (%lu elements)\n", walker->type, s->size);
+#endif
+               }
+
+               walker = walker->next;
+       }
+
+#ifndef NDEBUG
+       fprintf(stderr, "token stack has %lu elements (of %lu)\n", s->size, s->capacity);
+#endif
+
+       // Remove unused tokens from stack and return to parent
+       s->size = start_counter;
+}
diff --git a/src/token_pairs.h b/src/token_pairs.h
new file mode 100644 (file)
index 0000000..07f6b14
--- /dev/null
@@ -0,0 +1,119 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file token_pairs.h
+
+       @brief  Allow for pairing certain tokens together (e.g. '[' and ']') to create
+       more meaningful token trees.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+
+#ifndef TOKEN_PAIRS_MULTIMARKDOWN_H
+#define TOKEN_PAIRS_MULTIMARKDOWN_H
+
+#include "stack.h"
+#include "token.h"
+
+
+#ifdef TEST
+#include "CuTest.h"
+#endif
+
+#define kMaxTokenTypes 200             // This needs to be larger than the largest token type being used
+
+/// Store information about which tokens can be paired, and what actions to take when 
+/// pairing them.
+struct token_pair_engine {
+       unsigned short          can_open_pair[kMaxTokenTypes];                          //!< Can token type open a pair?
+       unsigned short          can_close_pair[kMaxTokenTypes];                         //!< Can token type close a pair?
+
+       unsigned short          pair_type[kMaxTokenTypes][kMaxTokenTypes];      //!< Which pair are we forming?
+
+       unsigned short          empty_allowed[kMaxTokenTypes];                          //!< Is this pair type allowed to be empty?
+       unsigned short          match_len[kMaxTokenTypes];                                      //!< Does this pair type require matched lengths of openers/closers?
+       unsigned short          should_prune[kMaxTokenTypes];                           //!< Does this pair type need to be pruned to a child token chain?
+};
+
+typedef struct token_pair_engine token_pair_engine;
+
+
+/// Flags for token pair options
+enum pairings_options {
+       PAIRING_ALLOW_EMPTY             = 1 << 0,               //!< Allow consecutive tokens to match with each other
+       PAIRING_MATCH_LENGTH    = 1 << 1,               //!< Require that opening/closing tokens be same length
+       PAIRING_PRUNE_MATCH             = 1 << 2,               //!< Move the matched sub-chain into a child chain
+};
+
+
+/// Create a new token pair engine
+token_pair_engine * token_pair_engine_new(void);
+
+/// Free existing token pair engine
+void token_pair_engine_free(
+       token_pair_engine * e                                   //!< Token pair engine to be freed
+);
+
+/// Add a new pairing configuration to a token pair engine
+void token_pair_engine_add_pairing(
+       token_pair_engine * e,                                  //!< Token pair engine to add to
+       unsigned short open_type,                               //!< Token type for opener
+       unsigned short close_type,                              //!< Token type for closer
+       unsigned short pair_type,                               //!< Token type for pairing
+       int options                                                             //!< Token pair options to use
+);
+
+/// Search a token's childen for matching pairs
+void token_pairs_match_pairs_inside_token(
+       token * parent,                                                 //!< Which tokens should we search for pairs
+       token_pair_engine * e,                                  //!< Token pair engine to be used for matching
+       stack * s                                                               //!< Pointer to a stack to use for pairing tokens
+);
+
+
+#endif
diff --git a/src/uthash.h b/src/uthash.h
new file mode 100644 (file)
index 0000000..45d1f9f
--- /dev/null
@@ -0,0 +1,1074 @@
+/*
+Copyright (c) 2003-2016, Troy D. Hanson     http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+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.
+*/
+
+#ifndef UTHASH_H
+#define UTHASH_H
+
+#define UTHASH_VERSION 2.0.1
+
+#include <string.h>   /* memcmp,strlen */
+#include <stddef.h>   /* ptrdiff_t */
+#include <stdlib.h>   /* exit() */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+   As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+   when compiling c++ source) this code uses whatever method is needed
+   or, for VS2008 where neither is available, uses casting workarounds. */
+#if defined(_MSC_VER)   /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus)  /* VS2010 or newer in C++ mode */
+#define DECLTYPE(x) (decltype(x))
+#else                   /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#define DECLTYPE(x)
+#endif
+#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__)
+#define NO_DECLTYPE
+#define DECLTYPE(x)
+#else                   /* GNU, Sun and other compilers */
+#define DECLTYPE(x) (__typeof(x))
+#endif
+
+#ifdef NO_DECLTYPE
+#define DECLTYPE_ASSIGN(dst,src)                                                 \
+do {                                                                             \
+  char **_da_dst = (char**)(&(dst));                                             \
+  *_da_dst = (char*)(src);                                                       \
+} while (0)
+#else
+#define DECLTYPE_ASSIGN(dst,src)                                                 \
+do {                                                                             \
+  (dst) = DECLTYPE(dst)(src);                                                    \
+} while (0)
+#endif
+
+/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */
+#if defined(_WIN32)
+#if defined(_MSC_VER) && _MSC_VER >= 1600
+#include <stdint.h>
+#elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__)
+#include <stdint.h>
+#else
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+#endif
+#elif defined(__GNUC__) && !defined(__VXWORKS__)
+#include <stdint.h>
+#else
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+#endif
+
+#ifndef uthash_fatal
+#define uthash_fatal(msg) exit(-1)        /* fatal error (out of memory,etc) */
+#endif
+#ifndef uthash_malloc
+#define uthash_malloc(sz) malloc(sz)      /* malloc fcn                      */
+#endif
+#ifndef uthash_free
+#define uthash_free(ptr,sz) free(ptr)     /* free fcn                        */
+#endif
+#ifndef uthash_strlen
+#define uthash_strlen(s) strlen(s)
+#endif
+#ifndef uthash_memcmp
+#define uthash_memcmp(a,b,n) memcmp(a,b,n)
+#endif
+
+#ifndef uthash_noexpand_fyi
+#define uthash_noexpand_fyi(tbl)          /* can be defined to log noexpand  */
+#endif
+#ifndef uthash_expand_fyi
+#define uthash_expand_fyi(tbl)            /* can be defined to log expands   */
+#endif
+
+/* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS 32U     /* initial number of buckets        */
+#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */
+#define HASH_BKT_CAPACITY_THRESH 10U     /* expand when bucket count reaches */
+
+/* calculate the element whose hash handle address is hhp */
+#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
+/* calculate the hash handle from element address elp */
+#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho)))
+
+#define HASH_VALUE(keyptr,keylen,hashv)                                          \
+do {                                                                             \
+  HASH_FCN(keyptr, keylen, hashv);                                               \
+} while (0)
+
+#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out)                 \
+do {                                                                             \
+  (out) = NULL;                                                                  \
+  if (head) {                                                                    \
+    unsigned _hf_bkt;                                                            \
+    HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt);                  \
+    if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) {                         \
+      HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \
+    }                                                                            \
+  }                                                                              \
+} while (0)
+
+#define HASH_FIND(hh,head,keyptr,keylen,out)                                     \
+do {                                                                             \
+  unsigned _hf_hashv;                                                            \
+  HASH_VALUE(keyptr, keylen, _hf_hashv);                                         \
+  HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out);               \
+} while (0)
+
+#ifdef HASH_BLOOM
+#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM)
+#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL)
+#define HASH_BLOOM_MAKE(tbl)                                                     \
+do {                                                                             \
+  (tbl)->bloom_nbits = HASH_BLOOM;                                               \
+  (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN);                 \
+  if (!((tbl)->bloom_bv))  { uthash_fatal( "out of memory"); }                   \
+  memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN);                                \
+  (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE;                                       \
+} while (0)
+
+#define HASH_BLOOM_FREE(tbl)                                                     \
+do {                                                                             \
+  uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN);                              \
+} while (0)
+
+#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U)))
+#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U)))
+
+#define HASH_BLOOM_ADD(tbl,hashv)                                                \
+  HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U)))
+
+#define HASH_BLOOM_TEST(tbl,hashv)                                               \
+  HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U)))
+
+#else
+#define HASH_BLOOM_MAKE(tbl)
+#define HASH_BLOOM_FREE(tbl)
+#define HASH_BLOOM_ADD(tbl,hashv)
+#define HASH_BLOOM_TEST(tbl,hashv) (1)
+#define HASH_BLOOM_BYTELEN 0U
+#endif
+
+#define HASH_MAKE_TABLE(hh,head)                                                 \
+do {                                                                             \
+  (head)->hh.tbl = (UT_hash_table*)uthash_malloc(                                \
+                  sizeof(UT_hash_table));                                        \
+  if (!((head)->hh.tbl))  { uthash_fatal( "out of memory"); }                    \
+  memset((head)->hh.tbl, 0, sizeof(UT_hash_table));                              \
+  (head)->hh.tbl->tail = &((head)->hh);                                          \
+  (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS;                        \
+  (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2;              \
+  (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head);                    \
+  (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc(                      \
+          HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket));               \
+  if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); }             \
+  memset((head)->hh.tbl->buckets, 0,                                             \
+          HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket));               \
+  HASH_BLOOM_MAKE((head)->hh.tbl);                                               \
+  (head)->hh.tbl->signature = HASH_SIGNATURE;                                    \
+} while (0)
+
+#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \
+do {                                                                             \
+  (replaced) = NULL;                                                             \
+  HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \
+  if (replaced) {                                                                \
+     HASH_DELETE(hh, head, replaced);                                            \
+  }                                                                              \
+  HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \
+} while (0)
+
+#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \
+do {                                                                             \
+  (replaced) = NULL;                                                             \
+  HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \
+  if (replaced) {                                                                \
+     HASH_DELETE(hh, head, replaced);                                            \
+  }                                                                              \
+  HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \
+} while (0)
+
+#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced)                   \
+do {                                                                             \
+  unsigned _hr_hashv;                                                            \
+  HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv);                         \
+  HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \
+} while (0)
+
+#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn)    \
+do {                                                                             \
+  unsigned _hr_hashv;                                                            \
+  HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv);                         \
+  HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \
+} while (0)
+
+#define HASH_APPEND_LIST(hh, head, add)                                          \
+do {                                                                             \
+  (add)->hh.next = NULL;                                                         \
+  (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail);           \
+  (head)->hh.tbl->tail->next = (add);                                            \
+  (head)->hh.tbl->tail = &((add)->hh);                                           \
+} while (0)
+
+#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \
+do {                                                                             \
+  unsigned _ha_bkt;                                                              \
+  (add)->hh.hashv = (hashval);                                                   \
+  (add)->hh.key = (char*) (keyptr);                                              \
+  (add)->hh.keylen = (unsigned) (keylen_in);                                     \
+  if (!(head)) {                                                                 \
+    (add)->hh.next = NULL;                                                       \
+    (add)->hh.prev = NULL;                                                       \
+    (head) = (add);                                                              \
+    HASH_MAKE_TABLE(hh, head);                                                   \
+  } else {                                                                       \
+    struct UT_hash_handle *_hs_iter = &(head)->hh;                               \
+    (add)->hh.tbl = (head)->hh.tbl;                                              \
+    do {                                                                         \
+      if (cmpfcn(DECLTYPE(head) ELMT_FROM_HH((head)->hh.tbl, _hs_iter), add) > 0) \
+        break;                                                                   \
+    } while ((_hs_iter = _hs_iter->next));                                       \
+    if (_hs_iter) {                                                              \
+      (add)->hh.next = _hs_iter;                                                 \
+      if (((add)->hh.prev = _hs_iter->prev)) {                                   \
+        HH_FROM_ELMT((head)->hh.tbl, _hs_iter->prev)->next = (add);              \
+      } else {                                                                   \
+        (head) = (add);                                                          \
+      }                                                                          \
+      _hs_iter->prev = (add);                                                    \
+    } else {                                                                     \
+      HASH_APPEND_LIST(hh, head, add);                                           \
+    }                                                                            \
+  }                                                                              \
+  (head)->hh.tbl->num_items++;                                                   \
+  HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt);                    \
+  HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh);                 \
+  HASH_BLOOM_ADD((head)->hh.tbl, hashval);                                       \
+  HASH_EMIT_KEY(hh, head, keyptr, keylen_in);                                    \
+  HASH_FSCK(hh, head);                                                           \
+} while (0)
+
+#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn)             \
+do {                                                                             \
+  unsigned _hs_hashv;                                                            \
+  HASH_VALUE(keyptr, keylen_in, _hs_hashv);                                      \
+  HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \
+} while (0)
+
+#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \
+  HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn)
+
+#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn)                 \
+  HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn)
+
+#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add)        \
+do {                                                                             \
+  unsigned _ha_bkt;                                                              \
+  (add)->hh.hashv = (hashval);                                                   \
+  (add)->hh.key = (char*) (keyptr);                                              \
+  (add)->hh.keylen = (unsigned) (keylen_in);                                     \
+  if (!(head)) {                                                                 \
+    (add)->hh.next = NULL;                                                       \
+    (add)->hh.prev = NULL;                                                       \
+    (head) = (add);                                                              \
+    HASH_MAKE_TABLE(hh, head);                                                   \
+  } else {                                                                       \
+    (add)->hh.tbl = (head)->hh.tbl;                                              \
+    HASH_APPEND_LIST(hh, head, add);                                             \
+  }                                                                              \
+  (head)->hh.tbl->num_items++;                                                   \
+  HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt);                    \
+  HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh);                 \
+  HASH_BLOOM_ADD((head)->hh.tbl, hashval);                                       \
+  HASH_EMIT_KEY(hh, head, keyptr, keylen_in);                                    \
+  HASH_FSCK(hh, head);                                                           \
+} while (0)
+
+#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add)                            \
+do {                                                                             \
+  unsigned _ha_hashv;                                                            \
+  HASH_VALUE(keyptr, keylen_in, _ha_hashv);                                      \
+  HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add);      \
+} while (0)
+
+#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add)            \
+  HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add)
+
+#define HASH_ADD(hh,head,fieldname,keylen_in,add)                                \
+  HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add)
+
+#define HASH_TO_BKT(hashv,num_bkts,bkt)                                          \
+do {                                                                             \
+  bkt = ((hashv) & ((num_bkts) - 1U));                                           \
+} while (0)
+
+/* delete "delptr" from the hash table.
+ * "the usual" patch-up process for the app-order doubly-linked-list.
+ * The use of _hd_hh_del below deserves special explanation.
+ * These used to be expressed using (delptr) but that led to a bug
+ * if someone used the same symbol for the head and deletee, like
+ *  HASH_DELETE(hh,users,users);
+ * We want that to work, but by changing the head (users) below
+ * we were forfeiting our ability to further refer to the deletee (users)
+ * in the patch-up process. Solution: use scratch space to
+ * copy the deletee pointer, then the latter references are via that
+ * scratch pointer rather than through the repointed (users) symbol.
+ */
+#define HASH_DELETE(hh,head,delptr)                                              \
+do {                                                                             \
+    struct UT_hash_handle *_hd_hh_del;                                           \
+    if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) )  {         \
+        uthash_free((head)->hh.tbl->buckets,                                     \
+                    (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+        HASH_BLOOM_FREE((head)->hh.tbl);                                         \
+        uthash_free((head)->hh.tbl, sizeof(UT_hash_table));                      \
+        head = NULL;                                                             \
+    } else {                                                                     \
+        unsigned _hd_bkt;                                                        \
+        _hd_hh_del = &((delptr)->hh);                                            \
+        if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) {     \
+            (head)->hh.tbl->tail =                                               \
+                (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) +               \
+                (head)->hh.tbl->hho);                                            \
+        }                                                                        \
+        if ((delptr)->hh.prev != NULL) {                                         \
+            ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) +                  \
+                    (head)->hh.tbl->hho))->next = (delptr)->hh.next;             \
+        } else {                                                                 \
+            DECLTYPE_ASSIGN(head,(delptr)->hh.next);                             \
+        }                                                                        \
+        if (_hd_hh_del->next != NULL) {                                          \
+            ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next +                     \
+                    (head)->hh.tbl->hho))->prev =                                \
+                    _hd_hh_del->prev;                                            \
+        }                                                                        \
+        HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt);   \
+        HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del);        \
+        (head)->hh.tbl->num_items--;                                             \
+    }                                                                            \
+    HASH_FSCK(hh,head);                                                          \
+} while (0)
+
+
+/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
+#define HASH_FIND_STR(head,findstr,out)                                          \
+    HASH_FIND(hh,head,findstr,(unsigned)uthash_strlen(findstr),out)
+#define HASH_ADD_STR(head,strfield,add)                                          \
+    HASH_ADD(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add)
+#define HASH_REPLACE_STR(head,strfield,add,replaced)                             \
+    HASH_REPLACE(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add,replaced)
+#define HASH_FIND_INT(head,findint,out)                                          \
+    HASH_FIND(hh,head,findint,sizeof(int),out)
+#define HASH_ADD_INT(head,intfield,add)                                          \
+    HASH_ADD(hh,head,intfield,sizeof(int),add)
+#define HASH_REPLACE_INT(head,intfield,add,replaced)                             \
+    HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced)
+#define HASH_FIND_PTR(head,findptr,out)                                          \
+    HASH_FIND(hh,head,findptr,sizeof(void *),out)
+#define HASH_ADD_PTR(head,ptrfield,add)                                          \
+    HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
+#define HASH_REPLACE_PTR(head,ptrfield,add,replaced)                             \
+    HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced)
+#define HASH_DEL(head,delptr)                                                    \
+    HASH_DELETE(hh,head,delptr)
+
+/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
+ * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
+ */
+#ifdef HASH_DEBUG
+#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
+#define HASH_FSCK(hh,head)                                                       \
+do {                                                                             \
+    struct UT_hash_handle *_thh;                                                 \
+    if (head) {                                                                  \
+        unsigned _bkt_i;                                                         \
+        unsigned _count;                                                         \
+        char *_prev;                                                             \
+        _count = 0;                                                              \
+        for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) {       \
+            unsigned _bkt_count = 0;                                             \
+            _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head;                      \
+            _prev = NULL;                                                        \
+            while (_thh) {                                                       \
+               if (_prev != (char*)(_thh->hh_prev)) {                            \
+                   HASH_OOPS("invalid hh_prev %p, actual %p\n",                  \
+                    _thh->hh_prev, _prev );                                      \
+               }                                                                 \
+               _bkt_count++;                                                     \
+               _prev = (char*)(_thh);                                            \
+               _thh = _thh->hh_next;                                             \
+            }                                                                    \
+            _count += _bkt_count;                                                \
+            if ((head)->hh.tbl->buckets[_bkt_i].count !=  _bkt_count) {          \
+               HASH_OOPS("invalid bucket count %u, actual %u\n",                 \
+                (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count);              \
+            }                                                                    \
+        }                                                                        \
+        if (_count != (head)->hh.tbl->num_items) {                               \
+            HASH_OOPS("invalid hh item count %u, actual %u\n",                   \
+                (head)->hh.tbl->num_items, _count );                             \
+        }                                                                        \
+        /* traverse hh in app order; check next/prev integrity, count */         \
+        _count = 0;                                                              \
+        _prev = NULL;                                                            \
+        _thh =  &(head)->hh;                                                     \
+        while (_thh) {                                                           \
+           _count++;                                                             \
+           if (_prev !=(char*)(_thh->prev)) {                                    \
+              HASH_OOPS("invalid prev %p, actual %p\n",                          \
+                    _thh->prev, _prev );                                         \
+           }                                                                     \
+           _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh);                    \
+           _thh = ( _thh->next ?  (UT_hash_handle*)((char*)(_thh->next) +        \
+                                  (head)->hh.tbl->hho) : NULL );                 \
+        }                                                                        \
+        if (_count != (head)->hh.tbl->num_items) {                               \
+            HASH_OOPS("invalid app item count %u, actual %u\n",                  \
+                (head)->hh.tbl->num_items, _count );                             \
+        }                                                                        \
+    }                                                                            \
+} while (0)
+#else
+#define HASH_FSCK(hh,head)
+#endif
+
+/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
+ * the descriptor to which this macro is defined for tuning the hash function.
+ * The app can #include <unistd.h> to get the prototype for write(2). */
+#ifdef HASH_EMIT_KEYS
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)                                   \
+do {                                                                             \
+    unsigned _klen = fieldlen;                                                   \
+    write(HASH_EMIT_KEYS, &_klen, sizeof(_klen));                                \
+    write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen);                      \
+} while (0)
+#else
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
+#endif
+
+/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
+#ifdef HASH_FUNCTION
+#define HASH_FCN HASH_FUNCTION
+#else
+#define HASH_FCN HASH_JEN
+#endif
+
+/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */
+#define HASH_BER(key,keylen,hashv)                                               \
+do {                                                                             \
+  unsigned _hb_keylen=(unsigned)keylen;                                          \
+  const unsigned char *_hb_key=(const unsigned char*)(key);                      \
+  (hashv) = 0;                                                                   \
+  while (_hb_keylen-- != 0U) {                                                   \
+      (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++;                         \
+  }                                                                              \
+} while (0)
+
+
+/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
+ * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
+#define HASH_SAX(key,keylen,hashv)                                               \
+do {                                                                             \
+  unsigned _sx_i;                                                                \
+  const unsigned char *_hs_key=(const unsigned char*)(key);                      \
+  hashv = 0;                                                                     \
+  for(_sx_i=0; _sx_i < keylen; _sx_i++) {                                        \
+      hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i];                     \
+  }                                                                              \
+} while (0)
+/* FNV-1a variation */
+#define HASH_FNV(key,keylen,hashv)                                               \
+do {                                                                             \
+  unsigned _fn_i;                                                                \
+  const unsigned char *_hf_key=(const unsigned char*)(key);                      \
+  hashv = 2166136261U;                                                           \
+  for(_fn_i=0; _fn_i < keylen; _fn_i++) {                                        \
+      hashv = hashv ^ _hf_key[_fn_i];                                            \
+      hashv = hashv * 16777619U;                                                 \
+  }                                                                              \
+} while (0)
+
+#define HASH_OAT(key,keylen,hashv)                                               \
+do {                                                                             \
+  unsigned _ho_i;                                                                \
+  const unsigned char *_ho_key=(const unsigned char*)(key);                      \
+  hashv = 0;                                                                     \
+  for(_ho_i=0; _ho_i < keylen; _ho_i++) {                                        \
+      hashv += _ho_key[_ho_i];                                                   \
+      hashv += (hashv << 10);                                                    \
+      hashv ^= (hashv >> 6);                                                     \
+  }                                                                              \
+  hashv += (hashv << 3);                                                         \
+  hashv ^= (hashv >> 11);                                                        \
+  hashv += (hashv << 15);                                                        \
+} while (0)
+
+#define HASH_JEN_MIX(a,b,c)                                                      \
+do {                                                                             \
+  a -= b; a -= c; a ^= ( c >> 13 );                                              \
+  b -= c; b -= a; b ^= ( a << 8 );                                               \
+  c -= a; c -= b; c ^= ( b >> 13 );                                              \
+  a -= b; a -= c; a ^= ( c >> 12 );                                              \
+  b -= c; b -= a; b ^= ( a << 16 );                                              \
+  c -= a; c -= b; c ^= ( b >> 5 );                                               \
+  a -= b; a -= c; a ^= ( c >> 3 );                                               \
+  b -= c; b -= a; b ^= ( a << 10 );                                              \
+  c -= a; c -= b; c ^= ( b >> 15 );                                              \
+} while (0)
+
+#define HASH_JEN(key,keylen,hashv)                                               \
+do {                                                                             \
+  unsigned _hj_i,_hj_j,_hj_k;                                                    \
+  unsigned const char *_hj_key=(unsigned const char*)(key);                      \
+  hashv = 0xfeedbeefu;                                                           \
+  _hj_i = _hj_j = 0x9e3779b9u;                                                   \
+  _hj_k = (unsigned)(keylen);                                                    \
+  while (_hj_k >= 12U) {                                                         \
+    _hj_i +=    (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 )                      \
+        + ( (unsigned)_hj_key[2] << 16 )                                         \
+        + ( (unsigned)_hj_key[3] << 24 ) );                                      \
+    _hj_j +=    (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 )                      \
+        + ( (unsigned)_hj_key[6] << 16 )                                         \
+        + ( (unsigned)_hj_key[7] << 24 ) );                                      \
+    hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 )                         \
+        + ( (unsigned)_hj_key[10] << 16 )                                        \
+        + ( (unsigned)_hj_key[11] << 24 ) );                                     \
+                                                                                 \
+     HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                          \
+                                                                                 \
+     _hj_key += 12;                                                              \
+     _hj_k -= 12U;                                                               \
+  }                                                                              \
+  hashv += (unsigned)(keylen);                                                   \
+  switch ( _hj_k ) {                                                             \
+     case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */        \
+     case 10: hashv += ( (unsigned)_hj_key[9] << 16 );  /* FALLTHROUGH */        \
+     case 9:  hashv += ( (unsigned)_hj_key[8] << 8 );   /* FALLTHROUGH */        \
+     case 8:  _hj_j += ( (unsigned)_hj_key[7] << 24 );  /* FALLTHROUGH */        \
+     case 7:  _hj_j += ( (unsigned)_hj_key[6] << 16 );  /* FALLTHROUGH */        \
+     case 6:  _hj_j += ( (unsigned)_hj_key[5] << 8 );   /* FALLTHROUGH */        \
+     case 5:  _hj_j += _hj_key[4];                      /* FALLTHROUGH */        \
+     case 4:  _hj_i += ( (unsigned)_hj_key[3] << 24 );  /* FALLTHROUGH */        \
+     case 3:  _hj_i += ( (unsigned)_hj_key[2] << 16 );  /* FALLTHROUGH */        \
+     case 2:  _hj_i += ( (unsigned)_hj_key[1] << 8 );   /* FALLTHROUGH */        \
+     case 1:  _hj_i += _hj_key[0];                                               \
+  }                                                                              \
+  HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                             \
+} while (0)
+
+/* The Paul Hsieh hash function */
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__)             \
+  || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)             \
+                       +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+#define HASH_SFH(key,keylen,hashv)                                               \
+do {                                                                             \
+  unsigned const char *_sfh_key=(unsigned const char*)(key);                     \
+  uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen;                                \
+                                                                                 \
+  unsigned _sfh_rem = _sfh_len & 3U;                                             \
+  _sfh_len >>= 2;                                                                \
+  hashv = 0xcafebabeu;                                                           \
+                                                                                 \
+  /* Main loop */                                                                \
+  for (;_sfh_len > 0U; _sfh_len--) {                                             \
+    hashv    += get16bits (_sfh_key);                                            \
+    _sfh_tmp  = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv;              \
+    hashv     = (hashv << 16) ^ _sfh_tmp;                                        \
+    _sfh_key += 2U*sizeof (uint16_t);                                            \
+    hashv    += hashv >> 11;                                                     \
+  }                                                                              \
+                                                                                 \
+  /* Handle end cases */                                                         \
+  switch (_sfh_rem) {                                                            \
+    case 3: hashv += get16bits (_sfh_key);                                       \
+            hashv ^= hashv << 16;                                                \
+            hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18;              \
+            hashv += hashv >> 11;                                                \
+            break;                                                               \
+    case 2: hashv += get16bits (_sfh_key);                                       \
+            hashv ^= hashv << 11;                                                \
+            hashv += hashv >> 17;                                                \
+            break;                                                               \
+    case 1: hashv += *_sfh_key;                                                  \
+            hashv ^= hashv << 10;                                                \
+            hashv += hashv >> 1;                                                 \
+  }                                                                              \
+                                                                                 \
+    /* Force "avalanching" of final 127 bits */                                  \
+    hashv ^= hashv << 3;                                                         \
+    hashv += hashv >> 5;                                                         \
+    hashv ^= hashv << 4;                                                         \
+    hashv += hashv >> 17;                                                        \
+    hashv ^= hashv << 25;                                                        \
+    hashv += hashv >> 6;                                                         \
+} while (0)
+
+#ifdef HASH_USING_NO_STRICT_ALIASING
+/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
+ * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
+ * MurmurHash uses the faster approach only on CPU's where we know it's safe.
+ *
+ * Note the preprocessor built-in defines can be emitted using:
+ *
+ *   gcc -m64 -dM -E - < /dev/null                  (on gcc)
+ *   cc -## a.c (where a.c is a simple test file)   (Sun Studio)
+ */
+#if (defined(__i386__) || defined(__x86_64__)  || defined(_M_IX86))
+#define MUR_GETBLOCK(p,i) p[i]
+#else /* non intel */
+#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL)
+#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL)
+#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL)
+#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL)
+#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
+#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
+#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
+#define MUR_TWO_TWO(p)   ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >>  8))
+#else /* assume little endian non-intel */
+#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
+#define MUR_TWO_TWO(p)   ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) <<  8))
+#endif
+#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) :           \
+                            (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
+                             (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) :  \
+                                                      MUR_ONE_THREE(p))))
+#endif
+#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
+#define MUR_FMIX(_h) \
+do {                 \
+  _h ^= _h >> 16;    \
+  _h *= 0x85ebca6bu; \
+  _h ^= _h >> 13;    \
+  _h *= 0xc2b2ae35u; \
+  _h ^= _h >> 16;    \
+} while (0)
+
+#define HASH_MUR(key,keylen,hashv)                                     \
+do {                                                                   \
+  const uint8_t *_mur_data = (const uint8_t*)(key);                    \
+  const int _mur_nblocks = (int)(keylen) / 4;                          \
+  uint32_t _mur_h1 = 0xf88D5353u;                                      \
+  uint32_t _mur_c1 = 0xcc9e2d51u;                                      \
+  uint32_t _mur_c2 = 0x1b873593u;                                      \
+  uint32_t _mur_k1 = 0;                                                \
+  const uint8_t *_mur_tail;                                            \
+  const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \
+  int _mur_i;                                                          \
+  for(_mur_i = -_mur_nblocks; _mur_i!=0; _mur_i++) {                   \
+    _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i);                        \
+    _mur_k1 *= _mur_c1;                                                \
+    _mur_k1 = MUR_ROTL32(_mur_k1,15);                                  \
+    _mur_k1 *= _mur_c2;                                                \
+                                                                       \
+    _mur_h1 ^= _mur_k1;                                                \
+    _mur_h1 = MUR_ROTL32(_mur_h1,13);                                  \
+    _mur_h1 = (_mur_h1*5U) + 0xe6546b64u;                              \
+  }                                                                    \
+  _mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4));          \
+  _mur_k1=0;                                                           \
+  switch((keylen) & 3U) {                                              \
+    case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \
+    case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8;  /* FALLTHROUGH */ \
+    case 1: _mur_k1 ^= (uint32_t)_mur_tail[0];                         \
+    _mur_k1 *= _mur_c1;                                                \
+    _mur_k1 = MUR_ROTL32(_mur_k1,15);                                  \
+    _mur_k1 *= _mur_c2;                                                \
+    _mur_h1 ^= _mur_k1;                                                \
+  }                                                                    \
+  _mur_h1 ^= (uint32_t)(keylen);                                       \
+  MUR_FMIX(_mur_h1);                                                   \
+  hashv = _mur_h1;                                                     \
+} while (0)
+#endif  /* HASH_USING_NO_STRICT_ALIASING */
+
+/* iterate over items in a known bucket to find desired item */
+#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out)               \
+do {                                                                             \
+  if ((head).hh_head != NULL) {                                                  \
+    DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head));                     \
+  } else {                                                                       \
+    (out) = NULL;                                                                \
+  }                                                                              \
+  while ((out) != NULL) {                                                        \
+    if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) {       \
+      if (uthash_memcmp((out)->hh.key, keyptr, keylen_in) == 0) {                \
+        break;                                                                   \
+      }                                                                          \
+    }                                                                            \
+    if ((out)->hh.hh_next != NULL) {                                             \
+      DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next));                \
+    } else {                                                                     \
+      (out) = NULL;                                                              \
+    }                                                                            \
+  }                                                                              \
+} while (0)
+
+/* add an item to a bucket  */
+#define HASH_ADD_TO_BKT(head,addhh)                                              \
+do {                                                                             \
+ head.count++;                                                                   \
+ (addhh)->hh_next = head.hh_head;                                                \
+ (addhh)->hh_prev = NULL;                                                        \
+ if (head.hh_head != NULL) { (head).hh_head->hh_prev = (addhh); }                \
+ (head).hh_head=addhh;                                                           \
+ if ((head.count >= ((head.expand_mult+1U) * HASH_BKT_CAPACITY_THRESH))          \
+     && ((addhh)->tbl->noexpand != 1U)) {                                        \
+       HASH_EXPAND_BUCKETS((addhh)->tbl);                                        \
+ }                                                                               \
+} while (0)
+
+/* remove an item from a given bucket */
+#define HASH_DEL_IN_BKT(hh,head,hh_del)                                          \
+    (head).count--;                                                              \
+    if ((head).hh_head == hh_del) {                                              \
+      (head).hh_head = hh_del->hh_next;                                          \
+    }                                                                            \
+    if (hh_del->hh_prev) {                                                       \
+        hh_del->hh_prev->hh_next = hh_del->hh_next;                              \
+    }                                                                            \
+    if (hh_del->hh_next) {                                                       \
+        hh_del->hh_next->hh_prev = hh_del->hh_prev;                              \
+    }
+
+/* Bucket expansion has the effect of doubling the number of buckets
+ * and redistributing the items into the new buckets. Ideally the
+ * items will distribute more or less evenly into the new buckets
+ * (the extent to which this is true is a measure of the quality of
+ * the hash function as it applies to the key domain).
+ *
+ * With the items distributed into more buckets, the chain length
+ * (item count) in each bucket is reduced. Thus by expanding buckets
+ * the hash keeps a bound on the chain length. This bounded chain
+ * length is the essence of how a hash provides constant time lookup.
+ *
+ * The calculation of tbl->ideal_chain_maxlen below deserves some
+ * explanation. First, keep in mind that we're calculating the ideal
+ * maximum chain length based on the *new* (doubled) bucket count.
+ * In fractions this is just n/b (n=number of items,b=new num buckets).
+ * Since the ideal chain length is an integer, we want to calculate
+ * ceil(n/b). We don't depend on floating point arithmetic in this
+ * hash, so to calculate ceil(n/b) with integers we could write
+ *
+ *      ceil(n/b) = (n/b) + ((n%b)?1:0)
+ *
+ * and in fact a previous version of this hash did just that.
+ * But now we have improved things a bit by recognizing that b is
+ * always a power of two. We keep its base 2 log handy (call it lb),
+ * so now we can write this with a bit shift and logical AND:
+ *
+ *      ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
+ *
+ */
+#define HASH_EXPAND_BUCKETS(tbl)                                                 \
+do {                                                                             \
+    unsigned _he_bkt;                                                            \
+    unsigned _he_bkt_i;                                                          \
+    struct UT_hash_handle *_he_thh, *_he_hh_nxt;                                 \
+    UT_hash_bucket *_he_new_buckets, *_he_newbkt;                                \
+    _he_new_buckets = (UT_hash_bucket*)uthash_malloc(                            \
+             2UL * tbl->num_buckets * sizeof(struct UT_hash_bucket));            \
+    if (!_he_new_buckets) { uthash_fatal( "out of memory"); }                    \
+    memset(_he_new_buckets, 0,                                                   \
+            2UL * tbl->num_buckets * sizeof(struct UT_hash_bucket));             \
+    tbl->ideal_chain_maxlen =                                                    \
+       (tbl->num_items >> (tbl->log2_num_buckets+1U)) +                          \
+       (((tbl->num_items & ((tbl->num_buckets*2U)-1U)) != 0U) ? 1U : 0U);        \
+    tbl->nonideal_items = 0;                                                     \
+    for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++)                \
+    {                                                                            \
+        _he_thh = tbl->buckets[ _he_bkt_i ].hh_head;                             \
+        while (_he_thh != NULL) {                                                \
+           _he_hh_nxt = _he_thh->hh_next;                                        \
+           HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2U, _he_bkt);           \
+           _he_newbkt = &(_he_new_buckets[ _he_bkt ]);                           \
+           if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) {                \
+             tbl->nonideal_items++;                                              \
+             _he_newbkt->expand_mult = _he_newbkt->count /                       \
+                                        tbl->ideal_chain_maxlen;                 \
+           }                                                                     \
+           _he_thh->hh_prev = NULL;                                              \
+           _he_thh->hh_next = _he_newbkt->hh_head;                               \
+           if (_he_newbkt->hh_head != NULL) { _he_newbkt->hh_head->hh_prev =     \
+                _he_thh; }                                                       \
+           _he_newbkt->hh_head = _he_thh;                                        \
+           _he_thh = _he_hh_nxt;                                                 \
+        }                                                                        \
+    }                                                                            \
+    uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+    tbl->num_buckets *= 2U;                                                      \
+    tbl->log2_num_buckets++;                                                     \
+    tbl->buckets = _he_new_buckets;                                              \
+    tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ?         \
+        (tbl->ineff_expands+1U) : 0U;                                            \
+    if (tbl->ineff_expands > 1U) {                                               \
+        tbl->noexpand=1;                                                         \
+        uthash_noexpand_fyi(tbl);                                                \
+    }                                                                            \
+    uthash_expand_fyi(tbl);                                                      \
+} while (0)
+
+
+/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
+/* Note that HASH_SORT assumes the hash handle name to be hh.
+ * HASH_SRT was added to allow the hash handle name to be passed in. */
+#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
+#define HASH_SRT(hh,head,cmpfcn)                                                 \
+do {                                                                             \
+  unsigned _hs_i;                                                                \
+  unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize;               \
+  struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail;            \
+  if (head != NULL) {                                                            \
+      _hs_insize = 1;                                                            \
+      _hs_looping = 1;                                                           \
+      _hs_list = &((head)->hh);                                                  \
+      while (_hs_looping != 0U) {                                                \
+          _hs_p = _hs_list;                                                      \
+          _hs_list = NULL;                                                       \
+          _hs_tail = NULL;                                                       \
+          _hs_nmerges = 0;                                                       \
+          while (_hs_p != NULL) {                                                \
+              _hs_nmerges++;                                                     \
+              _hs_q = _hs_p;                                                     \
+              _hs_psize = 0;                                                     \
+              for ( _hs_i = 0; _hs_i  < _hs_insize; _hs_i++ ) {                  \
+                  _hs_psize++;                                                   \
+                  _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ?              \
+                          ((void*)((char*)(_hs_q->next) +                        \
+                          (head)->hh.tbl->hho)) : NULL);                         \
+                  if (! (_hs_q) ) { break; }                                     \
+              }                                                                  \
+              _hs_qsize = _hs_insize;                                            \
+              while ((_hs_psize > 0U) || ((_hs_qsize > 0U) && (_hs_q != NULL))) {\
+                  if (_hs_psize == 0U) {                                         \
+                      _hs_e = _hs_q;                                             \
+                      _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ?          \
+                              ((void*)((char*)(_hs_q->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_qsize--;                                               \
+                  } else if ( (_hs_qsize == 0U) || (_hs_q == NULL) ) {           \
+                      _hs_e = _hs_p;                                             \
+                      if (_hs_p != NULL){                                        \
+                        _hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ?        \
+                                ((void*)((char*)(_hs_p->next) +                  \
+                                (head)->hh.tbl->hho)) : NULL);                   \
+                       }                                                         \
+                      _hs_psize--;                                               \
+                  } else if ((                                                   \
+                      cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
+                             DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
+                             ) <= 0) {                                           \
+                      _hs_e = _hs_p;                                             \
+                      if (_hs_p != NULL){                                        \
+                        _hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ?        \
+                               ((void*)((char*)(_hs_p->next) +                   \
+                               (head)->hh.tbl->hho)) : NULL);                    \
+                       }                                                         \
+                      _hs_psize--;                                               \
+                  } else {                                                       \
+                      _hs_e = _hs_q;                                             \
+                      _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ?          \
+                              ((void*)((char*)(_hs_q->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_qsize--;                                               \
+                  }                                                              \
+                  if ( _hs_tail != NULL ) {                                      \
+                      _hs_tail->next = ((_hs_e != NULL) ?                        \
+                            ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL);          \
+                  } else {                                                       \
+                      _hs_list = _hs_e;                                          \
+                  }                                                              \
+                  if (_hs_e != NULL) {                                           \
+                  _hs_e->prev = ((_hs_tail != NULL) ?                            \
+                     ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL);              \
+                  }                                                              \
+                  _hs_tail = _hs_e;                                              \
+              }                                                                  \
+              _hs_p = _hs_q;                                                     \
+          }                                                                      \
+          if (_hs_tail != NULL){                                                 \
+            _hs_tail->next = NULL;                                               \
+          }                                                                      \
+          if ( _hs_nmerges <= 1U ) {                                             \
+              _hs_looping=0;                                                     \
+              (head)->hh.tbl->tail = _hs_tail;                                   \
+              DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list));      \
+          }                                                                      \
+          _hs_insize *= 2U;                                                      \
+      }                                                                          \
+      HASH_FSCK(hh,head);                                                        \
+ }                                                                               \
+} while (0)
+
+/* This function selects items from one hash into another hash.
+ * The end result is that the selected items have dual presence
+ * in both hashes. There is no copy of the items made; rather
+ * they are added into the new hash through a secondary hash
+ * hash handle that must be present in the structure. */
+#define HASH_SELECT(hh_dst, dst, hh_src, src, cond)                              \
+do {                                                                             \
+  unsigned _src_bkt, _dst_bkt;                                                   \
+  void *_last_elt=NULL, *_elt;                                                   \
+  UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL;                         \
+  ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst));                 \
+  if (src != NULL) {                                                             \
+    for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) {     \
+      for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head;                \
+          _src_hh != NULL;                                                       \
+          _src_hh = _src_hh->hh_next) {                                          \
+          _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh);                       \
+          if (cond(_elt)) {                                                      \
+            _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho);               \
+            _dst_hh->key = _src_hh->key;                                         \
+            _dst_hh->keylen = _src_hh->keylen;                                   \
+            _dst_hh->hashv = _src_hh->hashv;                                     \
+            _dst_hh->prev = _last_elt;                                           \
+            _dst_hh->next = NULL;                                                \
+            if (_last_elt_hh != NULL) { _last_elt_hh->next = _elt; }             \
+            if (dst == NULL) {                                                   \
+              DECLTYPE_ASSIGN(dst,_elt);                                         \
+              HASH_MAKE_TABLE(hh_dst,dst);                                       \
+            } else {                                                             \
+              _dst_hh->tbl = (dst)->hh_dst.tbl;                                  \
+            }                                                                    \
+            HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt);    \
+            HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh);            \
+            (dst)->hh_dst.tbl->num_items++;                                      \
+            _last_elt = _elt;                                                    \
+            _last_elt_hh = _dst_hh;                                              \
+          }                                                                      \
+      }                                                                          \
+    }                                                                            \
+  }                                                                              \
+  HASH_FSCK(hh_dst,dst);                                                         \
+} while (0)
+
+#define HASH_CLEAR(hh,head)                                                      \
+do {                                                                             \
+  if (head != NULL) {                                                            \
+    uthash_free((head)->hh.tbl->buckets,                                         \
+                (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket));      \
+    HASH_BLOOM_FREE((head)->hh.tbl);                                             \
+    uthash_free((head)->hh.tbl, sizeof(UT_hash_table));                          \
+    (head)=NULL;                                                                 \
+  }                                                                              \
+} while (0)
+
+#define HASH_OVERHEAD(hh,head)                                                   \
+ ((head != NULL) ? (                                                             \
+ (size_t)(((head)->hh.tbl->num_items   * sizeof(UT_hash_handle))   +             \
+          ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket))   +             \
+           sizeof(UT_hash_table)                                   +             \
+           (HASH_BLOOM_BYTELEN))) : 0U)
+
+#ifdef NO_DECLTYPE
+#define HASH_ITER(hh,head,el,tmp)                                                \
+for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \
+  (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL)))
+#else
+#define HASH_ITER(hh,head,el,tmp)                                                \
+for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL));      \
+  (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL)))
+#endif
+
+/* obtain a count of items in the hash */
+#define HASH_COUNT(head) HASH_CNT(hh,head)
+#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U)
+
+typedef struct UT_hash_bucket {
+   struct UT_hash_handle *hh_head;
+   unsigned count;
+
+   /* expand_mult is normally set to 0. In this situation, the max chain length
+    * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
+    * the bucket's chain exceeds this length, bucket expansion is triggered).
+    * However, setting expand_mult to a non-zero value delays bucket expansion
+    * (that would be triggered by additions to this particular bucket)
+    * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
+    * (The multiplier is simply expand_mult+1). The whole idea of this
+    * multiplier is to reduce bucket expansions, since they are expensive, in
+    * situations where we know that a particular bucket tends to be overused.
+    * It is better to let its chain length grow to a longer yet-still-bounded
+    * value, than to do an O(n) bucket expansion too often.
+    */
+   unsigned expand_mult;
+
+} UT_hash_bucket;
+
+/* random signature used only to find hash tables in external analysis */
+#define HASH_SIGNATURE 0xa0111fe1u
+#define HASH_BLOOM_SIGNATURE 0xb12220f2u
+
+typedef struct UT_hash_table {
+   UT_hash_bucket *buckets;
+   unsigned num_buckets, log2_num_buckets;
+   unsigned num_items;
+   struct UT_hash_handle *tail; /* tail hh in app order, for fast append    */
+   ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
+
+   /* in an ideal situation (all buckets used equally), no bucket would have
+    * more than ceil(#items/#buckets) items. that's the ideal chain length. */
+   unsigned ideal_chain_maxlen;
+
+   /* nonideal_items is the number of items in the hash whose chain position
+    * exceeds the ideal chain maxlen. these items pay the penalty for an uneven
+    * hash distribution; reaching them in a chain traversal takes >ideal steps */
+   unsigned nonideal_items;
+
+   /* ineffective expands occur when a bucket doubling was performed, but
+    * afterward, more than half the items in the hash had nonideal chain
+    * positions. If this happens on two consecutive expansions we inhibit any
+    * further expansion, as it's not helping; this happens when the hash
+    * function isn't a good fit for the key domain. When expansion is inhibited
+    * the hash will still work, albeit no longer in constant time. */
+   unsigned ineff_expands, noexpand;
+
+   uint32_t signature; /* used only to find hash tables in external analysis */
+#ifdef HASH_BLOOM
+   uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
+   uint8_t *bloom_bv;
+   uint8_t bloom_nbits;
+#endif
+
+} UT_hash_table;
+
+typedef struct UT_hash_handle {
+   struct UT_hash_table *tbl;
+   void *prev;                       /* prev element in app order      */
+   void *next;                       /* next element in app order      */
+   struct UT_hash_handle *hh_prev;   /* previous hh in bucket order    */
+   struct UT_hash_handle *hh_next;   /* next hh in bucket order        */
+   void *key;                        /* ptr to enclosing struct's key  */
+   unsigned keylen;                  /* enclosing struct's key len     */
+   unsigned hashv;                   /* result of hash-fcn(key)        */
+} UT_hash_handle;
+
+#endif /* UTHASH_H */
diff --git a/src/writer.c b/src/writer.c
new file mode 100644 (file)
index 0000000..5c7e3de
--- /dev/null
@@ -0,0 +1,1194 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file writer.c
+
+       @brief Coordinate conversion of token tree to output formats.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libMultiMarkdown.h"
+
+#include "char.h"
+#include "d_string.h"
+#include "html.h"
+#include "mmd.h"
+#include "scanners.h"
+#include "token.h"
+#include "writer.h"
+
+
+void store_citation(scratch_pad * scratch, footnote * f);
+
+void store_footnote(scratch_pad * scratch, footnote * f);
+
+void store_link(scratch_pad * scratch, link * l);
+
+
+/// Temporary storage while exporting parse tree to output format
+scratch_pad * scratch_pad_new(mmd_engine * e) {
+       scratch_pad * p = malloc(sizeof(scratch_pad));
+
+       if (p) {
+               p->padded = 2;                                                  // Prevent unnecessary leading space
+               p->list_is_tight = false;                               // Tight vs Loose list
+               p->skip_token = 0;                                              // Skip over next n tokens
+
+               p->link_hash = NULL;                                    // Store defined links in a hash
+
+               link * l;
+
+               for (int i = 0; i < e->link_stack->size; ++i)
+               {
+                       l = stack_peek_index(e->link_stack, i);
+
+                       store_link(p, l);
+               }
+
+               p->used_footnotes = stack_new(0);                               // Store footnotes as we use them
+               p->inline_footnotes_to_free = stack_new(0);             // Inline footnotes need to be freed
+               p->footnote_being_printed = 0;
+               p->footnote_para_counter = -1;
+
+               p->footnote_hash = NULL;                                // Store defined footnotes in a hash
+
+               footnote * f;
+
+               for (int i = 0; i < e->footnote_stack->size; ++i)
+               {
+                       f = stack_peek_index(e->footnote_stack, i);
+
+                       store_footnote(p, f);
+               }
+
+               p->used_citations = stack_new(0);
+               p->inline_citations_to_free = stack_new(0);
+               p->citation_being_printed = 0;
+
+               p->citation_hash = NULL;
+
+               for (int i = 0; i < e->citation_stack->size; ++i)
+               {
+                       f = stack_peek_index(e->citation_stack, i);
+
+                       store_citation(p, f);
+               }
+
+
+
+               p->extensions = e->extensions;
+       }
+
+       return p;
+}
+
+
+void scratch_pad_free(scratch_pad * scratch) {
+//     HASH_CLEAR(hh, scratch->link_hash);
+
+       link * l, * l_tmp;
+       
+       // Free link hash
+       HASH_ITER(hh, scratch->link_hash, l, l_tmp) {
+               HASH_DEL(scratch->link_hash, l);        // Remove item from hash
+               free(l);                // "Shallow" free -- the pointers will be freed
+                                               // with the original later.
+       }
+
+       fn_holder * f, * f_tmp;
+
+
+       // Free footnote hash
+       HASH_ITER(hh, scratch->footnote_hash, f, f_tmp) {
+               HASH_DEL(scratch->footnote_hash, f);    // Remove item from hash
+               free(f);                // Free the fn_holder
+       }
+
+       stack_free(scratch->used_footnotes);
+
+       while (scratch->inline_footnotes_to_free->size) {
+               footnote_free(stack_pop(scratch->inline_footnotes_to_free));
+       }
+       stack_free(scratch->inline_footnotes_to_free);
+
+
+       // Free citation hash
+       HASH_ITER(hh, scratch->citation_hash, f, f_tmp) {
+               HASH_DEL(scratch->citation_hash, f);    // Remove item from hash
+               free(f);                // Free the fn_holder
+       }
+
+       stack_free(scratch->used_citations);
+
+       while (scratch->inline_citations_to_free->size) {
+               footnote_free(stack_pop(scratch->inline_citations_to_free));
+       }
+       stack_free(scratch->inline_citations_to_free);
+
+
+       free(scratch);
+}
+
+
+/// Ensure at least num newlines at end of output buffer
+void pad(DString * d, short num, scratch_pad * scratch) {
+       while (num > scratch->padded) {
+               d_string_append_c(d, '\n');
+               scratch->padded++;
+       }
+}
+
+
+void print_token_raw(DString * out, const char * source, token * t) {
+       if (t) {
+               switch (t->type) {
+                       case EMPH_START:
+                       case EMPH_STOP:
+                       case STRONG_START:
+                       case STRONG_STOP:
+                       case TEXT_EMPTY:
+                               break;
+                       default:
+                               d_string_append_c_array(out, &source[t->start], t->len);
+                               break;
+               }
+       }
+}
+
+
+void print_token_tree_raw(DString * out, const char * source, token * t) {
+       while (t) {
+               print_token_raw(out, source, t);
+
+               t = t->next;
+       }
+}
+
+
+char * text_inside_pair(const char * source, token * pair) {
+       char * result = NULL;
+
+       if (source && pair) {
+               result = strndup(&source[pair->start + pair->child->len], pair->len - (pair->child->len + 1));
+       }
+
+       return result;
+}
+
+
+char * label_from_string(const char * str) {
+       const char * next_char;
+       char * label = NULL;
+
+       DString * out = d_string_new("");
+
+       while (*str != '\0') {
+               next_char = str;
+               next_char++;
+
+               if ((*next_char & 0xC0) == 0x80) {
+                       // Allow multibyte characters
+                       d_string_append_c(out, *str);
+
+                       while ((*next_char & 0xC0) == 0x80) {
+                               str++;
+                               d_string_append_c(out, *str);
+                               next_char++;
+                       }
+               } else if ((*str >= '0' && *str <= '9') || (*str >= 'A' && *str <= 'Z')
+                       || (*str >= 'a' && *str <= 'z') || (*str == '.') || (*str== '_')
+                       || (*str== '-') || (*str== ':'))
+               {
+                       // Allow 0-9, A-Z, a-z, ., _, -, :
+                       d_string_append_c(out, tolower(*str));
+               }
+
+               str++;
+       }
+
+       label = out->str;
+       d_string_free(out, false);
+
+       return label;
+}
+
+
+char * label_from_token(const char * source, token * t) {
+       char * label = NULL;
+
+       DString * raw = d_string_new("");
+
+       d_string_append_c_array(raw, &source[t->start], t->len);
+
+       label = label_from_string(raw->str);
+
+       d_string_free(raw, true);
+
+       return label;
+}
+
+
+/// Clean up whitespace in string for standardization
+char * clean_string(const char * str, bool lowercase) {
+       if (str == NULL)
+               return NULL;
+       
+       DString * out = d_string_new("");
+       char * clean = NULL;
+       bool block_whitespace = true;
+
+       while (*str != '\0') {
+               switch (*str) {
+                       case '\t':
+                       case ' ':
+                       case '\n':
+                       case '\r':
+                               if (!block_whitespace) {
+                                       d_string_append_c(out, ' ');
+                                       block_whitespace = true;
+                               }
+                               break;
+                       default:
+                               if (lowercase)
+                                       d_string_append_c(out, tolower(*str));
+                               else
+                                       d_string_append_c(out, *str);
+
+                               block_whitespace = false;
+                               break;
+               }
+
+               str++;
+       }
+
+       clean = out->str;
+
+       // Trim trailing whitespace/newlines
+       while (out->currentStringLength && char_is_whitespace_or_line_ending(clean[out->currentStringLength - 1])) {
+               out->currentStringLength--;
+               clean[out->currentStringLength] = '\0';
+       }
+
+       d_string_free(out, false);
+
+       // Trim trailing whitespace
+       return clean;
+}
+
+
+char * clean_string_from_token(const char * source, token * t, bool lowercase) {
+       char * clean = NULL;
+
+       DString * raw = d_string_new("");
+
+       d_string_append_c_array(raw, &source[t->start], t->len);
+
+       clean = clean_string(raw->str, lowercase);
+
+       d_string_free(raw, true);
+
+       return clean;
+}
+
+
+char * clean_inside_pair(const char * source, token * t, bool lowercase) {
+       char * text = text_inside_pair(source, t);
+
+       char * clean = clean_string(text, lowercase);
+
+       free(text);
+
+       return clean;
+}
+
+
+attr * attr_new(char * key, char * value) {
+       attr * a = malloc(sizeof(attr));
+       size_t len = strlen(value);
+
+       // Strip quotes if present
+       if (value[0] == '"') {
+               value++;
+               len--;
+       }
+
+       if (value[len - 1] == '"') {
+               value[len - 1] = '\0';
+       }
+
+       if (a) {
+               a->key = key;
+               a->value = strdup(value);
+               a->next = NULL;
+       }
+
+       return a;
+}
+
+
+attr * parse_attributes(char * source) {
+       attr * attributes = NULL;
+       attr * a = NULL;
+       char * key = NULL;
+       char * value = NULL;
+       size_t scan_len;
+       size_t pos = 0;
+
+       while (scan_attr(&source[pos])) {
+               pos +=  scan_spnl(&source[pos]);
+
+               // Get key
+               scan_len = scan_key(&source[pos]);
+               key = strndup(&source[pos], scan_len);
+               
+               // Skip '='
+               pos += scan_len + 1;
+
+               // Get value
+               scan_len = scan_value(&source[pos]);
+               value = strndup(&source[pos], scan_len);
+
+               pos += scan_len;
+
+               if (a) {
+                       a->next = attr_new(key, value);
+                       a = a->next;
+               } else {
+                       a = attr_new(key, value);
+                       attributes = a;
+               }
+
+               free(value);    // We stored a copy
+       }
+
+       return attributes;
+}
+
+
+link * link_new(const char * source, token * label, char * url, char * title, char * attributes) {
+       link * l = malloc(sizeof(link));
+
+       if (l) {
+               l->label = label;
+               l->clean_text = clean_inside_pair(source, label, true);
+               l->label_text = label_from_token(source, label);
+               l->url = clean_string(url, false);
+               l->title = (title == NULL) ? NULL : strdup(title);
+               l->attributes = (attributes == NULL) ? NULL : parse_attributes(attributes);
+       }
+
+       return l;
+}
+
+
+/// Store shallow copies of links in the storage hash.  The link
+/// itself is new, but references the same data as the original.
+/// This allows the copied link to simply be `free()`'d without
+/// freeing the pointers.
+link * link_shallow_copy(link * l) {
+       link * new = malloc(sizeof(link));
+
+       if (new) {
+               new->label = l->label;
+               new->clean_text = l->clean_text;
+               new->label_text = l->label_text;
+               new->url = l->url;
+               new->title = l->title;
+               new->attributes = l->attributes;
+       }
+       
+       return new;
+}
+
+
+/// Copy stored links to a hash for quick searching during export.
+/// Links are stored via a clean version of their text(from
+/// `clean_string()`) and a label version (`label_from_string()`).
+/// The first link for each string is stored.
+void store_link(scratch_pad * scratch, link * l) {
+       link * temp_link;
+
+       // Add link via `clean_text`?
+       HASH_FIND_STR(scratch->link_hash, l->clean_text, temp_link);
+       
+       if (!temp_link) {
+               // Only add if another link is not found with clean_text
+               temp_link = link_shallow_copy(l);
+               HASH_ADD_KEYPTR(hh, scratch->link_hash, l->clean_text, strlen(l->clean_text), temp_link);
+       }
+
+       // Add link via `label_text`?
+       HASH_FIND_STR(scratch->link_hash, l->label_text, temp_link);
+
+       if (!temp_link) {
+               // Only add if another link is not found with label_text
+               temp_link = link_shallow_copy(l);
+               HASH_ADD_KEYPTR(hh, scratch->link_hash, l->label_text, strlen(l->label_text), temp_link);
+       }
+}
+
+link * retrieve_link(scratch_pad * scratch, const char * key) {
+       link * l;
+
+       HASH_FIND_STR(scratch->link_hash, key, l);
+
+       if (l)
+               return l;
+
+       char * clean = clean_string(key, true);
+
+       HASH_FIND_STR(scratch->link_hash, clean, l);
+
+       free(clean);
+
+       return l;
+}
+
+
+fn_holder * fn_holder_new(footnote * f) {
+       fn_holder * h = malloc(sizeof(fn_holder));
+
+       if (h) {
+               h->note = f;
+       }
+
+       return h;
+}
+
+
+void store_footnote(scratch_pad * scratch, footnote * f) {
+       fn_holder * temp_holder;
+
+       // Store by `clean_text`?
+       HASH_FIND_STR(scratch->footnote_hash, f->clean_text, temp_holder);
+
+       if (!temp_holder) {
+               temp_holder = fn_holder_new(f);
+               HASH_ADD_KEYPTR(hh, scratch->footnote_hash, f->clean_text, strlen(f->clean_text), temp_holder);
+       }
+
+       // Store by `label_text`?
+       HASH_FIND_STR(scratch->footnote_hash, f->label_text, temp_holder);
+
+       if (!temp_holder) {
+               temp_holder = fn_holder_new(f);
+               HASH_ADD_KEYPTR(hh, scratch->footnote_hash, f->label_text, strlen(f->label_text), temp_holder);
+       }
+}
+
+
+void store_citation(scratch_pad * scratch, footnote * f) {
+       fn_holder * temp_holder;
+
+       // Store by `clean_text`?
+       HASH_FIND_STR(scratch->citation_hash, f->clean_text, temp_holder);
+
+       if (!temp_holder) {
+               temp_holder = fn_holder_new(f);
+               HASH_ADD_KEYPTR(hh, scratch->citation_hash, f->clean_text, strlen(f->clean_text), temp_holder);
+       }
+
+       // Store by `label_text`?
+       HASH_FIND_STR(scratch->citation_hash, f->label_text, temp_holder);
+
+       if (!temp_holder) {
+               temp_holder = fn_holder_new(f);
+               HASH_ADD_KEYPTR(hh, scratch->citation_hash, f->label_text, strlen(f->label_text), temp_holder);
+       }
+}
+
+
+void link_free(link * l) {
+       free(l->label_text);
+       free(l->clean_text);
+       free(l->url);
+       free(l->title);
+//     free(l->id);
+
+       attr * a = l->attributes;
+       attr * b;
+
+       while (a) {
+               b = a->next;
+               free(a->key);
+               free(a->value);
+               free(a);
+               a = b;
+       }
+
+       free(l);
+}
+
+
+void whitespace_accept(token ** remainder) {
+       while (token_chain_accept_multiple(remainder, 3, NON_INDENT_SPACE, INDENT_SPACE, INDENT_TAB));
+}
+
+
+/// Find link based on label
+link * extract_link_from_stack(scratch_pad * scratch, const char * target) {
+       char * key = clean_string(target, true);
+
+       link * temp = NULL;
+
+       HASH_FIND_STR(scratch->link_hash, key, temp);
+
+       free(key);
+
+       if (temp)
+               return temp;
+
+       key = label_from_string(target);
+
+       HASH_FIND_STR(scratch->link_hash, key, temp);
+
+       free(key);
+
+       return temp;
+}
+
+
+bool validate_url(const char * url) {
+       size_t len = scan_url(url);
+
+       return (len && len == strlen(url)) ? true : false;
+}
+
+
+char * url_accept(const char * source, token ** remainder, bool validate) {
+       char * url = NULL;
+       char * clean = NULL;
+       token * t = NULL;
+       token * first = NULL;
+       token * last = NULL;
+
+       switch ((*remainder)->type) {
+               case PAIR_PAREN:
+               case PAIR_ANGLE:
+               case PAIR_QUOTE_SINGLE:
+               case PAIR_QUOTE_DOUBLE:
+                       t = token_chain_accept_multiple(remainder, 2, PAIR_ANGLE, PAIR_PAREN);
+                       url = text_inside_pair(source, t);
+                       break;
+               case TEXT_PLAIN:
+                       first = *remainder;
+                       
+                       // Grab parts for URL
+                       while (token_chain_accept_multiple(remainder, 5, AMPERSAND, COLON, TEXT_PERIOD, TEXT_PLAIN, UL));
+
+                       last = (*remainder)->prev;
+
+                       // Is there a space in a URL concatenated with a title or attribute?
+                       // e.g. [foo]: http://foo.bar/ class="foo"
+                       // Since only one space between URL and class, they are joined.
+
+                       if (last->type == TEXT_PLAIN) {
+                               // Trim leading whitespace
+                               token_trim_leading_whitespace(last, source);
+                               token_split_on_char(last, source, ' ');
+                               *remainder = last->next;
+                       }
+
+                       url = strndup(&source[first->start], last->start + last->len - first->start);
+                       break;
+       }
+
+       // Is this a valid URL?
+       clean = clean_string(url, false);
+       
+       if (validate && !validate_url(clean)) {
+               free(clean);
+               clean = NULL;
+       }
+
+       free(url);
+       return clean;
+}
+
+
+/// Extract url string from `(foo)` or `(<foo>)` or `(foo "bar")`
+void extract_from_paren(token * paren, const char * source, char ** url, char ** title, char ** attributes) {
+       token * t;
+       size_t attr_len;
+
+       token * remainder = paren->child->next;
+
+       if (remainder) {
+               // Skip whitespace
+               whitespace_accept(&remainder);
+
+               // Grab URL
+               *url = url_accept(source, &remainder, false);
+
+               // Skip whitespace
+               whitespace_accept(&remainder);
+
+               // Grab title, if present
+               t = token_chain_accept_multiple(&remainder, 3, PAIR_QUOTE_DOUBLE, PAIR_QUOTE_SINGLE, PAIR_PAREN);
+
+               if (t) {
+                       *title = text_inside_pair(source, t);
+               }
+
+               // Grab attributes, if present
+               if (t) {
+                       attr_len = scan_attributes(&source[t->start + t->len]);
+                       
+                       if (attr_len) {
+                               *attributes = strndup(&source[t->start + t->len], attr_len);
+                       }
+               }
+       }
+}
+
+
+/// Create a link from an explicit link `[foo](bar)`
+link * explicit_link(scratch_pad * scratch, token * bracket, token * paren, const char * source) {
+       char * url_char =NULL;
+       char * title_char = NULL;
+       char * attr_char = NULL;
+       link * l = NULL;
+
+       extract_from_paren(paren, source, &url_char, &title_char, &attr_char);
+
+       if (attr_char) {
+               if (!(scratch->extensions & EXT_COMPATIBILITY))
+                       l = link_new(source, bracket, url_char, title_char, attr_char);
+       } else {
+               l = link_new(source, bracket, url_char, title_char, attr_char);         
+       }
+
+       free(url_char);
+       free(title_char);
+       free(attr_char);
+
+       return l;
+}
+
+
+footnote * footnote_new(const char * source, token * label, token * content) {
+       footnote * f = malloc(sizeof(footnote));
+
+       if (f) {
+               f->label = label;
+               f->clean_text = (label == NULL) ? NULL : clean_inside_pair(source, label, true);
+               f->label_text = (label == NULL) ? NULL : label_from_token(source, label);
+               f->free_para  = false;
+               f->count = -1;
+
+               if (content) {
+                       switch (content->type) {
+                               case BLOCK_PARA:
+                                       f->content = content;
+                                       break;
+                               case TEXT_PLAIN:
+                                       token_trim_leading_whitespace(content, source);
+                               default:
+                                       f->content = token_new_parent(content, BLOCK_PARA);
+                                       f->free_para = true;
+                                       break;
+                       }
+               }
+       }
+
+       return f;
+}
+
+
+void footnote_free(footnote * f) {
+       if (f) {
+               if (f->free_para) {
+                       // I'm not sure why, but the following causes a memory error.
+                       // Strangely, not freeing it does *not* seem to cause memory
+                       // leaks??
+
+                       //free(f->content);
+               }
+               free(f->clean_text);
+               free(f->label_text);
+
+               free(f);
+       }
+}
+
+
+bool definition_extract(mmd_engine * e, token ** remainder) {
+       char * source = e->dstr->str;
+       token * label = NULL;
+       token * title = NULL;
+       char * url_char = NULL;
+       char * title_char = NULL;
+       char * attr_char = NULL;
+       token * temp = NULL;
+       size_t attr_len;
+
+       link * l = NULL;
+       footnote * f = NULL;
+       
+       // Store label
+       label = *remainder;
+
+       *remainder = (*remainder)->next;
+       
+       // Prepare for parsing
+
+       switch (label->type) {
+               case PAIR_BRACKET:
+                       // Reference Link Definition
+
+                       if (!token_chain_accept(remainder, COLON))
+                               return false;
+
+                       // Skip space
+                       whitespace_accept(remainder);
+
+                       // Grab URL
+                       url_char = url_accept(e->dstr->str, remainder, false);
+
+                       whitespace_accept(remainder);
+
+                       // Grab title, if present
+                       temp = *remainder;
+
+                       title = token_chain_accept_multiple(remainder, 2, PAIR_QUOTE_DOUBLE, PAIR_QUOTE_SINGLE);
+
+                       if (!title) {
+                               // See if there's a title on next line
+                               whitespace_accept(remainder);
+                               token_chain_accept_multiple(remainder, 2, TEXT_NL, TEXT_LINEBREAK);
+                               whitespace_accept(remainder);
+
+                               title = token_chain_accept_multiple(remainder, 2, PAIR_QUOTE_DOUBLE, PAIR_QUOTE_SINGLE);
+
+                               if (!title)
+                                       *remainder = temp;
+                       }
+
+                       title_char = text_inside_pair(e->dstr->str, title);
+
+                       // Get attributes
+                       if ((*remainder) && (((*remainder)->type != TEXT_NL) && ((*remainder)->type != TEXT_LINEBREAK))) {
+                               if (!(e->extensions & EXT_COMPATIBILITY)) {
+                                       attr_len = scan_attributes(&source[(*remainder)->start]);
+                                       
+                                       if (attr_len) {
+                                               attr_char = strndup(&source[(*remainder)->start], attr_len);
+
+                                               // Skip forward
+                                               attr_len += (*remainder)->start;
+
+                                               while ((*remainder) && (*remainder)->start < attr_len)
+                                                       *remainder = (*remainder)->next;
+                                       }
+                                       
+                                       l = link_new(e->dstr->str, label, url_char, title_char, attr_char);
+                               } else {
+                                       // Not valid match
+                               }
+                       } else {
+                               l = link_new(e->dstr->str, label, url_char, title_char, attr_char);
+                       }
+
+                       // Store link for later use
+                       if (l)
+                               stack_push(e->link_stack, l);
+
+                       break;
+               case PAIR_BRACKET_CITATION:
+                       if (!token_chain_accept(remainder, COLON))
+                               return false;
+
+                       title = *remainder;             // Track first token of content in 'title'
+                       f = footnote_new(e->dstr->str, label, title);
+
+                       // Store citation for later use
+                       stack_push(e->citation_stack, f);
+                       
+                       break;
+               case PAIR_BRACKET_FOOTNOTE:
+                       if (!token_chain_accept(remainder, COLON))
+                               return false;
+
+                       title = *remainder;             // Track first token of content in 'title'
+                       f = footnote_new(e->dstr->str, label, title);
+
+                       // Store footnote for later use
+                       stack_push(e->footnote_stack, f);
+                       
+                       break;
+               case PAIR_BRACKET_VARIABLE:
+                       fprintf(stderr, "Process variable:\n");
+                       token_describe(label, e->dstr->str);
+                       break;
+               default:
+                       // Rest of block is not definitions (or has already been processed)
+                       return false;
+       }
+
+       // Advance to next line
+       token_skip_until_type_multiple(remainder, 2, TEXT_NL, TEXT_LINEBREAK);
+       if (*remainder)
+               *remainder = (*remainder)->next;                                
+
+       // Clean up
+       free(url_char);
+       free(title_char);
+       free(attr_char);
+       
+       return true;
+}
+
+
+void process_definition_block(mmd_engine * e, token * block) {
+       token * remainder = block->child;
+       bool def_list = false;
+
+//     while (remainder) {
+               switch (remainder->type) {
+                       case PAIR_BRACKET_FOOTNOTE:
+                       case PAIR_BRACKET_CITATION:
+                       case PAIR_BRACKET_VARIABLE:
+                               if (!(e->extensions & EXT_NOTES))
+                                       return;
+                       case PAIR_BRACKET:
+                               if (definition_extract(e, &remainder))
+                                       def_list = true;
+                               break;
+                       default:
+                               // Rest of block is not definitions (or has already been processed)
+                               if (def_list) {
+                                       tokens_prune(block->child, remainder->prev);
+                                       block->child = remainder;
+                               }
+                               return;
+               }
+//     }
+       
+       // Ignore this block in the future
+       block->type = BLOCK_EMPTY;
+}
+
+
+void process_definition_stack(mmd_engine * e) {
+       for (int i = 0; i < e->definition_stack->size; ++i)
+       {
+               process_definition_block(e, stack_peek_index(e->definition_stack, i));
+       }
+}
+
+
+void process_header_to_links(mmd_engine * e, token * h) {
+       char * label = label_from_token(e->dstr->str, h);
+
+       DString * url = d_string_new("#");
+
+       d_string_append(url, label);
+
+       link * l = link_new(e->dstr->str, h, url->str, NULL, NULL);
+
+       // Store link for later use
+       stack_push(e->link_stack, l);
+
+       d_string_free(url, true);
+       free(label);
+}
+
+
+void process_header_stack(mmd_engine * e) {
+       // NTD in compatibility mode or if disabled
+       if (e->extensions & EXT_NO_LABELS)
+               return;
+
+       for (int i = 0; i < e->header_stack->size; ++i)
+       {
+               process_header_to_links(e, stack_peek_index(e->header_stack, i));
+       }
+}
+
+void mmd_export_token_tree(DString * out, mmd_engine * e, short format) {
+
+       // Process potential reference definitions
+       process_definition_stack(e);
+
+       // Process headers for potential cross-reference targets
+       process_header_stack(e);
+
+       // Create scratch pad
+       scratch_pad * scratch = scratch_pad_new(e);
+
+       switch (format) {
+               case FORMAT_HTML:
+                       mmd_export_token_tree_html(out, e->dstr->str, e->root, 0, scratch);
+                       mmd_export_footnote_list_html(out, e->dstr->str, scratch);
+                       mmd_export_citation_list_html(out, e->dstr->str, scratch);
+                       break;
+       }
+
+       scratch_pad_free(scratch);
+}
+
+
+void parse_brackets(const char * source, scratch_pad * scratch, token * bracket, link ** final_link, short * skip_token, bool * free_link) {
+       link * temp_link = NULL;
+       char * temp_char = NULL;
+       short temp_short = 0;
+
+       // What is next?
+       token * next = bracket->next;
+
+       if (next)
+               temp_short = 1;
+
+       // Do not free this link after using it
+       *free_link = false;
+
+       if (next && next->type == PAIR_PAREN) {
+               // We have `[foo](bar)` or `![foo](bar)`
+
+               temp_link = explicit_link(scratch, bracket, next, source);
+
+               if (temp_link) {
+                       // Don't output brackets
+                       bracket->child->type = TEXT_EMPTY;
+                       bracket->child->mate->type = TEXT_EMPTY;
+
+                       // This was an explicit link
+                       *final_link = temp_link;
+
+                       // Skip over parentheses
+                       *skip_token = temp_short;
+
+                       // Free this link
+                       *free_link = true;
+                       return;
+               }
+       }
+
+       if (next && next->type == PAIR_BRACKET) {
+               // Is this a reference link? `[foo][bar]` or `![foo][bar]`
+               temp_char = text_inside_pair(source, next);
+
+               if (temp_char[0] == '\0') {
+                       // Empty label, use first bracket
+                       free(temp_char);
+                       temp_char = text_inside_pair(source, bracket);
+               }
+       } else {
+               temp_char = text_inside_pair(source, bracket);
+               // Don't skip tokens
+               temp_short = 0;
+       }
+
+       temp_link = extract_link_from_stack(scratch, temp_char);
+
+       if (temp_char)
+               free(temp_char);
+
+       if (temp_link) {
+               // Don't output brackets
+               bracket->child->type = TEXT_EMPTY;
+               bracket->child->mate->type = TEXT_EMPTY;
+
+               *final_link = temp_link;
+
+               // Skip over second bracket if present
+               *skip_token = temp_short;
+               return;
+       }
+
+       // No existing links, so nothing to do
+       *final_link = NULL;
+}
+
+
+void mark_citation_as_used(scratch_pad * scratch, footnote * c) {
+       if (c->count == -1) {
+               // Add citation to used stack
+               stack_push(scratch->used_citations, c);
+
+               // Update counter
+               c->count = scratch->used_citations->size;
+       }
+}
+
+
+void mark_footnote_as_used(scratch_pad * scratch, footnote * f) {
+       if (f->count == -1) {
+               // Add footnote to used stack
+               stack_push(scratch->used_footnotes, f);
+
+               // Update counter
+               f->count = scratch->used_footnotes->size;
+       }
+}
+
+
+size_t extract_citation_from_stack(scratch_pad * scratch, const char * target) {
+       char * key = clean_string(target, true);
+
+       fn_holder * h;
+
+       HASH_FIND_STR(scratch->citation_hash, key, h);
+
+       free(key);
+
+       if (h) {
+               mark_citation_as_used(scratch, h->note);
+               return h->note->count;
+       }
+
+       key = label_from_string(target);
+
+       HASH_FIND_STR(scratch->citation_hash, key, h);
+
+       free(key);
+
+       if (h) {
+               mark_citation_as_used(scratch, h->note);
+               return h->note->count;
+       }
+
+       // None found
+       return -1;
+}
+
+
+size_t extract_footnote_from_stack(scratch_pad * scratch, const char * target) {
+       char * key = clean_string(target, true);
+
+       fn_holder * h;
+
+       HASH_FIND_STR(scratch->footnote_hash, key, h);
+
+       free(key);
+
+       if (h) {
+               mark_footnote_as_used(scratch, h->note);
+               return h->note->count;
+       }
+
+       key = label_from_string(target);
+
+       HASH_FIND_STR(scratch->footnote_hash, key, h);
+
+       free(key);
+
+       if (h) {
+               mark_footnote_as_used(scratch, h->note);
+               return h->note->count;
+       }
+
+       // None found
+       return -1;
+}
+
+
+void footnote_from_bracket(const char * source, scratch_pad * scratch, token * t, short * num) {
+       // Get text inside bracket
+       char * text = text_inside_pair(source, t);
+       short footnote_id = extract_footnote_from_stack(scratch, text);
+       
+       free(text);
+
+       if (footnote_id == -1) {
+               // No match, this is an inline footnote -- create a new one
+               t->child->type = TEXT_EMPTY;
+               t->child->mate->type = TEXT_EMPTY;
+
+               // Create footnote
+               footnote * temp = footnote_new(source, NULL, t->child);
+
+               // Store as used
+               stack_push(scratch->used_footnotes, temp);
+               *num = scratch->used_footnotes->size;
+               temp->count = *num;
+
+               // We need to free this one later since it doesn't exist
+               // in the engine's stack, on the scratch_pad stack
+               stack_push(scratch->inline_footnotes_to_free, temp);
+       } else {
+               // Footnote in stack
+               *num = footnote_id;
+       }
+}
+
+
+void citation_from_bracket(const char * source, scratch_pad * scratch, token * t, short * num) {
+       // Get text inside bracket
+       char * text = text_inside_pair(source, t);
+       short citation_id = extract_citation_from_stack(scratch, text);
+       
+       free(text);
+
+       if (citation_id == -1) {
+               // No match, this is an inline footnote -- create a new one
+               t->child->type = TEXT_EMPTY;
+               t->child->mate->type = TEXT_EMPTY;
+
+               // Create footnote
+               footnote * temp = footnote_new(source, NULL, t->child);
+
+               // Store as used
+               stack_push(scratch->used_citations, temp);
+               *num = scratch->used_citations->size;
+               temp->count = *num;
+
+               // We need to free this one later since it doesn't exist
+               // in the engine's stack, on the scratch_pad stack
+               stack_push(scratch->inline_citations_to_free, temp);
+       } else {
+               // Citation in stack
+               *num = citation_id;
+       }
+}
+
diff --git a/src/writer.h b/src/writer.h
new file mode 100644 (file)
index 0000000..83f4829
--- /dev/null
@@ -0,0 +1,169 @@
+/**
+
+       MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file writer.h
+
+       @brief Coordinate conversion of token tree to output formats.
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the text
+       of the license.
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining a copy
+       of this software and associated documentation files (the "Software"), to deal
+       in the Software without restriction, including without limitation the rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+       
+       The above copyright notice and this permission notice shall be included in
+       all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+       THE SOFTWARE.
+
+*/
+
+
+#ifndef WRITER_MULTIMARKDOWN_H
+#define WRITER_MULTIMARKDOWN_H
+
+#ifdef TEST
+#include "CuTest.h"
+#endif
+
+#include "d_string.h"
+#include "mmd.h"
+#include "stack.h"
+#include "token.h"
+#include "uthash.h"
+
+
+typedef struct {
+       struct link *           link_hash;
+
+       unsigned long           extensions;
+       short                           padded;                 //!< How many empty lines at end output buffer
+       short                           list_is_tight;
+       short                           skip_token;
+
+       short                           footnote_para_counter;
+       stack *                         used_footnotes;
+       stack *                         inline_footnotes_to_free;
+       struct fn_holder *      footnote_hash;
+       short                           footnote_being_printed;
+
+       stack *                         used_citations;
+       stack *                         inline_citations_to_free;
+       struct fn_holder *      citation_hash;
+       short                           citation_being_printed;
+
+       char                            _PADDING[6];    //!< pad struct for alignment
+} scratch_pad;
+
+
+struct attr {
+       char *                          key;
+       char *                          value;
+       struct attr *           next;
+};
+
+typedef struct attr attr;
+
+struct link {
+       token *                         label;
+       char *                          label_text;
+       char *                          clean_text;
+       char *                          url;
+       char *                          title;
+       attr *                          attributes;
+       UT_hash_handle          hh;
+};
+
+typedef struct link link;
+
+struct footnote {
+       token *                         label;
+       char *                          label_text;
+       char *                          clean_text;
+       token *                         content;
+       size_t                          count;
+       bool                            free_para;
+
+       char                            _PADDING[7];    //!< pad struct for alignment
+};
+
+typedef struct footnote footnote;
+
+struct fn_holder {
+       footnote *                      note;
+       UT_hash_handle          hh;
+};
+
+typedef struct fn_holder fn_holder;
+
+
+/// Temporary storage while exporting parse tree to output format
+scratch_pad * scratch_pad_new(mmd_engine * e);
+
+void scratch_pad_free(scratch_pad * scratch);
+
+
+/// Ensure at least num newlines at end of output buffer
+void pad(DString * d, short num, scratch_pad * scratch);
+
+link * explicit_link(scratch_pad * scratch, token * label, token * url, const char * source);
+
+/// Find link based on label
+link * extract_link_from_stack(scratch_pad * scratch, const char * target);
+
+char * text_inside_pair(const char * source, token * pair);
+
+void link_free(link * l);
+void footnote_free(footnote * f);
+
+char * label_from_token(const char * source, token * t);
+
+void parse_brackets(const char * source, scratch_pad * scratch, token * bracket, link ** link, short * skip_token, bool * free_link);
+
+
+void print_token_raw(DString * out, const char * source, token * t);
+
+void print_token_tree_raw(DString * out, const char * source, token * t);
+
+char * url_accept(const char * source, token ** remainder, bool validate);
+
+void footnote_from_bracket(const char * source, scratch_pad * scratch, token * t, short * num);
+void citation_from_bracket(const char * source, scratch_pad * scratch, token * t, short * num);
+
+
+#endif
+
index b2d218b38ecd7523b8c8203848acc4ea49a53232..33644cbcfe6cfe1ad1b5f9b59692163e59b1efa6 100644 (file)
 | Version:   | @My_Project_Version@      |  
 
 
-## Introduction ##
+## An Announcement! ##
 
-This template was created out of a desire to simplify some of the setup and
-configuration that I was doing over and over each time I started a new project.
-Additionally, I wanted to try to start encouraging some "better practices"
-(though not necessarily "best practices"):
+I would like to officially announce that MultiMarkdown version 6 is in public
+alpha.  It's finally at a point where it is usable, but there are quite a few
+caveats.
 
-1. [Test-driven development][tdd] -- My development of MultiMarkdown
-       focused on integration testing, but really had no unit testing to
-       speak of.  Some newer projects I began working on were a bit math-
-       heavy, and ensuring that each piece works properly became even more
-       important.  It was also nice to be able to actually develop code that
-       could do *something* (via the test suite), even though the project as
-       a whole was nowhere near complete.)  To accomplish this, I include the
-       [CuTest] project to support writing tests for your code.
+This post is a way for me to organize some of my thoughts, provide some
+history for those who are interested, and to provide some tips and tricks from
+my experiences for those who are working on their own products.
 
-2.  Use of the [cmake] build system.  `cmake` is not perfect by any
-       means, but it does offer some very useful features and a means for
-       better integrating the compilation and packaging/installation aspects
-       of development.  Rather than reinventing the wheel each time, this
-       setup incorporates basic `cmake` functionality to make it easy to 
-       control how your project is compiled, and includes automated generation
-       of the test command.
+But first, some background...
 
-3.     Templates -- `cmake` has a reasonable templating system, so that you
-       can define basic variables (e.g. author, project name, etc.) and allow
-       `cmake` to combine those elements to ensure consistency across source
-       code and README files.
 
-4.     Documentation -- some default setup to allow for [Doxygen]-generated
-       documentation.  The generated `README.md` file is used as the main 
-       page, and the source c/header files are included.  Naturally, Doxygen
-       is a complex system, so you're responsible for figuring out how to 
-       properly document your code.
+### Why a New Version? ###
 
-5.     Simplify `git` a touch -- In my larger projects, I make heavy use of
-       git modules.  One project may make use of 20-30 modules, which are
-       designed to be re-usable across other projects.  I found that I was
-       spending too much time making sure that I had the latest version
-       of a module checked out, so I created two scripts to help me keep
-       my modules in line: `link_git_modules` and `update_git_modules`.
-       You run the `link` script once to ensure that your modules are properly
-       set up, and can then run the `update` script at any time to be sure
-       you've pulled the latest version.  One advantage of this is that your
-       modules are set to a branch, rather than just a detached commit. It
-       may or may not work for your needs, but it saves me a bunch of time
-       and headache.
+MultiMarkdown version 5 was released in November of 2015, but the codebase was
+essentially the same as that of v4 -- and that was released in beta in April
+of 2013.  A few key things prompted work on a new version:
 
+* Accuracy -- MMD v4 and v5 were the most accurate versions yet, and a lot of
+effort went into finding and resolving various edge cases.  However, it began
+to feel like a game of whack-a-mole where new bugs would creep in every time I
+fixed an old one.  The PEG began to feel rather convoluted in spots, even
+though it did allow for a precise (if not always accurate) specification of
+the grammar.
 
-[tdd]: https://en.wikipedia.org/wiki/Test-driven_development
-[cmake]:       http://www.cmake.org/
-[CuTest]:      http://cutest.sourceforge.net
-[Doxygen]:     http://www.stack.nl/~dimitri/doxygen/
+* Performance -- "Back in the day" [peg-markdown] was one of the fastest
+Markdown parsers around.  MMD v3 was based on peg-markdown, and would leap-
+frog with it in terms of performance.  Then [CommonMark] was released, which
+was a bit faster. Then a couple of years went by and CommonMark became *much*
+faster -- in one of my test suites, MMD v 5.4.0 takes about 25 times longer to
+process  a long document than CommonMark 0.27.0.
 
+[peg-markdown]:        https://github.com/jgm/peg-markdown
+[CommonMark]:  http://commonmark.org/
 
-## How do I use it? ##
+Last spring, I decided I wanted to rewrite MultiMarkdown from scratch,
+building the parser myself rather than relying on a pre-rolled solution.  (I
+had been using [greg](https://github.com/ooc-lang/greg) to compile the PEG
+into parser code.  It worked well overall, but lacked some features I needed,
+requiring a lot of workarounds.)
 
-You can download the source from [github] and get to work. The file "IMPORTANT"
-contains instructions on the various build commands you can use.
 
+## First Attempt ##
 
-I recommend using the following script to automatically create a new git repo,
-pull in the default project template, and configure git-flow.  You simply have
-to rename your project directory from `new-project` to whatever you desire:
+My first attempt  started by hand-crafting a parser that scanned through the
+document a line at a time, deciding what to do with each line as it found
+them.  I used regex parsers made with [re2c](http://re2c.org/index.html) to
+help classify each line, and then a separate parser layer to process groups of
+lines into blocks.  Initially this approach worked well, and was really
+efficient.  But I quickly began to code my way into a dead-end -- the strategy
+was not elegant enough to handle things like nested lists, etc.
 
+One thing that did turn out well from the first attempt, however, was an
+approach for handling `<emph>` and `<strong>` parsing.  I've learned over the
+years that this can be one of the hardest parts of coding accurately for
+Markdown.  There are many examples that are obvious to a person, but difficult
+to properly "explain" how to parse to a computer.
 
-       #!/bin/sh
+No solution is perfect, but I developed an approach that seems to accurately
+handle a wide range of situations without a great deal of complexity:
 
-       git init new-project
+1.  Scan the documents for asterisks (`*`).  Each one will be handled one at a
+time.
 
-       cd new-project
+2.  Unlike brackets (`[` and `]`), an asterisk is "ambidextrous", in that it
+may be able to open a matched pair of asterisks, close a pair, or both.  For
+example, in `foo *bar* foo`:
 
-       git remote add "template" https://github.com/fletcher/c-template.git
+       1.      The first asterisk can open a pair, but not close one.
 
-       git pull template master
+       2.      The second asterisk can close a pair, but not open one.
 
-       git flow init -d
+3.  So, once the asterisks have been identified, each has to be examined to
+determine whether it can open/close/both.  The algorithm is not that complex,
+but I'll describe it in general terms.  Check the code for more specifics.
+This approach seems to work, but might still need some slight tweaking.  In
+the future, I'll codify this better in language rather than just in code.
 
-       git checkout develop
+       1.      If there is whitespace to the left of an asterisk, it can't close.
 
+       2.      If there is whitespace or punctuation to the right it can't open.
 
-Using this approach, you can define your own `origin` remote if you like, but
-the `template` remote can be used to update the core project files should any
-improvements come about:
+       3.      "Runs" of asterisks, e.g. `**bar` are treated as a unit in terms of
+       looking left/right.
 
-       git checkout develop
-       git merge template master
+       4.      Asterisks inside a word are a bit trickier -- we look at the number of
+       asterisks before the word, the number in the current run, and the number
+       of asterisks after the word to determine which combinations, if any, are
+       permitted.
 
-**NOTE**: `cmake` is a complex suite of utilities, and if you have trouble you
-will need to get support elsewhere.  If you find errors in this template, by
-all means I want to hear about them and fix them, but this is just a basic 
-framework to get you started.  In all likelihood, all but the most basic
-projects will need some customization.
+4.  Once all asterisks have been tagged as able to open/close/both, we proceed
+through them in order:
+
+       1.      When we encounter a tag that can close, we look to see if there is a
+       previous opener that has not been paired off.  If so, pair the two and
+       remove the opener from the list of available asterisks.
+
+       2.      When we encounter an opener, add it to the stack of available openers.
+
+       3.      When encounter an asterisk that can do both, see if it can close an
+       existing opener.  If not, then add it to the stack.
+
+5.  After all tokens in the block have been paired, then we look for nesting
+pairs of asterisks in order to create `<emph>` and `<strong>` sets.  For
+example, assume we have six asterisks wrapped around a word, three in front,
+and three after.  The asterisks are indicated with numbers: `123foo456`. We
+proceed in the following manner:
 
+       1.      Based on the pairing algorithm above, these asterisks would be paired as
+       follows, with matching asterisks sharing numbers -- `123foo321`.
+
+       2.      Moving forwards, we come to asterisk "1".  It is followed by an
+       asterisk, so we check to see if they should be grouped as a `<strong>`.
+       Since the "1" asterisks are wrapped immediately outside the "2" asterisks,
+       they are joined together.  More than two pairs can't be joined, so we now
+       get the following -- `112foo211`, where the "11" represents the opening
+       and closing of a `<strong>`, and the "2" represents a `<emph>`.
+
+6.  When matching a pair, any unclosed openers that are on the stack are
+removed, preventing pairs from "crossing" or "intersecting".  Pairs can wrap
+around each other, e.g. `[(foo)]`, but not intersect like `[(foo])`.  In the
+second case, the brackets would close, removing the `(` from the stack.
+
+7.  This same approach is used in all tokens that are matched in pairs--
+`[foo]`, `(foo)`, `_foo_`, etc.  There's slightly more to it, but once you
+figure out how to assign opening/closing ability, the rest is easy.  By using
+a stack to track available openers, it can be performed efficiently.
+
+In my testing, this approach has worked quite well.  It handles all the basic
+scenarios I've thrown at it, and all of the "basic" and "devious" edge cases I
+have thought of (some of these don't necessarily have a "right" answer -- but
+v6 gives consistency answers that seem as reasonable as any others to me).
+There are also three more edge cases I've come up can still stump it, and
+ironically they are handled correctly by most implementations.  They just
+don't follow the rules above.  I'll continue to work on this.
+
+In the end, I scrapped this effort, but kept the lessons learned in the token
+pairing algorithm.
 
-[github]:      https://github.com/fletcher/c-template
 
+## Second Attempt ##
+
+I tried again this past Fall.  This time, I approached the problem with lots
+of reading.  *Lots and lots* of reading -- tons of websites, computer science
+journal articles, PhD theses, etc.  Learned a lot about lexers, and a lot
+about parsers, including hand-crafting vs using parser generators.  In brief:
+
+1. I learned about the [Aho–Corasick algorithm], which is a great way to
+efficiently search a string for multiple target strings at once.  I used this
+to create a custom lexer to identify tokens in a MultiMarkdown text document
+(e.g. `*`, `[ `, `{++`, etc.).  I learned a lot, and had a good time working
+out the implementation.  This code efficiently allowed me to break a string of
+text into the tokens that mattered for Markdown parsing.
+
+2. However, in a few instances I really needed some features of regular
+expressions to simplify more complex structures. After a quick bit of testing,
+using re2c to create a tokenizer was just as efficient, and allowed me to
+incorporate some regex functionality that simplified later parsing.  I'll keep
+the Aho-Corasick stuff around, and will probably experiment more with it
+later.  But I didn't need it for MMD now.  `lexer.re` contains the source for
+the tokenizer.
 
-## Configuration ##
+[Aho–Corasick algorithm]: https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm
 
+I looked long and hard for a way to simplify the parsing algorithm to try and
+"touch" each token only once.  Ideally, the program could step through each
+token, and decide when to create a new block, when to pair things together,
+etc.  But I'm not convinced it's possible.  Since Markdown's grammar varies
+based on context, it seems to work best when handled in distinct phases:
+
+1. Tokenize the string to identify key sections of text.  This includes line
+breaks, allowing the text to be examined one line at time.
+
+2. Join series of lines together into blocks, such as paragraphs, code blocks,
+lists, etc.
+
+3. The tokens inside each block can then be paired together to create more
+complex syntax such as links, strong, emphasis, etc.
+
+To handle the block parsing, I started off using the [Aho-Corasick] code to
+handle my first attempt.  I had actually implemented some basic regex
+functionality, and used that to group lines together to create blocks.  But
+this quickly fell apart in the face of more complex structures such as
+recursive lists.   After a lot of searching, and *tons* more reading, I
+ultimately decided to use a parser generator to handle the task of group lines
+into blocks.  `parser.y` has the source for this, and it is processed by the
+[lemon](http://www.hwaci.com/sw/lemon/) parser generator to create the actual
+code.
+
+I chose to do this because hand-crafting the block parser would be complex.
+The end result would likely be difficult to read and understand, which would
+make it difficult to update later on.  Using the parser generator allows me to
+write things out in a way that can more easily be understood by a person.  In
+all likelihood, the performance is probably as good as anything I could do
+anyway, if not better.
+
+Because lemon is a LALR(1) parser, it does require a bit of thinking ahead
+about how to create the grammar used.  But so far, it has been able to handle
+everything I have thrown at it.
+
+
+## Optimization ##
+
+One of my goals for MMD 6 was performance.  So I've paid attention to speed
+along the way, and have tried to use a few tricks to keep things fast.  Here
+are some things I've learned along the way.  In no particular order:
+
+
+### Memory Allocation ###
+
+When parsing a long document, a *lot* of token structures are created.  Each
+one requires a small bit of memory to be allocated.  In aggregate, that time
+added up and slowed down performance.
+
+After reading for a bit, I ended up coming up with an approach that uses
+larger chunks of memory.  I allocate pools of of memory in large slabs for
+smaller "objects"".  For example, I allocate memory for 1024 tokens at a
+single time, and then dole that memory out as needed.  When the slab is empty,
+a new one is allocated.  This dramatically improved performance.
+
+When pairing tokens, I created a new stack for each block.  I realized that an
+empty stack didn't have any "leftover" cruft to interfere with re-use, so I
+just used one for the entire document.  Again a sizeable improvement in
+performance from only allocating one object instead of many.  When recursing
+to a deeper level, the stack just gets deeper, but earlier levels aren't
+modified.
 
-### CMakeLists.txt File ###
+Speaking of tokens, I realized that the average document contains a lot of
+single spaces (there's one between every two words I have written, for
+example.)  The vast majority of the time, these single spaces have no effect
+on the output of Markdown documents.  I changed my whitespace token search to
+only flag runs of 2 or more spaces, dramatically reducing the number of
+tokens.  This gives the benefit of needing fewer memory allocations, and also
+reduces the number of tokens that need to be processed later on.  The only
+downside is remember to check for a single space character in a few instances
+where it matters.
 
-First, you should update the project information under the "Define Our Project"
-section, including the title, description, etc.  This information will be used
-to update the README, as well as to create the `version.h` file so that the 
-project can have access to its own version number.
 
-You will then need to update the various groups in the "Source Files" section
-so that Cmake will be able to determine which files are used to build your
-project.  For reasons that will become clear later, try to follow the
-suggestions for the different groups of files.
+### Proper input buffering ###
 
-You then need to define your targets, such as a library, or executable, etc.
-Obviously, this will depend on the needs of your project.  You can also add
-custom steps based on the Target OS (OS X, Windows, *nix, etc.).
+When I first began last spring, I was amazed to see how much time was being
+spent by MultiMarkdown simply reading the input file.  Then I discovered it
+was because I was reading it one character at a time.  I switched to using a
+buffered read approach and the time to read the file went to almost nothing. I
+experimented with different buffer sizes, but they did not seem to make a
+measurable difference.
 
-You can use CPack to generate installers for your software.  This can be
-complex, and you will need to modify this section heavily.
 
-CuTest is used by default to provide unit testing (see below), but you
-can also use CMake/CTest to provide integration testing.  Again, this will
-be up to you to configure.
+### Output Buffering ###
+
+I experimented with different approaches to creating the output after parsing.
+I tried printing directly to `stdout`, and even played with different
+buffering settings.  None of those seemed to work well, and all were slower
+than using the `d_string` approach (formerly call `GString` in MMD 5).
 
 
-### CuTest ###
+### Fast Searches ###
 
-[CuTest] provides a means to integrate unit testing with your C source code.
-Once you get the hang of it, it's easy to use.
+After getting basic Markdown functionality complete, I discovered during
+testing that the time required to parse a document grew exponentially as the
+document grew longer.  Performance was on par with CommonMark for shorter
+documents, but fell increasingly behind in larger tests.  Time profiling found
+that the culprit was searching for link definitions when they didn't exist.
+My first approach was to keep a stack of used link definitions, and to iterate
+through them when necessary.  In long documents, this performs very poorly.
+More research and I ended up using
+[uthash](http://troydhanson.github.io/uthash/).  This allows me to search for
+a link (or footnote, etc.) by "name" rather than searching through an array.
+This allowed me to get MMD's performance back to O(n), taking roughly twice as
+much time to process a document that is twice as long.
 
 
-### Doxygen ###
+### Efficient Utility Functions ###
 
-[Doxygen] is used to generate documentation from the source code itself. 
-Properly configuring your source for this is up to you.  You can modify the
-`doxygen.conf.in` template with your desired settings as desired, but most
-of the basics are handled for you based on your CMake configuration.
+It is frequently necessary when parsing Markdown to check what sort of
+character we are dealing with at a certain position -- a letter, whitespace,
+punctuation, etc.  I created a lookup table for this via `char_lookup.c` and
+hard-coded it in `char.c`.  These routines allow me to quickly, and
+consistently, classify any byte within a document. This saved a lot of
+programming time, and saved time tracking down bugs from handling things
+slightly differently under different circumstances.  I also suspect it
+improved performance, but don't have the data to back it up.
 
 
-### GitHub Pages Support ###
+### Testing While Writing ###
 
-The `configure-gh-pages` script sets up a `documentation` directory that is 
-linked to a `gh-pages` branch of the project.  You can then run `make gh-pages` 
-to update the documentation in this directory.  Commit and push to your origin,
-and your projects gh-page is updated.
+I developed several chunks of code in parallel while creating MMD 6.  The vast
+majority of it was developed largely in a [test-driven development] approach.
+The other code was largely created with extensive unit testing to accomplish
+this.
 
+[test-driven development]: https://en.wikipedia.org/wiki/Test-driven_development
 
-### Makefile ###
+MMD isn't particularly amenable to this approach at the small level, but
+instead I relied more on integration testing with an ever-growing collection
+of text files and the corresponding HTML files in the MMD 6 test suite.  This
+allowed me to ensure new features work properly and that old features aren't
+broken.  At this time, there are 29 text files in the test suite, and many
+more to come.
 
-The overall build process is controlled by the master `Makefile`.  It provides
-the following commands:
 
-       make
-       make release
+### Other Lessons ###
 
-Generate the CMake build files for use or distribution.  Once complete you will
-need to change to the `build` directory and run `make`, `make test`, and
-`cpack` as desired.
+Some things that didn't do me any good....
 
-       make zip
+I considered differences between using `malloc` and `calloc` when initializing
+tokens.  The time saved  by using `malloc` was basically exactly offset by the
+initial time required to initialize the token to default null values as
+compared to using `calloc`.  When trying `calloc` failed to help me out
+(thinking that clearing a single slab in the object pool would be faster), I
+stuck with `malloc` as it makes more sense to me in my workflow.
 
-Direct CPack to create a zip installer rather than a graphical installer.
+I read a bit about [struct padding] and reordered some of my structs.  It was
+until later that I discovered the `-Wpadded` option, and it's not clear
+whether my changes modified anything.  Since the structs were being padded
+automatically, there was no noticeable performance change, and I didn't have
+the tools to measure whether I could have improved memory usage at all.  Not
+sure this would be worth the effort -- much lower hanging fruit available.
 
-       make debug
+[struct padding]: http://www.catb.org/esr/structure-packing/
 
-Generate build files for [CuTest] unit testing.  In the `build` directory, 
-run `make`, then `make test`.
 
-       make analyze
+## Differences in MultiMarkdown Itself ##
 
-If you have `clang` installed, this will generate debug build files with the
-`scan-build` command.  In the `build` directory, run `scan-build -V make`
-to compile the software and view the static analysis results.
+MultiMarkdown v6 is mostly about making a better MMD parser, but it will
+likely involve a few changes to the MultiMarkdown language itself.
 
-       make xcode
 
-Build a project file for Xcode on OS X.
+1. I am thinking about removing Setext headers from the language.  I almost
+never use them, much preferring to use ATX style headers (`# foo #`).
+Additionally, I have never liked the fact that Setext headers allow the
+meaning of a line to be completely changed by the following line.  It makes
+the parsing slightly more difficult on a technical level (requiring some
+backtracking at times).  I'm not 100% certain on this, but right now I believe
+it's the only Markdown feature that doesn't exist in MMD 6 yet.
 
-       make windows
-       make windows-zip
-       make windows-32
-       make windows-zip-32
+2. Whitespace is not allowed between the text brackets and label brackets in
+reference links, images, footnotes, etc.  For example `[foo] [bar]` will no
+longer be the same as `[foo][bar]`.
 
-Use the MinGW software to cross-compile for Windows on a *nix machine.  You can
-specify the 32 bit option, and also the zip option as indicated.
+3. Link and image titles can be quoted with `'foo'`, `"foo"`, or `(foo)`.
 
-       make documentation
+4. HTML elements are handled slightly differently.  There is no longer a
+`markdown="1"` feature.  Instead, HTML elements that are on a line by
+themselves will open an HTML block that will cause the rest of the "paragraph"
+to be treated as HTML such that Markdown will not be parsed in side of it.
+HTML block-level tags are even "stronger" at starting an HTML block.  It is
+not quite as complex as the approach used in CommonMark, but is similar under
+most circumstances.
 
-Build the [Doxygen]-generated documentation.
+       For example, this would not be parsed:
 
-       make clean
+               <div>
+               *foo*
+               </div>
 
-Clean out the `build` directory.  Be sure to run this before running another
-command.
+       But this would be:
 
+               <div>
 
-## Git Submodules ##
+               *foo*
 
-Apparently, submodules are a rather controversial feature in git.  For me,
-however, they have proven invaluable.  My most active projects depend on each
-other, and the submodule feature allows me to easily keep everything up to
-date.  That said, however, I quickly realized that submodules don't work very
-well using default commands.
+               </div>
 
-The problem is that I want to always use the latest version of my submodules.
-This is more easily accomplished when the submodule is set to the `master`
-branch of the original repository, rather than a detached commit as happens
-by default.  In order to easily keep all submodules updated, there are two 
-scripts:
+5. I haven't worked a lot yet on the MMD-specific features, so there may be
+more changes to come.  One thing I do anticipate is that if fenced code blocks
+stay, they will work slightly differently.  Currently, an opening fence
+doesn't mean anything unless there is a closing fence that follows it.  Again,
+this requires backtracking in the parser.  I suspect that an opening fence
+will definitely open a code block.  If there is no closing fence, then the
+rest of the document will remain inside the code block.  This is the approach
+used by CommonMark and it's a reasonable one, IMO.
 
-1. `link_git_modules` -- this script is generally only run when the master
-repository is first cloned, but can also be run after a new submodule is 
-added.  It causes the submodules to automatically track the master branch.
-If you need to modify this, there are instructions in the script itself 
-explaining how to modify it on a per submodule basis.  Running this script 
-more than one time will not hurt anything.
 
-2. `update_git_modules` -- this script simply causes each submodule to be
-updated to the latest commit in the original repository.  Again, running it
-multiple times doesn't hurt anything.
+## Where Does MultiMarkdown 6 Stand? ##
 
 
-## Source File Templates ##
+### Features ###
 
-In the `templates` directory are two files, `template.c.in` and
-`template.h.in`.  These are used to create default source files that include
-the project title, copyright, license, etc. They are also set up to include
-some example information for [Doxygen] and [CuTest].
+I *think* that all basic Markdown features have been implemented, except for
+Setext headers, as mentioned above.  Additionally, the following MultiMarkdown
+features have been implemented:
+
+* Automatic cross-reference targets
+* Basic Citation support
+* CriticMarkup support
+* Inline and reference footnotes
+* Image and Link attributes (attributes can now be used with inline links as
+       well as reference links)
+* Math support
+* Smart quotes (support for languages other than english is not fully
+       implemented yet)
+* Superscripts/subscripts
+
+
+Things that are partially completed:
+
+* Citations -- still need:
+       * Syntax for "not cited" entries
+       * Output format
+       * HTML --> separate footnotes and citations?
+       * Locators required?
+* CriticMarkup -- need to decide:
+       * How to handle CM stretches that include blank lines
+* Fenced code blocks
+
+
+Things yet to be completed:
+
+* Multiple blocks inside of reference footnotes
+* Manually specified labels for headers
+* Definition lists
+* Abbreviations
+* Metadata
+* Glossaries
+* Tables
+* Table of Contents
+* File Transclusion
+
+
+### Accuracy ###
+
+MultiMarkdown v6 successfully parses the Markdown [syntax page], except for
+the Setext header at the top.  It passes the 29 test files currently in place.
+There are a few ad
+
+[syntax page]: https://daringfireball.net/projects/markdown/syntax
+
+
+### Performance ###
+
+Basic tests show that currently MMD 6 takes about 20-25% longer the CommonMark
+0.27.0 to process long files (e.g. 0.2 MB).  However, it is around 5% *faster*
+than CommonMark when parsing a shorter file (27 kB) (measured by parsing the
+same file 200 times over).  This test suite is performed by using the Markdown
+[syntax page], modified to avoid the use of the Setext header at the top.  The
+longer files tested are created by copying the same syntax page onto itself,
+thereby doubling the length of the file with each iteration.
+
+The largest file I test is approximately 108 MB (4096 copies of the syntax
+page).  On my machine (2012 Mac mini with 2.3 GHz Intel Core i7, 16 GB RAM),
+it takes approximately 4.4 seconds to parse with MMD 6 and 3.7 seconds with
+CommonMark.  MMD 6 processes approximately 25 MB/s on this test file.
+CommonMark 0.27.0 gets about 29 MB/s on the same machine.
+
+There are some slight variations with the smaller test files (8-32 copies),
+but overall the performance of both programs (MMD 6 and CommonMark) are
+roughly linear as the test file gets bigger (double the file size and it takes
+twice as long to parse, aka O(n)).
+
+Out of curiosity, I ran the same tests on the original Markdown.pl by Gruber
+(v 1.0.2b8).  It took approximately 178 seconds to parse 128 copies of the
+file (3.4 MB) and was demonstrating quadratic performance characteristics
+(double the file size and it takes 2^2 or 4 times longer to process, aka
+O(n^2)). I didn't bother running it on larger versions of the test file.  For
+comparison, MMD 6 can process 128 copies in approximately 140 msec.
+
+Of note, the throughput speed drops when testing more complicated files
+containing more advanced MultiMarkdown features, though it still seems to
+maintain linear performance characteristics.  A second test file is created by
+concatenating all of the test suite files (including the Markdown syntax
+file).  In this case, MMD gets about 13 MB/s.  CommonMark doesn't support
+these additional features, so testing it with that file is not relevant.  I
+will work to see whether there are certain features in particular that are
+more challenging and see whether they can be reworked to improve performance.
+
+As above, I have done some high level optimization of the parse strategy, but
+I'm sure there's still a lot of room for further improvement to be made.
+Suggestions welcome!
 
 
 ## License ##
 
-@My_Project_License@
+       @My_Project_License_Indented@
index e9830d494e8128c6992776f4c51a5c7134ff2816..45897c4ce2c56b6f45cbffb3d8b6880ecf57f15a 100644 (file)
@@ -17,7 +17,7 @@
        @My_Project_Copyright@
 
 
-       @My_Project_License_Indent@
+       @My_Project_License_Indented@
 
 */
 
index 8709eca474b0e7c7d8c7e3c0360cb5d64ecb1d74..ab64f45a32227c6780bfc2f9bb8e1dae7fa36ac8 100644 (file)
@@ -17,7 +17,7 @@
        @My_Project_Copyright@
 
 
-       @My_Project_License_Indent@
+       @My_Project_License_Indented@
 
 */
 
diff --git a/test/speed-full.sh b/test/speed-full.sh
new file mode 100755 (executable)
index 0000000..f8c68c8
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/bash
+cp ../tests/MMD6Tests/Markdown\ Syntax.text ../build/speed.txt
+
+cd ../build;
+
+
+echo "MMD 6 - 8"
+cat speed.txt{,}{,}{,} > speeda.txt
+cat speeda.txt > speedbig.txt
+/usr/bin/env time -p ./multimarkdown speedbig.txt > /dev/null
+
+echo "MMD 6 - 16"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown speedbig.txt > /dev/null
+
+echo "MMD 6 - 32"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown speedbig.txt > /dev/null
+
+echo "MMD 6 - 64"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown speedbig.txt > /dev/null
+
+echo "MMD 6 - 128"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown speedbig.txt > /dev/null
+
+echo "MMD 6 - 256"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown speedbig.txt > /dev/null
+
+echo "MMD 6 - 512"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown speedbig.txt > /dev/null
+
+echo "MMD 6 - 1024"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown speedbig.txt > /dev/null
+
+echo "MMD 6 - 2048"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown speedbig.txt > /dev/null
+
+echo "MMD 6 - 4096"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown speedbig.txt > /dev/null
+
+rm speed.txt
+rm speedbig.txt
+rm speeda.txt
diff --git a/test/speed.sh b/test/speed.sh
new file mode 100755 (executable)
index 0000000..3421352
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/bash
+cp ../tests/MMD6Tests/Markdown\ Syntax.text ../build/speed.txt
+
+cd ../build;
+
+
+echo "MMD 6 - 8"
+cat speed.txt{,}{,}{,} > speeda.txt
+cat speeda.txt > speedbig.txt
+/usr/bin/env time -p ./multimarkdown -c speedbig.txt > /dev/null
+
+echo "MMD 6 - 16"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown -c speedbig.txt > /dev/null
+
+echo "MMD 6 - 32"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown -c speedbig.txt > /dev/null
+
+echo "MMD 6 - 64"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown -c speedbig.txt > /dev/null
+
+echo "MMD 6 - 128"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown -c speedbig.txt > /dev/null
+
+echo "MMD 6 - 256"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown -c speedbig.txt > /dev/null
+
+echo "MMD 6 - 512"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown -c speedbig.txt > /dev/null
+
+echo "MMD 6 - 1024"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown -c speedbig.txt > /dev/null
+
+echo "MMD 6 - 2048"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown -c speedbig.txt > /dev/null
+
+echo "MMD 6 - 4096"
+cat speeda.txt >> speedbig.txt
+cat speedbig.txt > speeda.txt
+/usr/bin/env time -p ./multimarkdown -c speedbig.txt > /dev/null
+
+rm speed.txt
+rm speedbig.txt
+rm speeda.txt
diff --git a/tests/Disabled/Advanced Footnotes.text b/tests/Disabled/Advanced Footnotes.text
new file mode 100644 (file)
index 0000000..09c21fd
--- /dev/null
@@ -0,0 +1,17 @@
+Reference.[^foo]
+
+Reference.[^foo2]
+
+Reference.[^foo3]
+
+
+[^foo]: This is a *short* footnote.
+[^foo2]: This is a longer footnote.
+
+       With two paragraphs.
+
+[^foo3]: This is a longer footnote.
+
+       * With
+       * a
+       * list
diff --git a/tests/Disabled/Advanced.html b/tests/Disabled/Advanced.html
new file mode 100644 (file)
index 0000000..7f0bf0e
--- /dev/null
@@ -0,0 +1,5 @@
+<pre><code>\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}
+</code></pre>
+
+<pre><code class="latex">\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}
+</code></pre>
diff --git a/tests/Disabled/Advanced.text b/tests/Disabled/Advanced.text
new file mode 100644 (file)
index 0000000..e25850c
--- /dev/null
@@ -0,0 +1,13 @@
+```
+\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}
+```
+
+```latex
+\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}
+```
+
+
+A slightly more [complicated *example] string* with *improperly* nested structures.
+
+[complicated *example]: http://foo.bar/
+
diff --git a/tests/Disabled/zEmph and Strong Complex.html b/tests/Disabled/zEmph and Strong Complex.html
new file mode 100644 (file)
index 0000000..3de46b5
--- /dev/null
@@ -0,0 +1,5 @@
+<p><strong>foo<em>bar</em>foo</strong></p>
+
+<p><strong>foo foo<em>bar</em>foo</strong></p>
+
+<p><strong>foo<em>bar</em>foo foo</strong></p>
diff --git a/tests/Disabled/zEmph and Strong Complex.text b/tests/Disabled/zEmph and Strong Complex.text
new file mode 100644 (file)
index 0000000..babca82
--- /dev/null
@@ -0,0 +1,5 @@
+**foo*bar*foo**
+
+**foo foo*bar*foo**
+
+**foo*bar*foo foo**
diff --git a/tests/MMD6Tests/Advanced Emph and Strong.html b/tests/MMD6Tests/Advanced Emph and Strong.html
new file mode 100644 (file)
index 0000000..0799b20
--- /dev/null
@@ -0,0 +1,59 @@
+<p>foo<em>bar</em></p>
+
+<p>foo*bar**</p>
+
+<p>foo*bar***</p>
+
+<p>foo**bar*</p>
+
+<p>foo<strong>bar</strong></p>
+
+<p>5</p>
+
+<p>foo**bar***</p>
+
+<p>foo***bar*</p>
+
+<p>foo***bar**</p>
+
+<p>foo<strong><em>bar</em></strong></p>
+
+<p><em>foo</em>bar</p>
+
+<p>10</p>
+
+<p>*foo**bar</p>
+
+<p><em>foo</em>bar*</p>
+
+<p><em>foo**bar</em></p>
+
+<p><em>foo</em><strong>bar</strong></p>
+
+<p><em>foo****bar</em></p>
+
+<p>15</p>
+
+<p><em>foo<strong>bar</strong>foo</em></p>
+
+<p>**foo*bar</p>
+
+<p><strong>foo*bar</strong></p>
+
+<p><strong>foo</strong>bar**</p>
+
+<p><strong>foo</strong><em>bar</em></p>
+
+<p>20</p>
+
+<p><strong>foo****bar</strong></p>
+
+<p><strong>foo foo<em>bar</em>foo foo</strong></p>
+
+<p><strong><em>foo</em>bar</strong></p>
+
+<p><em><strong>foo</strong>bar</em></p>
+
+<p><em>ab</em>duct instead of ab<em>duct</em></p>
+
+<p>25</p>
diff --git a/tests/MMD6Tests/Advanced Emph and Strong.htmlc b/tests/MMD6Tests/Advanced Emph and Strong.htmlc
new file mode 100644 (file)
index 0000000..0799b20
--- /dev/null
@@ -0,0 +1,59 @@
+<p>foo<em>bar</em></p>
+
+<p>foo*bar**</p>
+
+<p>foo*bar***</p>
+
+<p>foo**bar*</p>
+
+<p>foo<strong>bar</strong></p>
+
+<p>5</p>
+
+<p>foo**bar***</p>
+
+<p>foo***bar*</p>
+
+<p>foo***bar**</p>
+
+<p>foo<strong><em>bar</em></strong></p>
+
+<p><em>foo</em>bar</p>
+
+<p>10</p>
+
+<p>*foo**bar</p>
+
+<p><em>foo</em>bar*</p>
+
+<p><em>foo**bar</em></p>
+
+<p><em>foo</em><strong>bar</strong></p>
+
+<p><em>foo****bar</em></p>
+
+<p>15</p>
+
+<p><em>foo<strong>bar</strong>foo</em></p>
+
+<p>**foo*bar</p>
+
+<p><strong>foo*bar</strong></p>
+
+<p><strong>foo</strong>bar**</p>
+
+<p><strong>foo</strong><em>bar</em></p>
+
+<p>20</p>
+
+<p><strong>foo****bar</strong></p>
+
+<p><strong>foo foo<em>bar</em>foo foo</strong></p>
+
+<p><strong><em>foo</em>bar</strong></p>
+
+<p><em><strong>foo</strong>bar</em></p>
+
+<p><em>ab</em>duct instead of ab<em>duct</em></p>
+
+<p>25</p>
diff --git a/tests/MMD6Tests/Advanced Emph and Strong.text b/tests/MMD6Tests/Advanced Emph and Strong.text
new file mode 100644 (file)
index 0000000..5af2235
--- /dev/null
@@ -0,0 +1,59 @@
+foo*bar*
+
+foo*bar**
+
+foo*bar***
+
+foo**bar*
+
+foo**bar**
+
+5
+
+foo**bar***
+
+foo***bar*
+
+foo***bar**
+
+foo***bar***
+
+*foo*bar
+
+10
+
+*foo**bar
+
+*foo*bar*
+
+*foo**bar*
+
+*foo***bar**
+
+*foo****bar*
+
+15
+
+*foo**bar**foo*
+
+**foo*bar
+
+**foo*bar**
+
+**foo**bar**
+
+**foo***bar*
+
+20
+
+**foo****bar**
+
+**foo foo*bar*foo foo**
+
+***foo*bar**
+
+***foo**bar*
+
+*ab*duct instead of ab*duct*
+
+25
diff --git a/tests/MMD6Tests/Amps and Angles.html b/tests/MMD6Tests/Amps and Angles.html
new file mode 100644 (file)
index 0000000..6fc4e57
--- /dev/null
@@ -0,0 +1,24 @@
+<p>AT&amp;T has an ampersand in their name.</p>
+
+<p>AT&amp;T is another way to write it.</p>
+
+<p>This &amp; that.</p>
+
+<p>4 &lt; 5.</p>
+
+<p>6 &gt; 5.</p>
+
+<p>5</p>
+
+<p>Here is a <a href="http://example.com/?foo=1&amp;bar=2">link</a> with an ampersand in the URL.</p>
+
+<p>Here is a link with an amersand in the link text: <a href="http://att.com/" title="AT&amp;T">AT&amp;T</a>.</p>
+
+<p>Here is an inline <a href="/script?foo=1&amp;bar=2">link</a>.</p>
+
+<p>Here is an inline <a href="/script?foo=1&amp;bar=2">link</a>.</p>
+
+<pre><code>&amp; and &amp;amp; and &lt; and &gt; in code block.
+</code></pre>
+
+<p>10</p>
diff --git a/tests/MMD6Tests/Amps and Angles.htmlc b/tests/MMD6Tests/Amps and Angles.htmlc
new file mode 100644 (file)
index 0000000..6fc4e57
--- /dev/null
@@ -0,0 +1,24 @@
+<p>AT&amp;T has an ampersand in their name.</p>
+
+<p>AT&amp;T is another way to write it.</p>
+
+<p>This &amp; that.</p>
+
+<p>4 &lt; 5.</p>
+
+<p>6 &gt; 5.</p>
+
+<p>5</p>
+
+<p>Here is a <a href="http://example.com/?foo=1&amp;bar=2">link</a> with an ampersand in the URL.</p>
+
+<p>Here is a link with an amersand in the link text: <a href="http://att.com/" title="AT&amp;T">AT&amp;T</a>.</p>
+
+<p>Here is an inline <a href="/script?foo=1&amp;bar=2">link</a>.</p>
+
+<p>Here is an inline <a href="/script?foo=1&amp;bar=2">link</a>.</p>
+
+<pre><code>&amp; and &amp;amp; and &lt; and &gt; in code block.
+</code></pre>
+
+<p>10</p>
diff --git a/tests/MMD6Tests/Amps and Angles.text b/tests/MMD6Tests/Amps and Angles.text
new file mode 100644 (file)
index 0000000..3ca9d46
--- /dev/null
@@ -0,0 +1,26 @@
+AT&T has an ampersand in their name.
+
+AT&amp;T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+5
+
+Here is a [link][1] with an ampersand in the URL.
+
+Here is a link with an amersand in the link text: [AT&T][2].
+
+Here is an inline [link](/script?foo=1&bar=2).
+
+Here is an inline [link](</script?foo=1&bar=2>).
+
+       & and &amp; and < and > in code block.
+
+10
+
+[1]: http://example.com/?foo=1&bar=2
+[2]: http://att.com/  "AT&T"
diff --git a/tests/MMD6Tests/Automatic Links.html b/tests/MMD6Tests/Automatic Links.html
new file mode 100644 (file)
index 0000000..7964b5c
--- /dev/null
@@ -0,0 +1,3 @@
+<p><a href="http://foo.com/">http://foo.com/</a></p>
+
+<p><a href="&#x66;&#x6f;&#111;&#x40;&#x62;&#97;&#x72;&#x2e;&#99;&#111;&#109;">&#x66;&#x6f;&#x6f;&#x40;&#98;&#97;&#114;&#x2e;&#x63;&#x6f;&#109;</a></p>
diff --git a/tests/MMD6Tests/Automatic Links.htmlc b/tests/MMD6Tests/Automatic Links.htmlc
new file mode 100644 (file)
index 0000000..7964b5c
--- /dev/null
@@ -0,0 +1,3 @@
+<p><a href="http://foo.com/">http://foo.com/</a></p>
+
+<p><a href="&#x66;&#x6f;&#111;&#x40;&#x62;&#97;&#x72;&#x2e;&#99;&#111;&#109;">&#x66;&#x6f;&#x6f;&#x40;&#98;&#97;&#114;&#x2e;&#x63;&#x6f;&#109;</a></p>
diff --git a/tests/MMD6Tests/Automatic Links.text b/tests/MMD6Tests/Automatic Links.text
new file mode 100644 (file)
index 0000000..60da45f
--- /dev/null
@@ -0,0 +1,3 @@
+<http://foo.com/>
+
+<foo@bar.com>
diff --git a/tests/MMD6Tests/Basic Blocks.html b/tests/MMD6Tests/Basic Blocks.html
new file mode 100644 (file)
index 0000000..fb63a8f
--- /dev/null
@@ -0,0 +1,16 @@
+<p>foo</p>
+
+<h1 id="headingfoo">Heading <em>foo</em> </h1>
+
+<h2 id="heading">Heading </h2>
+
+<p>foo
+bar</p>
+
+<p>5</p>
+
+<p>foo
+bar</p>
+
+<p>foo
+bar</p>
diff --git a/tests/MMD6Tests/Basic Blocks.htmlc b/tests/MMD6Tests/Basic Blocks.htmlc
new file mode 100644 (file)
index 0000000..21822d1
--- /dev/null
@@ -0,0 +1,16 @@
+<p>foo</p>
+
+<h1>Heading <em>foo</em> </h1>
+
+<h2>Heading </h2>
+
+<p>foo
+bar</p>
+
+<p>5</p>
+
+<p>foo
+bar</p>
+
+<p>foo
+bar</p>
diff --git a/tests/MMD6Tests/Basic Blocks.text b/tests/MMD6Tests/Basic Blocks.text
new file mode 100644 (file)
index 0000000..92c9486
--- /dev/null
@@ -0,0 +1,17 @@
+foo
+
+# Heading *foo* #
+
+## Heading ##
+
+foo
+bar
+
+5
+
+foo
+       bar
+
+foo
+               bar
+
diff --git a/tests/MMD6Tests/Basic Lists.html b/tests/MMD6Tests/Basic Lists.html
new file mode 100644 (file)
index 0000000..bd29e7c
--- /dev/null
@@ -0,0 +1,74 @@
+<ul>
+<li>foo</li>
+<li>foo</li>
+<li>foo</li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+</ul>
+
+<p>5</p>
+
+<ol>
+<li>foo</li>
+<li>foo</li>
+<li>foo</li>
+</ol>
+
+<p>bar</p>
+
+<ol>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+</ol>
+
+<p>bar</p>
+
+<ol>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+</ol>
+
+<p>10</p>
+
+<ul>
+<li>foo</li>
+<li>foo</li>
+<li>foo</li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li>foo</li>
+<li>foo</li>
+<li>foo</li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li>foo
+bar</li>
+<li>foo
+bar</li>
+<li>foo
+bar</li>
+</ul>
+
+<p>15</p>
diff --git a/tests/MMD6Tests/Basic Lists.htmlc b/tests/MMD6Tests/Basic Lists.htmlc
new file mode 100644 (file)
index 0000000..bd29e7c
--- /dev/null
@@ -0,0 +1,74 @@
+<ul>
+<li>foo</li>
+<li>foo</li>
+<li>foo</li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+</ul>
+
+<p>5</p>
+
+<ol>
+<li>foo</li>
+<li>foo</li>
+<li>foo</li>
+</ol>
+
+<p>bar</p>
+
+<ol>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+</ol>
+
+<p>bar</p>
+
+<ol>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+</ol>
+
+<p>10</p>
+
+<ul>
+<li>foo</li>
+<li>foo</li>
+<li>foo</li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li>foo</li>
+<li>foo</li>
+<li>foo</li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li>foo
+bar</li>
+<li>foo
+bar</li>
+<li>foo
+bar</li>
+</ul>
+
+<p>15</p>
diff --git a/tests/MMD6Tests/Basic Lists.text b/tests/MMD6Tests/Basic Lists.text
new file mode 100644 (file)
index 0000000..04bd226
--- /dev/null
@@ -0,0 +1,64 @@
+* foo
+* foo
+* foo
+
+
+bar
+
+* foo
+
+* foo
+
+* foo
+
+
+bar
+
+*  foo
+*       foo
+
+*              foo
+
+5
+
+1. foo
+2.       foo
+3.     foo
+
+bar
+
+1. foo
+
+2. foo
+
+3. foo
+
+bar
+
+1. foo
+2. foo
+
+3. foo
+
+10
+
++ foo
++ foo
++ foo
+
+bar
+
+- foo
+- foo
+- foo
+
+bar
+
+* foo
+       bar
+* foo
+       bar
+* foo
+       bar
+
+15
diff --git a/tests/MMD6Tests/Blockquotes.html b/tests/MMD6Tests/Blockquotes.html
new file mode 100644 (file)
index 0000000..94ac71c
--- /dev/null
@@ -0,0 +1,35 @@
+<blockquote>
+<p>foo
+bar</p>
+</blockquote>
+
+<blockquote>
+<p>foo</p>
+
+<blockquote>
+<p>bar
+foo</p>
+</blockquote>
+</blockquote>
+
+<blockquote>
+<p>foo</p>
+
+<blockquote>
+<p>bar</p>
+</blockquote>
+
+<p>foo</p>
+</blockquote>
+
+<blockquote>
+<p>foo
+bar
+ foo</p>
+
+<pre><code>    bar
+foo
+</code></pre>
+
+<p>bar</p>
+</blockquote>
diff --git a/tests/MMD6Tests/Blockquotes.htmlc b/tests/MMD6Tests/Blockquotes.htmlc
new file mode 100644 (file)
index 0000000..94ac71c
--- /dev/null
@@ -0,0 +1,35 @@
+<blockquote>
+<p>foo
+bar</p>
+</blockquote>
+
+<blockquote>
+<p>foo</p>
+
+<blockquote>
+<p>bar
+foo</p>
+</blockquote>
+</blockquote>
+
+<blockquote>
+<p>foo</p>
+
+<blockquote>
+<p>bar</p>
+</blockquote>
+
+<p>foo</p>
+</blockquote>
+
+<blockquote>
+<p>foo
+bar
+ foo</p>
+
+<pre><code>    bar
+foo
+</code></pre>
+
+<p>bar</p>
+</blockquote>
diff --git a/tests/MMD6Tests/Blockquotes.text b/tests/MMD6Tests/Blockquotes.text
new file mode 100644 (file)
index 0000000..f983ae3
--- /dev/null
@@ -0,0 +1,19 @@
+> foo
+>      bar
+
+> foo
+>> bar
+> foo
+
+> foo
+> > bar
+>
+> foo
+
+>   foo
+>    bar
+>           foo
+>
+>              bar
+>      foo
+>bar
diff --git a/tests/MMD6Tests/Citations.html b/tests/MMD6Tests/Citations.html
new file mode 100644 (file)
index 0000000..7976de5
--- /dev/null
@@ -0,0 +1,18 @@
+<p><a href="#cn:1" id="cnref:1" title="see citation" class="citation">[1]</a></p>
+
+<p>[p. 123]<a href="#cn:1" id="cnref:1" title="see citation" class="citation">[1]</a></p>
+
+<p>[]<a href="#cn:1" id="cnref:1" title="see citation" class="citation">[1]</a></p>
+
+<p>[Not Cited]<a href="#cn:1" id="cnref:1" title="see citation" class="citation">[1]</a></p>
+
+<div class="citations">
+<hr />
+<ol>
+
+<li id="cn:1">
+<p>John Doe. <em>A Totally Fake Book</em>. Vanity Press, 2006. <a href="#cnref:1" title="return to body" class="reversecitation">&#160;&#8617;</a></p>
+</li>
+
+</ol>
+</div>
diff --git a/tests/MMD6Tests/Citations.htmlc b/tests/MMD6Tests/Citations.htmlc
new file mode 100644 (file)
index 0000000..2a77d6e
--- /dev/null
@@ -0,0 +1,9 @@
+<p>[#first]</p>
+
+<p>[p. 123][#first]</p>
+
+<p>[][#first]</p>
+
+<p>[Not Cited][#first]</p>
+
+<p>[#first]: John Doe. <em>A Totally Fake Book</em>. Vanity Press, 2006.</p>
diff --git a/tests/MMD6Tests/Citations.text b/tests/MMD6Tests/Citations.text
new file mode 100644 (file)
index 0000000..6540e77
--- /dev/null
@@ -0,0 +1,10 @@
+[#first]
+
+[p. 123][#first]
+
+[][#first]
+
+[Not Cited][#first]
+
+
+[#first]: John Doe. *A Totally Fake Book*.  Vanity Press, 2006.
diff --git a/tests/MMD6Tests/Code Spans.html b/tests/MMD6Tests/Code Spans.html
new file mode 100644 (file)
index 0000000..28f256a
--- /dev/null
@@ -0,0 +1,34 @@
+<p><code>foo</code></p>
+
+<p><code>foo ` bar</code></p>
+
+<p><code>``</code></p>
+
+<p><code>foo``bar</code></p>
+
+<p>``foo`</p>
+
+<p>5</p>
+
+<p>`foo``</p>
+
+<p><code>foo</code></p>
+
+<p><code>foo   bar
+baz</code></p>
+
+<p><code>foo `` bar</code></p>
+
+<p><code>foo</code></p>
+
+<p>10</p>
+
+<p><code>foo   bar</code></p>
+
+<p><code>*foo*</code></p>
+
+<p><code>[foo]</code></p>
+
+<p><code>-&lt;&gt;--&amp;\&amp;---...</code></p>
+
+<p><code>`foo`</code></p>
diff --git a/tests/MMD6Tests/Code Spans.htmlc b/tests/MMD6Tests/Code Spans.htmlc
new file mode 100644 (file)
index 0000000..28f256a
--- /dev/null
@@ -0,0 +1,34 @@
+<p><code>foo</code></p>
+
+<p><code>foo ` bar</code></p>
+
+<p><code>``</code></p>
+
+<p><code>foo``bar</code></p>
+
+<p>``foo`</p>
+
+<p>5</p>
+
+<p>`foo``</p>
+
+<p><code>foo</code></p>
+
+<p><code>foo   bar
+baz</code></p>
+
+<p><code>foo `` bar</code></p>
+
+<p><code>foo</code></p>
+
+<p>10</p>
+
+<p><code>foo   bar</code></p>
+
+<p><code>*foo*</code></p>
+
+<p><code>[foo]</code></p>
+
+<p><code>-&lt;&gt;--&amp;\&amp;---...</code></p>
+
+<p><code>`foo`</code></p>
diff --git a/tests/MMD6Tests/Code Spans.text b/tests/MMD6Tests/Code Spans.text
new file mode 100644 (file)
index 0000000..e27ed95
--- /dev/null
@@ -0,0 +1,36 @@
+`foo`
+
+`` foo ` bar  ``
+
+` `` `
+
+`foo``bar`
+
+``foo`
+
+5
+
+`foo``
+
+``
+foo
+``
+
+`foo   bar
+  baz`
+
+`foo `` bar`
+
+`   foo    `
+
+10
+
+`   foo   bar   `
+
+`*foo*`
+
+`[foo]`
+
+`-<>--&\&---...`
+
+`` `foo` ``
diff --git a/tests/MMD6Tests/CriticMarkup.html b/tests/MMD6Tests/CriticMarkup.html
new file mode 100644 (file)
index 0000000..4ae2297
--- /dev/null
@@ -0,0 +1,59 @@
+<p><ins>foo</ins></p>
+
+<p><del>bar</del></p>
+
+<p><del>foo</del><ins>bar</ins></p>
+
+<p><span class="critic comment">foo</span></p>
+
+<p><mark>bar</mark></p>
+
+<p>5</p>
+
+<p>foo<ins> bar</ins></p>
+
+<p>foo<del> bar</del></p>
+
+<p>foo <del>foo</del><ins>bar</ins></p>
+
+<p>foo <span class="critic comment">bar</span></p>
+
+<p>foo <mark>bar</mark></p>
+
+<p>10</p>
+
+<p>foo<ins> <strong>bar</strong></ins></p>
+
+<p>foo<del> <strong>bar</strong></del></p>
+
+<p>foo <del><strong>bar</strong></del><ins><strong>bar</strong></ins></p>
+
+<p>foo <span class="critic comment"><strong>bar</strong></span></p>
+
+<p>foo <mark><strong>bar</strong></mark></p>
+
+<p>15</p>
+
+<p>foo <strong><ins>bar</ins></strong></p>
+
+<p>foo <strong><del>bar</del></strong></p>
+
+<p>foo <strong><del>foo</del><ins>bar</ins></strong></p>
+
+<p>foo <strong><span class="critic comment">bar</span></strong></p>
+
+<p>foo <strong><mark>bar</mark></strong></p>
+
+<p>20</p>
+
+<p>foo **<ins>bar**</ins></p>
+
+<p>foo **<del>bar**</del></p>
+
+<p>foo **<del>foo**</del><ins>bar**</ins></p>
+
+<p>foo **<span class="critic comment">bar**</span></p>
+
+<p>foo **<mark>bar**</mark></p>
+
+<p>25</p>
diff --git a/tests/MMD6Tests/CriticMarkup.htmlc b/tests/MMD6Tests/CriticMarkup.htmlc
new file mode 100644 (file)
index 0000000..11d33ae
--- /dev/null
@@ -0,0 +1,59 @@
+<p>{++foo++}</p>
+
+<p>{--bar--}</p>
+
+<p>{~~foo~&gt;bar~~}</p>
+
+<p>{&gt;&gt;foo&lt;&lt;}</p>
+
+<p>{==bar==}</p>
+
+<p>5</p>
+
+<p>foo{++ bar++}</p>
+
+<p>foo{-- bar--}</p>
+
+<p>foo {~~foo~&gt;bar~~}</p>
+
+<p>foo {&gt;&gt;bar&lt;&lt;}</p>
+
+<p>foo {==bar==}</p>
+
+<p>10</p>
+
+<p>foo{++ <strong>bar</strong>++}</p>
+
+<p>foo{-- <strong>bar</strong>--}</p>
+
+<p>foo {~~<strong>bar</strong>~&gt;<strong>bar</strong>~~}</p>
+
+<p>foo {&gt;&gt;<strong>bar</strong>&lt;&lt;}</p>
+
+<p>foo {==<strong>bar</strong>==}</p>
+
+<p>15</p>
+
+<p>foo <strong>{++bar++}</strong></p>
+
+<p>foo <strong>{--bar--}</strong></p>
+
+<p>foo <strong>{~~foo~&gt;bar~~}</strong></p>
+
+<p>foo <strong>{&gt;&gt;bar&lt;&lt;}</strong></p>
+
+<p>foo <strong>{==bar==}</strong></p>
+
+<p>20</p>
+
+<p>foo <strong>{++bar</strong>++}</p>
+
+<p>foo <strong>{--bar</strong>--}</p>
+
+<p>foo <strong>{~~foo</strong>~&gt;bar**~~}</p>
+
+<p>foo <strong>{&gt;&gt;bar</strong>&lt;&lt;}</p>
+
+<p>foo <strong>{==bar</strong>==}</p>
+
+<p>25</p>
diff --git a/tests/MMD6Tests/CriticMarkup.text b/tests/MMD6Tests/CriticMarkup.text
new file mode 100644 (file)
index 0000000..20d7b11
--- /dev/null
@@ -0,0 +1,59 @@
+{++foo++}
+
+{--bar--}
+
+{~~foo~>bar~~}
+
+{>>foo<<}
+
+{==bar==}
+
+5
+
+foo{++ bar++}
+
+foo{-- bar--}
+
+foo {~~foo~>bar~~}
+
+foo {>>bar<<}
+
+foo {==bar==}
+
+10
+
+foo{++ **bar**++}
+
+foo{-- **bar**--}
+
+foo {~~**bar**~>**bar**~~}
+
+foo {>>**bar**<<}
+
+foo {==**bar**==}
+
+15
+
+foo **{++bar++}**
+
+foo **{--bar--}**
+
+foo **{~~foo~>bar~~}**
+
+foo **{>>bar<<}**
+
+foo **{==bar==}**
+
+20
+
+foo **{++bar**++}
+
+foo **{--bar**--}
+
+foo **{~~foo**~>bar**~~}
+
+foo **{>>bar**<<}
+
+foo **{==bar**==}
+
+25
diff --git a/tests/MMD6Tests/Cross-References.html b/tests/MMD6Tests/Cross-References.html
new file mode 100644 (file)
index 0000000..b7a152a
--- /dev/null
@@ -0,0 +1,21 @@
+<h1 id="asection">A Section </h1>
+
+<h1 id="109canstartwithdigit">109&amp;*&amp;#()^ Can Start With Digit </h1>
+
+<h1 id="stripoutcharacters">Strip out &amp;%^ characters &amp;*^ </h1>
+
+<p><a href="#asection">A Section</a>.</p>
+
+<h2 id="1cross-references:specialcharacters">1 Cross-References: Special Characters!@#$%&amp;*()&lt;&gt;^ </h2>
+
+<p>5</p>
+
+<p>And now, link to <a href="#1cross-references:specialcharacters">1 Cross-References: Special Characters!@#$%&amp;*()&lt;&gt;^</a></p>
+
+<h1 id="Заголовокпо-русски">Заголовок по-русски </h1>
+
+<p>И ссылка на <a href="#Заголовокпо-русски">Заголовок по-русски</a>.</p>
+
+<h1 id="test的multibyte">Test 的 Multibyte </h1>
+
+<p>10</p>
diff --git a/tests/MMD6Tests/Cross-References.htmlc b/tests/MMD6Tests/Cross-References.htmlc
new file mode 100644 (file)
index 0000000..9bbb4d6
--- /dev/null
@@ -0,0 +1,21 @@
+<h1>A Section </h1>
+
+<h1>109&amp;*&amp;#()^ Can Start With Digit </h1>
+
+<h1>Strip out &amp;%^ characters &amp;*^ </h1>
+
+<p>[A Section].</p>
+
+<h2>1 Cross-References: Special Characters!@#$%&amp;*()&lt;&gt;^ </h2>
+
+<p>5</p>
+
+<p>And now, link to [1 Cross-References: Special Characters!@#$%&amp;*()&lt;&gt;^][]</p>
+
+<h1>Заголовок по-русски </h1>
+
+<p>И ссылка на [Заголовок по-русски].</p>
+
+<h1>Test 的 Multibyte </h1>
+
+<p>10</p>
diff --git a/tests/MMD6Tests/Cross-References.text b/tests/MMD6Tests/Cross-References.text
new file mode 100644 (file)
index 0000000..bd4d649
--- /dev/null
@@ -0,0 +1,21 @@
+# A Section #
+
+# 109&*&#()^ Can Start With Digit #
+
+# Strip out &%^ characters &*^ #
+
+[A Section].
+
+## 1 Cross-References: Special Characters!@#$%&*()<>^ ##
+
+5
+
+And now, link to [1 Cross-References: Special Characters!@#$%&*()<>^][]
+
+# Заголовок по-русски #
+
+И ссылка на [Заголовок по-русски].
+
+# Test 的 Multibyte #
+
+10
diff --git a/tests/MMD6Tests/Edge Cases 2.html b/tests/MMD6Tests/Edge Cases 2.html
new file mode 100644 (file)
index 0000000..54b2dfd
--- /dev/null
@@ -0,0 +1,70 @@
+<p><strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em></p>
diff --git a/tests/MMD6Tests/Edge Cases 2.htmlc b/tests/MMD6Tests/Edge Cases 2.htmlc
new file mode 100644 (file)
index 0000000..54b2dfd
--- /dev/null
@@ -0,0 +1,70 @@
+<p><strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em>
+<strong>b</strong>, <em>u</em>, <strong>v</strong>, <em><strong>w</strong></em>, <em><strong>x</strong></em>, <strong><em>y</em></strong>, <strong><em>z</em></strong>, <em>t <strong>w</strong> t</em></p>
diff --git a/tests/MMD6Tests/Edge Cases 2.text b/tests/MMD6Tests/Edge Cases 2.text
new file mode 100644 (file)
index 0000000..2b15883
--- /dev/null
@@ -0,0 +1,71 @@
+
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
+**b**, _u_, __v__, *__w__*, _**x**_, ***y***, ___z___, *t __w__ t*
diff --git a/tests/MMD6Tests/Edge Cases.html b/tests/MMD6Tests/Edge Cases.html
new file mode 100644 (file)
index 0000000..fe61d34
--- /dev/null
@@ -0,0 +1,89 @@
+<ul>
+<li>foo
+bar</li>
+</ul>
+
+<p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul>
+
+<p>foo</p>
+
+<ol>
+<li>bar</li>
+</ol>
+
+<p>foo</p>
+
+<ol>
+<li>bar</li>
+</ol>
+
+<p>foo</p>
+
+<blockquote>
+<p>bar</p>
+</blockquote>
+
+<p>5</p>
+
+<p>foo</p>
+
+<h1 id="bar">bar</h1>
+
+<p>foo
+bar</p>
+
+<p>The <strong><em>quick</em></strong> brown <strong><em>fox</em></strong> jumped</p>
+
+<p>The <strong><em>quick</em></strong> brown fox jumped</p>
+
+<p>The <em><strong>quick</strong> brown fox</em> jumped</p>
+
+<p>10</p>
+
+<p>The <strong><em>quick</em> brown fox</strong> jumped</p>
+
+<p>The <strong><em>quick</em> brown <em>fox</em></strong> jumped</p>
+
+<p>The <em><strong>quick</strong> brown <strong>fox</strong></em> jumped</p>
+
+<p>This <em>should</em> be parsed &#8211; fo***o</p>
+
+<p><em>test this</em>thing</p>
+
+<p>15</p>
+
+<p>_test this_thing</p>
+
+<p><strong>test this</strong>thing</p>
+
+<p>__test this__thing</p>
+
+<p><strong><em>test this</em></strong>thing</p>
+
+<p>___test this___thing</p>
+
+<p>20</p>
+
+<p>This is <strong><em>another</em> test</strong> of <em>italics</em> and <strong>bold</strong>.</p>
+
+<p>This is <strong><em>another</em> test</strong> of <strong>bold</strong> and <em>italics</em>.</p>
+
+<p>This is <em><strong>another</strong> test</em> of <strong>bold</strong> and <em>italics</em>.</p>
+
+<p>This is <em><strong>another</strong> test</em> of <em>italics</em> and <strong>bold</strong>.</p>
+
+<p>This is <strong><em>another</em> test</strong> of <em>italics</em> and <strong>bold</strong>.</p>
+
+<p>25</p>
+
+<p>This is <strong><em>another</em> test</strong> of <strong>bold</strong> and <em>italics</em>.</p>
+
+<p>This is <em><strong>another</strong> test</em> of <strong>bold</strong> and <em>italics</em>.</p>
+
+<p>This is <em><strong>another</strong> test</em> of <em>italics</em> and <strong>bold</strong>.</p>
+
+<p>*a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a </p>
diff --git a/tests/MMD6Tests/Edge Cases.htmlc b/tests/MMD6Tests/Edge Cases.htmlc
new file mode 100644 (file)
index 0000000..6e1a2c5
--- /dev/null
@@ -0,0 +1,89 @@
+<ul>
+<li>foo
+bar</li>
+</ul>
+
+<p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul>
+
+<p>foo</p>
+
+<ol>
+<li>bar</li>
+</ol>
+
+<p>foo</p>
+
+<ol>
+<li>bar</li>
+</ol>
+
+<p>foo</p>
+
+<blockquote>
+<p>bar</p>
+</blockquote>
+
+<p>5</p>
+
+<p>foo</p>
+
+<h1>bar</h1>
+
+<p>foo
+bar</p>
+
+<p>The <strong><em>quick</em></strong> brown <strong><em>fox</em></strong> jumped</p>
+
+<p>The <strong><em>quick</em></strong> brown fox jumped</p>
+
+<p>The <em><strong>quick</strong> brown fox</em> jumped</p>
+
+<p>10</p>
+
+<p>The <strong><em>quick</em> brown fox</strong> jumped</p>
+
+<p>The <strong><em>quick</em> brown <em>fox</em></strong> jumped</p>
+
+<p>The <em><strong>quick</strong> brown <strong>fox</strong></em> jumped</p>
+
+<p>This <em>should</em> be parsed -- fo***o</p>
+
+<p><em>test this</em>thing</p>
+
+<p>15</p>
+
+<p>_test this_thing</p>
+
+<p><strong>test this</strong>thing</p>
+
+<p>__test this__thing</p>
+
+<p><strong><em>test this</em></strong>thing</p>
+
+<p>___test this___thing</p>
+
+<p>20</p>
+
+<p>This is <strong><em>another</em> test</strong> of <em>italics</em> and <strong>bold</strong>.</p>
+
+<p>This is <strong><em>another</em> test</strong> of <strong>bold</strong> and <em>italics</em>.</p>
+
+<p>This is <em><strong>another</strong> test</em> of <strong>bold</strong> and <em>italics</em>.</p>
+
+<p>This is <em><strong>another</strong> test</em> of <em>italics</em> and <strong>bold</strong>.</p>
+
+<p>This is <strong><em>another</em> test</strong> of <em>italics</em> and <strong>bold</strong>.</p>
+
+<p>25</p>
+
+<p>This is <strong><em>another</em> test</strong> of <strong>bold</strong> and <em>italics</em>.</p>
+
+<p>This is <em><strong>another</strong> test</em> of <strong>bold</strong> and <em>italics</em>.</p>
+
+<p>This is <em><strong>another</strong> test</em> of <em>italics</em> and <strong>bold</strong>.</p>
+
+<p>*a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a </p>
diff --git a/tests/MMD6Tests/Edge Cases.text b/tests/MMD6Tests/Edge Cases.text
new file mode 100644 (file)
index 0000000..f44df90
--- /dev/null
@@ -0,0 +1,74 @@
+* foo
+bar
+
+foo
+* bar
+
+foo
+1. bar
+
+foo
+2. bar
+
+foo
+> bar
+
+5
+
+foo
+# bar
+
+foo
+       bar
+
+The ***quick*** brown ***fox*** jumped
+
+The ***quick*** brown fox jumped
+
+The ***quick** brown fox* jumped
+
+10
+
+The ***quick* brown fox** jumped
+
+The ***quick* brown *fox*** jumped
+
+The ***quick** brown **fox*** jumped
+
+This *should* be parsed --  fo***o
+
+*test this*thing
+
+15
+
+_test this_thing
+
+**test this**thing
+
+__test this__thing
+
+***test this***thing
+
+___test this___thing
+
+20
+
+This is ***another* test** of *italics* and **bold**.
+
+This is ***another* test** of **bold** and *italics*.
+
+This is ***another** test* of **bold** and *italics*.
+
+This is ***another** test* of *italics* and **bold**.
+
+This is ___another_ test__ of _italics_ and __bold__.
+
+25
+
+This is ___another_ test__ of __bold__ and _italics_.
+
+This is ___another__ test_ of __bold__ and _italics_.
+
+This is ___another__ test_ of _italics_ and __bold__.
+
+*a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a *a 
diff --git a/tests/MMD6Tests/Emph and Strong Star.html b/tests/MMD6Tests/Emph and Strong Star.html
new file mode 100644 (file)
index 0000000..0fc31b0
--- /dev/null
@@ -0,0 +1,195 @@
+<p><em>foo</em></p>
+
+<p>*<em>foo</em></p>
+
+<p><em>foo</em>*</p>
+
+<p><em>foo bar</em></p>
+
+<p><em>foo</em> bar</p>
+
+<p>5</p>
+
+<p>foo <em>bar</em></p>
+
+<p><strong>foo</strong></p>
+
+<p><strong>foo bar</strong></p>
+
+<p><strong>foo</strong> bar</p>
+
+<p>foo <strong>bar</strong></p>
+
+<p>10</p>
+
+<p><em>foo <em>bar</em> foo</em></p>
+
+<p><em>foo <strong>bar</strong> foo</em></p>
+
+<p><em>foo <strong><em>bar</em></strong> foo</em></p>
+
+<p><strong>foo <em>bar</em> foo</strong></p>
+
+<p><strong>foo <strong>bar</strong> foo</strong></p>
+
+<p>15</p>
+
+<p><strong>foo <strong><em>bar</em></strong> foo</strong></p>
+
+<p><strong><em>foo <em>bar</em> foo</em></strong></p>
+
+<p><strong><em>foo <strong>bar</strong> foo</em></strong></p>
+
+<p><strong><em>foo <strong><em>bar</em></strong> foo</em></strong></p>
+
+<p><strong><em>foo</em></strong></p>
+
+<p>20</p>
+
+<p><em><strong>foo</strong> bar</em></p>
+
+<p><strong><em>foo</em> bar</strong></p>
+
+<p><em>foo <strong>bar</strong></em></p>
+
+<p><strong>foo <em>bar</em></strong></p>
+
+<p><em>foo</em>bar*</p>
+
+<p>25</p>
+
+<p><em>foo <em>bar <em>foo <em>bar</em></em></em></em></p>
+
+<p><em><em><em><em>foo</em> bar</em> foo</em> bar</em></p>
+
+<p><em>foo bar</em>bar</p>
+
+<p><strong>foo bar</strong>bar</p>
+
+<p><strong><em>foo bar</em></strong>bar</p>
+
+<p>30</p>
+
+<p>foo<em>bar</em>foo</p>
+
+<p>foo<strong>bar</strong>foo</p>
+
+<p>foo<strong><em>bar</em></strong>foo</p>
+
+<p>foo<em>bar</em>foo</p>
+
+<p><strong>foo <em>foobarfoo</em> foo</strong></p>
+
+<p>35</p>
+
+<p>foo<strong><code>*bar*</code></strong></p>
+
+<p>*(<em>foo</em>)</p>
+
+<p><em>foo</em>:</p>
+
+<p><strong>foo</strong>:</p>
+
+<p><strong><em>foo</em></strong>:</p>
+
+<p>40</p>
+
+<p>foo*bar</p>
+
+<p>foo<em>bar foo</em>bar</p>
+
+<p>foo**bar</p>
+
+<p>foo<strong>bar foo</strong>bar</p>
+
+<p>foo***bar</p>
+
+<p>45</p>
+
+<p>foo<strong><em>bar foo</em></strong>bar</p>
+
+<p>foo <strong>- bar</strong></p>
+
+<p>foo <strong>1. bar</strong></p>
+
+<p><strong>foo:</strong> bar</p>
+
+<p>*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+<em>foo</em></p>
diff --git a/tests/MMD6Tests/Emph and Strong Star.htmlc b/tests/MMD6Tests/Emph and Strong Star.htmlc
new file mode 100644 (file)
index 0000000..0fc31b0
--- /dev/null
@@ -0,0 +1,195 @@
+<p><em>foo</em></p>
+
+<p>*<em>foo</em></p>
+
+<p><em>foo</em>*</p>
+
+<p><em>foo bar</em></p>
+
+<p><em>foo</em> bar</p>
+
+<p>5</p>
+
+<p>foo <em>bar</em></p>
+
+<p><strong>foo</strong></p>
+
+<p><strong>foo bar</strong></p>
+
+<p><strong>foo</strong> bar</p>
+
+<p>foo <strong>bar</strong></p>
+
+<p>10</p>
+
+<p><em>foo <em>bar</em> foo</em></p>
+
+<p><em>foo <strong>bar</strong> foo</em></p>
+
+<p><em>foo <strong><em>bar</em></strong> foo</em></p>
+
+<p><strong>foo <em>bar</em> foo</strong></p>
+
+<p><strong>foo <strong>bar</strong> foo</strong></p>
+
+<p>15</p>
+
+<p><strong>foo <strong><em>bar</em></strong> foo</strong></p>
+
+<p><strong><em>foo <em>bar</em> foo</em></strong></p>
+
+<p><strong><em>foo <strong>bar</strong> foo</em></strong></p>
+
+<p><strong><em>foo <strong><em>bar</em></strong> foo</em></strong></p>
+
+<p><strong><em>foo</em></strong></p>
+
+<p>20</p>
+
+<p><em><strong>foo</strong> bar</em></p>
+
+<p><strong><em>foo</em> bar</strong></p>
+
+<p><em>foo <strong>bar</strong></em></p>
+
+<p><strong>foo <em>bar</em></strong></p>
+
+<p><em>foo</em>bar*</p>
+
+<p>25</p>
+
+<p><em>foo <em>bar <em>foo <em>bar</em></em></em></em></p>
+
+<p><em><em><em><em>foo</em> bar</em> foo</em> bar</em></p>
+
+<p><em>foo bar</em>bar</p>
+
+<p><strong>foo bar</strong>bar</p>
+
+<p><strong><em>foo bar</em></strong>bar</p>
+
+<p>30</p>
+
+<p>foo<em>bar</em>foo</p>
+
+<p>foo<strong>bar</strong>foo</p>
+
+<p>foo<strong><em>bar</em></strong>foo</p>
+
+<p>foo<em>bar</em>foo</p>
+
+<p><strong>foo <em>foobarfoo</em> foo</strong></p>
+
+<p>35</p>
+
+<p>foo<strong><code>*bar*</code></strong></p>
+
+<p>*(<em>foo</em>)</p>
+
+<p><em>foo</em>:</p>
+
+<p><strong>foo</strong>:</p>
+
+<p><strong><em>foo</em></strong>:</p>
+
+<p>40</p>
+
+<p>foo*bar</p>
+
+<p>foo<em>bar foo</em>bar</p>
+
+<p>foo**bar</p>
+
+<p>foo<strong>bar foo</strong>bar</p>
+
+<p>foo***bar</p>
+
+<p>45</p>
+
+<p>foo<strong><em>bar foo</em></strong>bar</p>
+
+<p>foo <strong>- bar</strong></p>
+
+<p>foo <strong>1. bar</strong></p>
+
+<p><strong>foo:</strong> bar</p>
+
+<p>*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+<em>foo</em></p>
diff --git a/tests/MMD6Tests/Emph and Strong Star.text b/tests/MMD6Tests/Emph and Strong Star.text
new file mode 100644 (file)
index 0000000..06e3146
--- /dev/null
@@ -0,0 +1,195 @@
+*foo*
+
+**foo*
+
+*foo**
+
+*foo bar*
+
+*foo* bar
+
+5
+
+foo *bar*
+
+**foo**
+
+**foo bar**
+
+**foo** bar
+
+foo **bar**
+
+10
+
+*foo *bar* foo*
+
+*foo **bar** foo*
+
+*foo ***bar*** foo*
+
+**foo *bar* foo**
+
+**foo **bar** foo**
+
+15
+
+**foo ***bar*** foo**
+
+***foo *bar* foo***
+
+***foo **bar** foo***
+
+***foo ***bar*** foo***
+
+***foo***
+
+20
+
+***foo** bar*
+
+***foo* bar**
+
+*foo **bar***
+
+**foo *bar***
+
+*foo*bar*
+
+25
+
+*foo *bar *foo *bar****
+
+****foo* bar* foo* bar*
+
+*foo bar*bar
+
+**foo bar**bar
+
+***foo bar***bar
+
+30
+
+foo*bar*foo
+
+foo**bar**foo
+
+foo***bar***foo
+
+foo*bar*foo
+
+**foo *foobarfoo* foo**
+
+35
+
+foo**`*bar*`**
+
+*(*foo*)
+
+*foo*:
+
+**foo**:
+
+***foo***:
+
+40
+
+foo*bar
+
+foo*bar foo*bar
+
+foo**bar
+
+foo**bar foo**bar
+
+foo***bar
+
+45
+
+foo***bar foo***bar
+
+foo **- bar**
+
+foo **1. bar**
+
+**foo:** bar
+
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo
+*foo*
diff --git a/tests/MMD6Tests/Emph and Strong UL.html b/tests/MMD6Tests/Emph and Strong UL.html
new file mode 100644 (file)
index 0000000..f1fd99a
--- /dev/null
@@ -0,0 +1,193 @@
+<p><em>foo</em></p>
+
+<p>_<em>foo</em></p>
+
+<p><em>foo</em>_</p>
+
+<p><em>foo bar</em></p>
+
+<p><em>foo</em> bar</p>
+
+<p>5</p>
+
+<p>foo <em>bar</em></p>
+
+<p><strong>foo</strong></p>
+
+<p><strong>foo bar</strong></p>
+
+<p><strong>foo</strong> bar</p>
+
+<p>foo <strong>bar</strong></p>
+
+<p>10</p>
+
+<p><em>foo <em>bar</em> foo</em></p>
+
+<p><em>foo <strong>bar</strong> foo</em></p>
+
+<p><em>foo <strong><em>bar</em></strong> foo</em></p>
+
+<p><strong>foo <em>bar</em> foo</strong></p>
+
+<p><strong>foo <strong>bar</strong> foo</strong></p>
+
+<p>15</p>
+
+<p><strong>foo <strong><em>bar</em></strong> foo</strong></p>
+
+<p><strong><em>foo <em>bar</em> foo</em></strong></p>
+
+<p><strong><em>foo <strong>bar</strong> foo</em></strong></p>
+
+<p><strong><em>foo <strong><em>bar</em></strong> foo</em></strong></p>
+
+<p><strong><em>foo</em></strong></p>
+
+<p>20</p>
+
+<p><em><strong>foo</strong> bar</em></p>
+
+<p><strong><em>foo</em> bar</strong></p>
+
+<p><em>foo <strong>bar</strong></em></p>
+
+<p><strong>foo <em>bar</em></strong></p>
+
+<p><em>foo_bar</em></p>
+
+<p>25</p>
+
+<p><em>foo <em>bar <em>foo <em>bar</em></em></em></em></p>
+
+<p><em><em><em><em>foo</em> bar</em> foo</em> bar</em></p>
+
+<p>_foo bar_bar</p>
+
+<p>__foo bar__bar</p>
+
+<p>___foo bar___bar</p>
+
+<p>30</p>
+
+<p>foo_bar_foo</p>
+
+<p>foo__bar__foo</p>
+
+<p>foo___bar___foo</p>
+
+<p>foo_bar_foo</p>
+
+<p><strong>foo <em>foobarfoo</em> foo</strong></p>
+
+<p>35</p>
+
+<p>foo__<code>_bar_</code>__</p>
+
+<p>_(<em>foo</em>)</p>
+
+<p><em>foo</em>:</p>
+
+<p><strong>foo</strong>:</p>
+
+<p><strong><em>foo</em></strong>:</p>
+
+<p>40</p>
+
+<p>foo_bar</p>
+
+<p>foo_bar foo_bar</p>
+
+<p>foo__bar</p>
+
+<p>foo__bar foo__bar</p>
+
+<p>foo___bar</p>
+
+<p>45</p>
+
+<p>foo___bar foo___bar</p>
+
+<p>foo __- bar__</p>
+
+<p>foo <strong>1. bar</strong></p>
+
+<p>_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+<em>foo</em></p>
diff --git a/tests/MMD6Tests/Emph and Strong UL.htmlc b/tests/MMD6Tests/Emph and Strong UL.htmlc
new file mode 100644 (file)
index 0000000..f1fd99a
--- /dev/null
@@ -0,0 +1,193 @@
+<p><em>foo</em></p>
+
+<p>_<em>foo</em></p>
+
+<p><em>foo</em>_</p>
+
+<p><em>foo bar</em></p>
+
+<p><em>foo</em> bar</p>
+
+<p>5</p>
+
+<p>foo <em>bar</em></p>
+
+<p><strong>foo</strong></p>
+
+<p><strong>foo bar</strong></p>
+
+<p><strong>foo</strong> bar</p>
+
+<p>foo <strong>bar</strong></p>
+
+<p>10</p>
+
+<p><em>foo <em>bar</em> foo</em></p>
+
+<p><em>foo <strong>bar</strong> foo</em></p>
+
+<p><em>foo <strong><em>bar</em></strong> foo</em></p>
+
+<p><strong>foo <em>bar</em> foo</strong></p>
+
+<p><strong>foo <strong>bar</strong> foo</strong></p>
+
+<p>15</p>
+
+<p><strong>foo <strong><em>bar</em></strong> foo</strong></p>
+
+<p><strong><em>foo <em>bar</em> foo</em></strong></p>
+
+<p><strong><em>foo <strong>bar</strong> foo</em></strong></p>
+
+<p><strong><em>foo <strong><em>bar</em></strong> foo</em></strong></p>
+
+<p><strong><em>foo</em></strong></p>
+
+<p>20</p>
+
+<p><em><strong>foo</strong> bar</em></p>
+
+<p><strong><em>foo</em> bar</strong></p>
+
+<p><em>foo <strong>bar</strong></em></p>
+
+<p><strong>foo <em>bar</em></strong></p>
+
+<p><em>foo_bar</em></p>
+
+<p>25</p>
+
+<p><em>foo <em>bar <em>foo <em>bar</em></em></em></em></p>
+
+<p><em><em><em><em>foo</em> bar</em> foo</em> bar</em></p>
+
+<p>_foo bar_bar</p>
+
+<p>__foo bar__bar</p>
+
+<p>___foo bar___bar</p>
+
+<p>30</p>
+
+<p>foo_bar_foo</p>
+
+<p>foo__bar__foo</p>
+
+<p>foo___bar___foo</p>
+
+<p>foo_bar_foo</p>
+
+<p><strong>foo <em>foobarfoo</em> foo</strong></p>
+
+<p>35</p>
+
+<p>foo__<code>_bar_</code>__</p>
+
+<p>_(<em>foo</em>)</p>
+
+<p><em>foo</em>:</p>
+
+<p><strong>foo</strong>:</p>
+
+<p><strong><em>foo</em></strong>:</p>
+
+<p>40</p>
+
+<p>foo_bar</p>
+
+<p>foo_bar foo_bar</p>
+
+<p>foo__bar</p>
+
+<p>foo__bar foo__bar</p>
+
+<p>foo___bar</p>
+
+<p>45</p>
+
+<p>foo___bar foo___bar</p>
+
+<p>foo __- bar__</p>
+
+<p>foo <strong>1. bar</strong></p>
+
+<p>_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+<em>foo</em></p>
diff --git a/tests/MMD6Tests/Emph and Strong UL.text b/tests/MMD6Tests/Emph and Strong UL.text
new file mode 100644 (file)
index 0000000..f2b5723
--- /dev/null
@@ -0,0 +1,193 @@
+_foo_
+
+__foo_
+
+_foo__
+
+_foo bar_
+
+_foo_ bar
+
+5
+
+foo _bar_
+
+__foo__
+
+__foo bar__
+
+__foo__ bar
+
+foo __bar__
+
+10
+
+_foo _bar_ foo_
+
+_foo __bar__ foo_
+
+_foo ___bar___ foo_
+
+__foo _bar_ foo__
+
+__foo __bar__ foo__
+
+15
+
+__foo ___bar___ foo__
+
+___foo _bar_ foo___
+
+___foo __bar__ foo___
+
+___foo ___bar___ foo___
+
+___foo___
+
+20
+
+___foo__ bar_
+
+___foo_ bar__
+
+_foo __bar___
+
+__foo _bar___
+
+_foo_bar_
+
+25
+
+_foo _bar _foo _bar____
+
+____foo_ bar_ foo_ bar_
+
+_foo bar_bar
+
+__foo bar__bar
+
+___foo bar___bar
+
+30
+
+foo_bar_foo
+
+foo__bar__foo
+
+foo___bar___foo
+
+foo_bar_foo
+
+__foo _foobarfoo_ foo__
+
+35
+
+foo__`_bar_`__
+
+_(_foo_)
+
+_foo_:
+
+__foo__:
+
+___foo___:
+
+40
+
+foo_bar
+
+foo_bar foo_bar
+
+foo__bar
+
+foo__bar foo__bar
+
+foo___bar
+
+45
+
+foo___bar foo___bar
+
+foo __- bar__
+
+foo __1. bar__
+
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo
+_foo_
diff --git a/tests/MMD6Tests/Escapes.html b/tests/MMD6Tests/Escapes.html
new file mode 100644 (file)
index 0000000..32a8f31
--- /dev/null
@@ -0,0 +1,92 @@
+<p>.</p>
+
+<p>!</p>
+
+<p>?</p>
+
+<p>,</p>
+
+<p>;</p>
+
+<p>5</p>
+
+<p>:</p>
+
+<p>&quot;</p>
+
+<p>'</p>
+
+<p>`</p>
+
+<p>~</p>
+
+<p>10</p>
+
+<p>(</p>
+
+<p>)</p>
+
+<p>{</p>
+
+<p>}</p>
+
+<p>[</p>
+
+<p>15</p>
+
+<p>]</p>
+
+<p>#</p>
+
+<p>$</p>
+
+<p>%</p>
+
+<p>+</p>
+
+<p>20</p>
+
+<p>-</p>
+
+<p>=</p>
+
+<p>&lt;</p>
+
+<p>&gt;</p>
+
+<p>&amp;</p>
+
+<p>25</p>
+
+<p>@</p>
+
+<p>\</p>
+
+<p>/</p>
+
+<p>^</p>
+
+<p>*</p>
+
+<p>30</p>
+
+<p>_</p>
+
+<p>|</p>
+
+<pre><code>\-
+\&amp;
+\%
+\\
+\`
+</code></pre>
+
+<p><code>\- \&amp; \% \\ \`</code></p>
+
+<p>*foo*</p>
+
+<p>35</p>
+
+<p>_bar_</p>
+
+<p>`foo`</p>
diff --git a/tests/MMD6Tests/Escapes.htmlc b/tests/MMD6Tests/Escapes.htmlc
new file mode 100644 (file)
index 0000000..32a8f31
--- /dev/null
@@ -0,0 +1,92 @@
+<p>.</p>
+
+<p>!</p>
+
+<p>?</p>
+
+<p>,</p>
+
+<p>;</p>
+
+<p>5</p>
+
+<p>:</p>
+
+<p>&quot;</p>
+
+<p>'</p>
+
+<p>`</p>
+
+<p>~</p>
+
+<p>10</p>
+
+<p>(</p>
+
+<p>)</p>
+
+<p>{</p>
+
+<p>}</p>
+
+<p>[</p>
+
+<p>15</p>
+
+<p>]</p>
+
+<p>#</p>
+
+<p>$</p>
+
+<p>%</p>
+
+<p>+</p>
+
+<p>20</p>
+
+<p>-</p>
+
+<p>=</p>
+
+<p>&lt;</p>
+
+<p>&gt;</p>
+
+<p>&amp;</p>
+
+<p>25</p>
+
+<p>@</p>
+
+<p>\</p>
+
+<p>/</p>
+
+<p>^</p>
+
+<p>*</p>
+
+<p>30</p>
+
+<p>_</p>
+
+<p>|</p>
+
+<pre><code>\-
+\&amp;
+\%
+\\
+\`
+</code></pre>
+
+<p><code>\- \&amp; \% \\ \`</code></p>
+
+<p>*foo*</p>
+
+<p>35</p>
+
+<p>_bar_</p>
+
+<p>`foo`</p>
diff --git a/tests/MMD6Tests/Escapes.text b/tests/MMD6Tests/Escapes.text
new file mode 100644 (file)
index 0000000..7c7c18f
--- /dev/null
@@ -0,0 +1,91 @@
+\.
+
+\!
+
+\?
+
+\,
+
+\;
+
+5
+
+\:
+
+\"
+
+\'
+
+\`
+
+\~
+
+10
+
+\(
+
+\)
+
+\{
+
+\}
+
+\[
+
+15
+
+\]
+
+\#
+
+\$
+
+\%
+
+\+
+
+20
+
+\-
+
+\=
+
+\<
+
+\>
+
+\&
+
+25
+
+\@
+
+\\
+
+\/
+
+\^
+
+\*
+
+30
+
+\_
+
+\|
+
+       \-
+       \&
+       \%
+       \\
+       \`
+
+`\- \& \% \\ \``
+
+\*foo\*
+
+35
+
+\_bar\_
+
+\`foo\`
diff --git a/tests/MMD6Tests/Fenced Code Blocks.html b/tests/MMD6Tests/Fenced Code Blocks.html
new file mode 100644 (file)
index 0000000..64170aa
--- /dev/null
@@ -0,0 +1,23 @@
+<pre><code>*foo*
+</code></pre>
+
+<pre><code>*foo*
+
+bar
+</code></pre>
+
+<ul>
+<li><p>foo</p>
+
+<pre><code>*foo*
+</code></pre></li>
+<li><p>foo</p>
+
+<pre><code>*foo*
+
+bar
+</code></pre></li>
+</ul>
+
+<pre><code>foo
+</code></pre>
diff --git a/tests/MMD6Tests/Fenced Code Blocks.htmlc b/tests/MMD6Tests/Fenced Code Blocks.htmlc
new file mode 100644 (file)
index 0000000..6586e2a
--- /dev/null
@@ -0,0 +1,23 @@
+<p><code>*foo*</code></p>
+
+<p>```
+<em>foo</em></p>
+
+<p>bar
+```</p>
+
+<ul>
+<li><p>foo</p>
+
+<p><code>*foo*</code></p></li>
+<li><p>foo</p>
+
+<p>```
+<em>foo</em></p>
+
+<p>bar
+```</p></li>
+</ul>
+
+<p>```
+foo</p>
diff --git a/tests/MMD6Tests/Fenced Code Blocks.text b/tests/MMD6Tests/Fenced Code Blocks.text
new file mode 100644 (file)
index 0000000..8f074ce
--- /dev/null
@@ -0,0 +1,29 @@
+```
+*foo*
+```
+
+```
+*foo*
+
+bar
+```
+
+
+
+
+* foo
+
+       ```
+       *foo*
+       ```
+
+* foo
+
+       ```
+       *foo*
+
+       bar
+       ```
+
+```
+foo
diff --git a/tests/MMD6Tests/HTML Blocks.html b/tests/MMD6Tests/HTML Blocks.html
new file mode 100644 (file)
index 0000000..7413787
--- /dev/null
@@ -0,0 +1,58 @@
+<p><del><em>bar</em></del></p>
+
+<del>
+*bar*
+</del>
+
+<p>foo
+<del>
+<em>bar</em>
+</del></p>
+
+<del>
+*bar*
+
+</del>
+
+<del>
+
+<p><em>bar</em></p>
+
+</del>
+
+<p>5</p>
+
+<div>*bar*</div>
+
+<div>
+*bar*
+</div>
+
+<p>foo</p>
+
+<div>
+*bar*
+</div>
+
+<div>
+*bar*
+
+</div>
+
+<div>
+
+<p><em>bar</em></p>
+
+</div>
+
+<p>10</p>
+
+<!-- This is a *comment* -->
+
+<!-- This is a
+longer
+ *comment* -->
+
+<!-- This is not a
+
+<p><em>comment</em> &#8211;&gt;</p>
diff --git a/tests/MMD6Tests/HTML Blocks.htmlc b/tests/MMD6Tests/HTML Blocks.htmlc
new file mode 100644 (file)
index 0000000..bb91798
--- /dev/null
@@ -0,0 +1,58 @@
+<p><del><em>bar</em></del></p>
+
+<del>
+*bar*
+</del>
+
+<p>foo
+<del>
+<em>bar</em>
+</del></p>
+
+<del>
+*bar*
+
+</del>
+
+<del>
+
+<p><em>bar</em></p>
+
+</del>
+
+<p>5</p>
+
+<div>*bar*</div>
+
+<div>
+*bar*
+</div>
+
+<p>foo</p>
+
+<div>
+*bar*
+</div>
+
+<div>
+*bar*
+
+</div>
+
+<div>
+
+<p><em>bar</em></p>
+
+</div>
+
+<p>10</p>
+
+<!-- This is a *comment* -->
+
+<!-- This is a
+longer
+ *comment* -->
+
+<!-- This is not a
+
+<p><em>comment</em> --&gt;</p>
diff --git a/tests/MMD6Tests/HTML Blocks.text b/tests/MMD6Tests/HTML Blocks.text
new file mode 100644 (file)
index 0000000..013d07e
--- /dev/null
@@ -0,0 +1,60 @@
+<del>*bar*</del>
+
+<del>
+*bar*
+</del>
+
+foo
+<del>
+*bar*
+</del>
+
+<del>
+*bar*
+
+</del>
+
+
+<del>
+
+*bar*
+
+</del>
+
+5
+
+<div>*bar*</div>
+
+<div>
+*bar*
+</div>
+
+foo
+<div>
+*bar*
+</div>
+
+<div>
+*bar*
+
+</div>
+
+
+<div>
+
+*bar*
+
+</div>
+
+10
+
+<!-- This is a *comment* -->
+
+<!-- This is a
+longer
+ *comment* -->
+
+
+<!-- This is not a
+
+ *comment* -->
diff --git a/tests/MMD6Tests/HTML Inline.html b/tests/MMD6Tests/HTML Inline.html
new file mode 100644 (file)
index 0000000..6a2a05a
--- /dev/null
@@ -0,0 +1,15 @@
+<p><foo><em>bar</em></foo></p>
+
+<p><foo bar="foo"><em>bar</em></foo></p>
+
+<pre><code>&lt;div&gt;
+    foo
+&lt;/div&gt;
+</code></pre>
+
+<p>test.<!-- Comment --></p>
+
+<p>test.<!-- Comment 
+with
+multiple
+line. --></p>
diff --git a/tests/MMD6Tests/HTML Inline.htmlc b/tests/MMD6Tests/HTML Inline.htmlc
new file mode 100644 (file)
index 0000000..6a2a05a
--- /dev/null
@@ -0,0 +1,15 @@
+<p><foo><em>bar</em></foo></p>
+
+<p><foo bar="foo"><em>bar</em></foo></p>
+
+<pre><code>&lt;div&gt;
+    foo
+&lt;/div&gt;
+</code></pre>
+
+<p>test.<!-- Comment --></p>
+
+<p>test.<!-- Comment 
+with
+multiple
+line. --></p>
diff --git a/tests/MMD6Tests/HTML Inline.text b/tests/MMD6Tests/HTML Inline.text
new file mode 100644 (file)
index 0000000..7af8412
--- /dev/null
@@ -0,0 +1,15 @@
+<foo>*bar*</foo>
+
+<foo bar="foo">*bar*</foo>
+
+
+       <div>
+           foo
+       </div>
+
+test.<!-- Comment -->
+
+test.<!-- Comment 
+with
+multiple
+line. -->
diff --git a/tests/MMD6Tests/Headers.html b/tests/MMD6Tests/Headers.html
new file mode 100644 (file)
index 0000000..be7dc36
--- /dev/null
@@ -0,0 +1,36 @@
+<h1 id="foo">foo </h1>
+
+<h1 id="foo">foo </h1>
+
+<h1 id="foo">foo </h1>
+
+<h1 id="foo">foo </h1>
+
+<pre><code># foo #
+</code></pre>
+
+<p>5</p>
+
+<p>#foo#</p>
+
+<p>#foo #</p>
+
+<h1 id="foobar">foo # bar</h1>
+
+<p># foo #</p>
+
+<h2 id="foo">foo </h2>
+
+<p>10</p>
+
+<h3 id="foo">foo </h3>
+
+<h4 id="foo">foo </h4>
+
+<h5 id="foo">foo </h5>
+
+<h6 id="foo">foo </h6>
+
+<p>####### foo #######</p>
+
+<p>15</p>
diff --git a/tests/MMD6Tests/Headers.htmlc b/tests/MMD6Tests/Headers.htmlc
new file mode 100644 (file)
index 0000000..579c177
--- /dev/null
@@ -0,0 +1,36 @@
+<h1>foo </h1>
+
+<h1>foo </h1>
+
+<h1>foo </h1>
+
+<h1>foo </h1>
+
+<pre><code># foo #
+</code></pre>
+
+<p>5</p>
+
+<p>#foo#</p>
+
+<p>#foo #</p>
+
+<h1>foo # bar</h1>
+
+<p># foo #</p>
+
+<h2>foo </h2>
+
+<p>10</p>
+
+<h3>foo </h3>
+
+<h4>foo </h4>
+
+<h5>foo </h5>
+
+<h6>foo </h6>
+
+<p>####### foo #######</p>
+
+<p>15</p>
diff --git a/tests/MMD6Tests/Headers.text b/tests/MMD6Tests/Headers.text
new file mode 100644 (file)
index 0000000..c159a0c
--- /dev/null
@@ -0,0 +1,35 @@
+# foo #
+
+ # foo #
+
+  # foo #
+
+   # foo #
+
+    # foo #
+
+5
+
+#foo#
+
+#foo #
+
+# foo # bar
+
+\# foo #
+
+## foo ##
+
+10
+
+### foo ###
+
+#### foo ####
+
+##### foo #####
+
+###### foo ######
+
+####### foo #######
+
+15
diff --git a/tests/MMD6Tests/Horizontal Rules.html b/tests/MMD6Tests/Horizontal Rules.html
new file mode 100644 (file)
index 0000000..dc38c62
--- /dev/null
@@ -0,0 +1,83 @@
+<p>Dashes:</p>
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<pre><code>---
+</code></pre>
+
+<p>5</p>
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<pre><code>- - -
+</code></pre>
+
+<p>10</p>
+
+<p>Asterisks:</p>
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<pre><code>***
+</code></pre>
+
+<p>15</p>
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<pre><code>* * *
+</code></pre>
+
+<p>20</p>
+
+<p>Underscores:</p>
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<pre><code>___
+</code></pre>
+
+<p>25</p>
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<pre><code>_ _ _
+</code></pre>
+
+<p>30</p>
diff --git a/tests/MMD6Tests/Horizontal Rules.htmlc b/tests/MMD6Tests/Horizontal Rules.htmlc
new file mode 100644 (file)
index 0000000..dc38c62
--- /dev/null
@@ -0,0 +1,83 @@
+<p>Dashes:</p>
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<pre><code>---
+</code></pre>
+
+<p>5</p>
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<pre><code>- - -
+</code></pre>
+
+<p>10</p>
+
+<p>Asterisks:</p>
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<pre><code>***
+</code></pre>
+
+<p>15</p>
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<pre><code>* * *
+</code></pre>
+
+<p>20</p>
+
+<p>Underscores:</p>
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<pre><code>___
+</code></pre>
+
+<p>25</p>
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<pre><code>_ _ _
+</code></pre>
+
+<p>30</p>
diff --git a/tests/MMD6Tests/Horizontal Rules.text b/tests/MMD6Tests/Horizontal Rules.text
new file mode 100644 (file)
index 0000000..0c968a6
--- /dev/null
@@ -0,0 +1,77 @@
+Dashes:
+
+---
+
+ ---
+  ---
+
+   ---
+
+       ---
+
+5
+
+- - -
+
+ - - -
+  - - -
+
+   - - -
+
+       - - -
+
+10
+
+Asterisks:
+
+***
+
+ ***
+  ***
+
+   ***
+
+       ***
+
+15
+
+* * *
+
+ * * *
+  * * *
+
+   * * *
+
+       * * *
+
+20
+
+Underscores:
+
+___
+
+ ___
+  ___
+
+   ___
+
+    ___
+
+25
+
+_ _ _
+
+ _ _ _
+  _ _ _
+
+   _ _ _
+
+    _ _ _
+
+30
diff --git a/tests/MMD6Tests/Indented Code Blocks.html b/tests/MMD6Tests/Indented Code Blocks.html
new file mode 100644 (file)
index 0000000..d170468
--- /dev/null
@@ -0,0 +1,58 @@
+<pre><code>foo
+</code></pre>
+
+<p>foo</p>
+
+<pre><code>bar
+</code></pre>
+
+<p>foo</p>
+
+<p> foo</p>
+
+<p>5</p>
+
+<p>foo</p>
+
+<p>foo</p>
+
+<pre><code>bar
+</code></pre>
+
+<p>foo</p>
+
+<pre><code>    bar
+</code></pre>
+
+<p>10</p>
+
+<p>foo</p>
+
+<pre><code>bar
+       bar
+</code></pre>
+
+<p>foo</p>
+
+<pre><code>bar
+</code></pre>
+
+<p>15</p>
+
+<p>foo
+bar
+bar</p>
+
+<p>foo</p>
+
+<pre><code>bar
+</code></pre>
+
+<p>foo</p>
+
+<pre><code>bar
+
+bar
+
+bar
+</code></pre>
diff --git a/tests/MMD6Tests/Indented Code Blocks.htmlc b/tests/MMD6Tests/Indented Code Blocks.htmlc
new file mode 100644 (file)
index 0000000..d170468
--- /dev/null
@@ -0,0 +1,58 @@
+<pre><code>foo
+</code></pre>
+
+<p>foo</p>
+
+<pre><code>bar
+</code></pre>
+
+<p>foo</p>
+
+<p> foo</p>
+
+<p>5</p>
+
+<p>foo</p>
+
+<p>foo</p>
+
+<pre><code>bar
+</code></pre>
+
+<p>foo</p>
+
+<pre><code>    bar
+</code></pre>
+
+<p>10</p>
+
+<p>foo</p>
+
+<pre><code>bar
+       bar
+</code></pre>
+
+<p>foo</p>
+
+<pre><code>bar
+</code></pre>
+
+<p>15</p>
+
+<p>foo
+bar
+bar</p>
+
+<p>foo</p>
+
+<pre><code>bar
+</code></pre>
+
+<p>foo</p>
+
+<pre><code>bar
+
+bar
+
+bar
+</code></pre>
diff --git a/tests/MMD6Tests/Indented Code Blocks.text b/tests/MMD6Tests/Indented Code Blocks.text
new file mode 100644 (file)
index 0000000..4256b80
--- /dev/null
@@ -0,0 +1,50 @@
+       foo
+
+foo
+
+       bar
+
+foo
+
+ foo
+
+5
+
+  foo
+
+   foo
+
+    bar
+
+foo
+
+               bar
+
+10
+
+foo
+
+       bar
+               bar
+
+foo
+
+       bar
+
+15
+
+foo
+       bar
+               bar
+
+foo
+
+       bar
+
+foo
+       
+       bar
+
+       bar
+
+       bar
diff --git a/tests/MMD6Tests/Inline Footnotes.html b/tests/MMD6Tests/Inline Footnotes.html
new file mode 100644 (file)
index 0000000..73f55d4
--- /dev/null
@@ -0,0 +1,20 @@
+<p>Inline.<a href="#fn:1" id="fnref:1" title="see footnote" class="footnote">[1]</a></p>
+
+<p>Inline.<a href="#fn:2" id="fnref:2" title="see footnote" class="footnote">[2]</a></p>
+
+<div class="footnotes">
+<hr />
+<ol>
+
+<li id="fn:1">
+<p>foo <em>bar</em> <a href="#fnref:1" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
+</li>
+
+<li id="fn:2">
+<p>foo <em>bar</em>
+<a href="/bar">foo</a>
+<strong>foo</strong>. <a href="#fnref:2" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
+</li>
+
+</ol>
+</div>
diff --git a/tests/MMD6Tests/Inline Footnotes.htmlc b/tests/MMD6Tests/Inline Footnotes.htmlc
new file mode 100644 (file)
index 0000000..7e1b7a6
--- /dev/null
@@ -0,0 +1,5 @@
+<p>Inline.[^foo <em>bar</em>]</p>
+
+<p>Inline.[^foo <em>bar</em>
+<a href="/bar">foo</a>
+<strong>foo</strong>.]</p>
diff --git a/tests/MMD6Tests/Inline Footnotes.text b/tests/MMD6Tests/Inline Footnotes.text
new file mode 100644 (file)
index 0000000..964006a
--- /dev/null
@@ -0,0 +1,5 @@
+Inline.[^foo *bar*]
+
+Inline.[^foo *bar*
+[foo](/bar)
+**foo**.]
diff --git a/tests/MMD6Tests/Inline Images.html b/tests/MMD6Tests/Inline Images.html
new file mode 100644 (file)
index 0000000..54b1cac
--- /dev/null
@@ -0,0 +1,27 @@
+<p>Just a <img src="/url/" alt="URL" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title preceded by two spaces" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title preceded by a tab" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title has spaces afterward" />.</p>
+
+<p>5</p>
+
+<p><a href="">Empty</a>.</p>
+
+<p><img src="/url/" alt="URL and title" title="title" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title" />.</p>
+
+<p>10</p>
+
+<p><img src="/url/" alt="URL and title" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="*title*" />.</p>
diff --git a/tests/MMD6Tests/Inline Images.htmlc b/tests/MMD6Tests/Inline Images.htmlc
new file mode 100644 (file)
index 0000000..54b1cac
--- /dev/null
@@ -0,0 +1,27 @@
+<p>Just a <img src="/url/" alt="URL" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title preceded by two spaces" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title preceded by a tab" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title has spaces afterward" />.</p>
+
+<p>5</p>
+
+<p><a href="">Empty</a>.</p>
+
+<p><img src="/url/" alt="URL and title" title="title" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="title" />.</p>
+
+<p>10</p>
+
+<p><img src="/url/" alt="URL and title" />.</p>
+
+<p><img src="/url/" alt="URL and title" title="*title*" />.</p>
diff --git a/tests/MMD6Tests/Inline Images.text b/tests/MMD6Tests/Inline Images.text
new file mode 100644 (file)
index 0000000..643b646
--- /dev/null
@@ -0,0 +1,27 @@
+Just a ![URL](/url/).
+
+![URL and title](/url/ "title").
+
+![URL and title](/url/  "title preceded by two spaces").
+
+![URL and title](/url/   "title preceded by a tab").
+
+![URL and title](/url/ "title has spaces afterward"  ).
+
+5
+
+[Empty]().
+
+![**URL** and *title*](/url/ "title").
+
+![URL and title](/url/ "title").
+
+![URL and title](/url/ 'title').
+
+![URL and title](/url/ (title)).
+
+10
+
+![URL and title](/url/ "").
+
+![URL and title](/url/ "*title*").
diff --git a/tests/MMD6Tests/Inline Links.html b/tests/MMD6Tests/Inline Links.html
new file mode 100644 (file)
index 0000000..664c4b7
--- /dev/null
@@ -0,0 +1,32 @@
+<p>Just a <a href="http://url/file.txt">URL</a>.</p>
+
+<p><a href="/url/file.txt" title="title">URL and title</a>.</p>
+
+<p><a href="/url/file.txt" title="title preceded by two spaces">URL and title</a>.</p>
+
+<p><a href="/url/file.txt" title="title preceded by a tab">URL and title</a>.</p>
+
+<p><a href="/url/file.txt" title="title has spaces afterward">URL and title</a>.</p>
+
+<p>5</p>
+
+<p><a href="">Empty</a>.</p>
+
+<p><a href="/url/file.txt" title="title"><strong>URL</strong> and <em>title</em></a>.</p>
+
+<p><a href="/url/file.txt" title="title">URL and title</a>.</p>
+
+<p><a href="/url/file.txt" title="title">URL and title</a>.</p>
+
+<p><a href="/url/file.txt" title="title">URL and title</a>.</p>
+
+<p>10</p>
+
+<p><a href="/url/file.txt">URL and title</a>.</p>
+
+<p><a href="/url/file.txt" title="*title*">URL and title</a>.</p>
+
+<p>[URL and title] (/url/file.txt &#8220;<em>title</em>&#8221;).</p>
+
+<p>[URL and title]
+(/url/file.txt &#8220;<em>title</em>&#8221;).</p>
diff --git a/tests/MMD6Tests/Inline Links.htmlc b/tests/MMD6Tests/Inline Links.htmlc
new file mode 100644 (file)
index 0000000..302544f
--- /dev/null
@@ -0,0 +1,32 @@
+<p>Just a <a href="http://url/file.txt">URL</a>.</p>
+
+<p><a href="/url/file.txt" title="title">URL and title</a>.</p>
+
+<p><a href="/url/file.txt" title="title preceded by two spaces">URL and title</a>.</p>
+
+<p><a href="/url/file.txt" title="title preceded by a tab">URL and title</a>.</p>
+
+<p><a href="/url/file.txt" title="title has spaces afterward">URL and title</a>.</p>
+
+<p>5</p>
+
+<p><a href="">Empty</a>.</p>
+
+<p><a href="/url/file.txt" title="title"><strong>URL</strong> and <em>title</em></a>.</p>
+
+<p><a href="/url/file.txt" title="title">URL and title</a>.</p>
+
+<p><a href="/url/file.txt" title="title">URL and title</a>.</p>
+
+<p><a href="/url/file.txt" title="title">URL and title</a>.</p>
+
+<p>10</p>
+
+<p><a href="/url/file.txt">URL and title</a>.</p>
+
+<p><a href="/url/file.txt" title="*title*">URL and title</a>.</p>
+
+<p>[URL and title] (/url/file.txt &quot;<em>title</em>&quot;).</p>
+
+<p>[URL and title]
+(/url/file.txt &quot;<em>title</em>&quot;).</p>
diff --git a/tests/MMD6Tests/Inline Links.text b/tests/MMD6Tests/Inline Links.text
new file mode 100644 (file)
index 0000000..a6a4095
--- /dev/null
@@ -0,0 +1,32 @@
+Just a [URL](http://url/file.txt).
+
+[URL and title](/url/file.txt "title").
+
+[URL and title](/url/file.txt  "title preceded by two spaces").
+
+[URL and title](/url/file.txt  "title preceded by a tab").
+
+[URL and title](/url/file.txt "title has spaces afterward"  ).
+
+5
+
+[Empty]().
+
+[**URL** and *title*](/url/file.txt "title").
+
+[URL and title](/url/file.txt "title").
+
+[URL and title](/url/file.txt 'title').
+
+[URL and title](/url/file.txt (title)).
+
+10
+
+[URL and title](/url/file.txt "").
+
+[URL and title](/url/file.txt "*title*").
+
+[URL and title] (/url/file.txt "*title*").
+
+[URL and title]
+(/url/file.txt "*title*").
diff --git a/tests/MMD6Tests/Link Attributes.html b/tests/MMD6Tests/Link Attributes.html
new file mode 100644 (file)
index 0000000..8afed8d
--- /dev/null
@@ -0,0 +1,11 @@
+<p>foo <img src="http://foo.bar/" alt="image" title="title" width="40px" height="400px" /></p>
+
+<p>foo <a href="http://foo.bar/1" class="external" style="border: solid black 1px;">link</a></p>
+
+<p>foo <a href="http://foo.bar/2" class="external" style="border: solid black 1px;">link2</a></p>
+
+<p>foo <a href="http://foo.bar/3" class="external" style="border: solid black 1px;">link3</a></p>
+
+<p><img src="http://foo.bar/" alt="test" title="title" width="40px" height="400px" /></p>
+
+<p>5</p>
diff --git a/tests/MMD6Tests/Link Attributes.htmlc b/tests/MMD6Tests/Link Attributes.htmlc
new file mode 100644 (file)
index 0000000..f717d6d
--- /dev/null
@@ -0,0 +1,19 @@
+<p>foo ![image][]</p>
+
+<p>foo [link][]</p>
+
+<p>foo [link2][]</p>
+
+<p>foo [link3][]</p>
+
+<p>![test](http://foo.bar/ &quot;title&quot; width=&quot;40px&quot; height=400px)</p>
+
+<p>5</p>
+
+<p>[image]:    http://foo.bar/ &quot;title&quot;       width=&quot;40px&quot;  height=400px
+[link]:                <a href="http://foo.bar/1">http://foo.bar/1</a> class=external
+style=&quot;border: solid black 1px;&quot;
+[link2]:       http://foo.bar/2 class=external
+style=&quot;border: solid black 1px;&quot;
+[link3]:       http://foo.bar/3        class=external
+style=&quot;border: solid black 1px;&quot;</p>
diff --git a/tests/MMD6Tests/Link Attributes.text b/tests/MMD6Tests/Link Attributes.text
new file mode 100644 (file)
index 0000000..e7546a6
--- /dev/null
@@ -0,0 +1,20 @@
+foo ![image][]
+
+foo [link][]
+
+foo [link2][]
+
+foo [link3][]
+
+![test](http://foo.bar/ "title" width="40px" height=400px)
+
+5
+
+
+[image]:       http://foo.bar/ "title" width="40px"    height=400px
+[link]:                <http://foo.bar/1> class=external
+                       style="border: solid black 1px;"
+[link2]:       http://foo.bar/2 class=external
+                       style="border: solid black 1px;"
+[link3]:       http://foo.bar/3        class=external
+                       style="border: solid black 1px;"
diff --git a/tests/MMD6Tests/Lists.html b/tests/MMD6Tests/Lists.html
new file mode 100644 (file)
index 0000000..3968561
--- /dev/null
@@ -0,0 +1,92 @@
+<ul>
+<li>foo</li>
+<li>foo</li>
+<li>foo</li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+</ul>
+
+<p>5</p>
+
+<ol>
+<li>foo</li>
+<li>foo</li>
+<li>foo</li>
+</ol>
+
+<p>bar</p>
+
+<ol>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+</ol>
+
+<p>bar</p>
+
+<ol>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+<li><p>foo</p></li>
+</ol>
+
+<p>10</p>
+
+<ul>
+<li>foo</li>
+<li>foo</li>
+<li>foo</li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li>foo</li>
+<li>foo</li>
+<li>foo</li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li>foo
+bar</li>
+<li>foo
+bar</li>
+<li>foo
+bar</li>
+</ul>
+
+<p>15</p>
+
+<ul>
+<li>foo
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li>foo
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li>foo
+
+<ul>
+<li>bar</li>
+</ul></li>
+</ul>
diff --git a/tests/MMD6Tests/Markdown Syntax.html b/tests/MMD6Tests/Markdown Syntax.html
new file mode 100644 (file)
index 0000000..3ed1e49
--- /dev/null
@@ -0,0 +1,956 @@
+<h1 id="markdown:syntax">Markdown: Syntax </h1>
+
+<ul id="ProjectSubmenu">
+    <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
+    <li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
+    <li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
+    <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
+    <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
+</ul>
+
+<ul>
+<li><a href="#overview">Overview</a>
+
+<ul>
+<li><a href="#philosophy">Philosophy</a></li>
+<li><a href="#html">Inline HTML</a></li>
+<li><a href="#autoescape">Automatic Escaping for Special Characters</a></li>
+</ul></li>
+<li><a href="#block">Block Elements</a>
+
+<ul>
+<li><a href="#p">Paragraphs and Line Breaks</a></li>
+<li><a href="#header">Headers</a></li>
+<li><a href="#blockquote">Blockquotes</a></li>
+<li><a href="#list">Lists</a></li>
+<li><a href="#precode">Code Blocks</a></li>
+<li><a href="#hr">Horizontal Rules</a></li>
+</ul></li>
+<li><a href="#span">Span Elements</a>
+
+<ul>
+<li><a href="#link">Links</a></li>
+<li><a href="#em">Emphasis</a></li>
+<li><a href="#code">Code</a></li>
+<li><a href="#img">Images</a></li>
+</ul></li>
+<li><a href="#misc">Miscellaneous</a>
+
+<ul>
+<li><a href="#backslash">Backslash Escapes</a></li>
+<li><a href="#autolink">Automatic Links</a></li>
+</ul></li>
+</ul>
+
+<p><strong>Note:</strong> This document is itself written using Markdown; you
+can <a href="/projects/markdown/syntax.text">see the source for it by adding &#8216;.text&#8217; to the URL</a>.</p>
+
+<hr />
+
+<h2 id="overview">Overview</h2>
+
+<h3 id="philosophy">Philosophy</h3>
+
+<p>Markdown is intended to be as easy-to-read and easy-to-write as is feasible.</p>
+
+<p>Readability, however, is emphasized above all else. A Markdown-formatted
+document should be publishable as-is, as plain text, without looking
+like it&#8217;s been marked up with tags or formatting instructions. While
+Markdown&#8217;s syntax has been influenced by several existing text-to-HTML
+filters &#8211; including <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a>, <a href="http://www.aaronsw.com/2002/atx/">atx</a>, <a href="http://textism.com/tools/textile/">Textile</a>, <a href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>,
+<a href="http://www.triptico.com/software/grutatxt.html">Grutatext</a>, and <a href="http://ettext.taint.org/doc/">EtText</a> &#8211; the single biggest source of
+inspiration for Markdown&#8217;s syntax is the format of plain text email.</p>
+
+<p>To this end, Markdown&#8217;s syntax is comprised entirely of punctuation
+characters, which punctuation characters have been carefully chosen so
+as to look like what they mean. E.g., asterisks around a word actually
+look like *emphasis*. Markdown lists look like, well, lists. Even
+blockquotes look like quoted passages of text, assuming you&#8217;ve ever
+used email.</p>
+
+<h3 id="html">Inline HTML</h3>
+
+<p>Markdown&#8217;s syntax is intended for one purpose: to be used as a
+format for <em>writing</em> for the web.</p>
+
+<p>Markdown is not a replacement for HTML, or even close to it. Its
+syntax is very small, corresponding only to a very small subset of
+HTML tags. The idea is <em>not</em> to create a syntax that makes it easier
+to insert HTML tags. In my opinion, HTML tags are already easy to
+insert. The idea for Markdown is to make it easy to read, write, and
+edit prose. HTML is a <em>publishing</em> format; Markdown is a <em>writing</em>
+format. Thus, Markdown&#8217;s formatting syntax only addresses issues that
+can be conveyed in plain text.</p>
+
+<p>For any markup that is not covered by Markdown&#8217;s syntax, you simply
+use HTML itself. There&#8217;s no need to preface it or delimit it to
+indicate that you&#8217;re switching from Markdown to HTML; you just use
+the tags.</p>
+
+<p>The only restrictions are that block-level HTML elements &#8211; e.g. <code>&lt;div&gt;</code>,
+<code>&lt;table&gt;</code>, <code>&lt;pre&gt;</code>, <code>&lt;p&gt;</code>, etc. &#8211; must be separated from surrounding
+content by blank lines, and the start and end tags of the block should
+not be indented with tabs or spaces. Markdown is smart enough not
+to add extra (unwanted) <code>&lt;p&gt;</code> tags around HTML block-level tags.</p>
+
+<p>For example, to add an HTML table to a Markdown article:</p>
+
+<pre><code>This is a regular paragraph.
+
+&lt;table&gt;
+    &lt;tr&gt;
+        &lt;td&gt;Foo&lt;/td&gt;
+    &lt;/tr&gt;
+&lt;/table&gt;
+
+This is another regular paragraph.
+</code></pre>
+
+<p>Note that Markdown formatting syntax is not processed within block-level
+HTML tags. E.g., you can&#8217;t use Markdown-style <code>*emphasis*</code> inside an
+HTML block.</p>
+
+<p>Span-level HTML tags &#8211; e.g. <code>&lt;span&gt;</code>, <code>&lt;cite&gt;</code>, or <code>&lt;del&gt;</code> &#8211; can be
+used anywhere in a Markdown paragraph, list item, or header. If you
+want, you can even use HTML tags instead of Markdown formatting; e.g. if
+you&#8217;d prefer to use HTML <code>&lt;a&gt;</code> or <code>&lt;img&gt;</code> tags instead of Markdown&#8217;s
+link or image syntax, go right ahead.</p>
+
+<p>Unlike block-level HTML tags, Markdown syntax <em>is</em> processed within
+span-level tags.</p>
+
+<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
+
+<p>In HTML, there are two characters that demand special treatment: <code>&lt;</code>
+and <code>&amp;</code>. Left angle brackets are used to start tags; ampersands are
+used to denote HTML entities. If you want to use them as literal
+characters, you must escape them as entities, e.g. <code>&amp;lt;</code>, and
+<code>&amp;amp;</code>.</p>
+
+<p>Ampersands in particular are bedeviling for web writers. If you want to
+write about &#8216;AT&amp;T&#8217;, you need to write &#8216;<code>AT&amp;amp;T</code>&#8217;. You even need to
+escape ampersands within URLs. Thus, if you want to link to:</p>
+
+<pre><code>http://images.google.com/images?num=30&amp;q=larry+bird
+</code></pre>
+
+<p>you need to encode the URL as:</p>
+
+<pre><code>http://images.google.com/images?num=30&amp;amp;q=larry+bird
+</code></pre>
+
+<p>in your anchor tag <code>href</code> attribute. Needless to say, this is easy to
+forget, and is probably the single most common source of HTML validation
+errors in otherwise well-marked-up web sites.</p>
+
+<p>Markdown allows you to use these characters naturally, taking care of
+all the necessary escaping for you. If you use an ampersand as part of
+an HTML entity, it remains unchanged; otherwise it will be translated
+into <code>&amp;amp;</code>.</p>
+
+<p>So, if you want to include a copyright symbol in your article, you can write:</p>
+
+<pre><code>&amp;copy;
+</code></pre>
+
+<p>and Markdown will leave it alone. But if you write:</p>
+
+<pre><code>AT&amp;T
+</code></pre>
+
+<p>Markdown will translate it to:</p>
+
+<pre><code>AT&amp;amp;T
+</code></pre>
+
+<p>Similarly, because Markdown supports <a href="#html">inline HTML</a>, if you use
+angle brackets as delimiters for HTML tags, Markdown will treat them as
+such. But if you write:</p>
+
+<pre><code>4 &lt; 5
+</code></pre>
+
+<p>Markdown will translate it to:</p>
+
+<pre><code>4 &amp;lt; 5
+</code></pre>
+
+<p>However, inside Markdown code spans and blocks, angle brackets and
+ampersands are <em>always</em> encoded automatically. This makes it easy to use
+Markdown to write about HTML code. (As opposed to raw HTML, which is a
+terrible format for writing about HTML syntax, because every single <code>&lt;</code>
+and <code>&amp;</code> in your example code needs to be escaped.)</p>
+
+<hr />
+
+<h2 id="block">Block Elements</h2>
+
+<h3 id="p">Paragraphs and Line Breaks</h3>
+
+<p>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 &#8211; a line containing nothing but spaces or tabs is considered
+blank.) Normal paragraphs should not be indented with spaces or tabs.</p>
+
+<p>The implication of the &#8220;one or more consecutive lines of text&#8221; rule is
+that Markdown supports &#8220;hard-wrapped&#8221; text paragraphs. This differs
+significantly from most other text-to-HTML formatters (including Movable
+Type&#8217;s &#8220;Convert Line Breaks&#8221; option) which translate every line break
+character in a paragraph into a <code>&lt;br /&gt;</code> tag.</p>
+
+<p>When you <em>do</em> want to insert a <code>&lt;br /&gt;</code> break tag using Markdown, you
+end a line with two or more spaces, then type return.</p>
+
+<p>Yes, this takes a tad more effort to create a <code>&lt;br /&gt;</code>, but a simplistic
+&#8220;every line break is a <code>&lt;br /&gt;</code>&#8221; rule wouldn&#8217;t work for Markdown.
+Markdown&#8217;s email-style <a href="#blockquote">blockquoting</a> and multi-paragraph <a href="#list">list items</a>
+work best &#8211; and look better &#8211; when you format them with hard breaks.</p>
+
+<h3 id="header">Headers</h3>
+
+<p>Markdown supports two styles of headers, <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a> and <a href="http://www.aaronsw.com/2002/atx/">atx</a>.</p>
+
+<p>Setext-style headers are &#8220;underlined&#8221; using equal signs (for first-level
+headers) and dashes (for second-level headers). For example:</p>
+
+<pre><code>This is an H1
+=============
+
+This is an H2
+-------------
+</code></pre>
+
+<p>Any number of underlining <code>=</code>&#8217;s or <code>-</code>&#8217;s will work.</p>
+
+<p>Atx-style headers use 1&#8211;6 hash characters at the start of the line,
+corresponding to header levels 1&#8211;6. For example:</p>
+
+<pre><code># This is an H1
+
+## This is an H2
+
+###### This is an H6
+</code></pre>
+
+<p>Optionally, you may &#8220;close&#8221; atx-style headers. This is purely
+cosmetic &#8211; you can use this if you think it looks better. The
+closing hashes don&#8217;t even need to match the number of hashes
+used to open the header. (The number of opening hashes
+determines the header level.) :</p>
+
+<pre><code># This is an H1 #
+
+## This is an H2 ##
+
+### This is an H3 ######
+</code></pre>
+
+<h3 id="blockquote">Blockquotes</h3>
+
+<p>Markdown uses email-style <code>&gt;</code> characters for blockquoting. If you&#8217;re
+familiar with quoting passages of text in an email message, then you
+know how to create a blockquote in Markdown. It looks best if you hard
+wrap the text and put a <code>&gt;</code> before every line:</p>
+
+<pre><code>&gt; This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+&gt; consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+&gt; Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+&gt; 
+&gt; Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+&gt; id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>Markdown allows you to be lazy and only put the <code>&gt;</code> before the first
+line of a hard-wrapped paragraph:</p>
+
+<pre><code>&gt; This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+
+&gt; Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
+adding additional levels of <code>&gt;</code>:</p>
+
+<pre><code>&gt; This is the first level of quoting.
+&gt;
+&gt; &gt; This is nested blockquote.
+&gt;
+&gt; Back to the first level.
+</code></pre>
+
+<p>Blockquotes can contain other Markdown elements, including headers, lists,
+and code blocks:</p>
+
+<pre><code>&gt; ## This is a header.
+&gt; 
+&gt; 1.   This is the first list item.
+&gt; 2.   This is the second list item.
+&gt; 
+&gt; Here's some example code:
+&gt; 
+&gt;     return shell_exec(&quot;echo $input | $markdown_script&quot;);
+</code></pre>
+
+<p>Any decent text editor should make email-style quoting easy. For
+example, with BBEdit, you can make a selection and choose Increase
+Quote Level from the Text menu.</p>
+
+<h3 id="list">Lists</h3>
+
+<p>Markdown supports ordered (numbered) and unordered (bulleted) lists.</p>
+
+<p>Unordered lists use asterisks, pluses, and hyphens &#8211; interchangably
+&#8211; as list markers:</p>
+
+<pre><code>*   Red
+*   Green
+*   Blue
+</code></pre>
+
+<p>is equivalent to:</p>
+
+<pre><code>+   Red
++   Green
++   Blue
+</code></pre>
+
+<p>and:</p>
+
+<pre><code>-   Red
+-   Green
+-   Blue
+</code></pre>
+
+<p>Ordered lists use numbers followed by periods:</p>
+
+<pre><code>1.  Bird
+2.  McHale
+3.  Parish
+</code></pre>
+
+<p>It&#8217;s important to note that the actual numbers you use to mark the
+list have no effect on the HTML output Markdown produces. The HTML
+Markdown produces from the above list is:</p>
+
+<pre><code>&lt;ol&gt;
+&lt;li&gt;Bird&lt;/li&gt;
+&lt;li&gt;McHale&lt;/li&gt;
+&lt;li&gt;Parish&lt;/li&gt;
+&lt;/ol&gt;
+</code></pre>
+
+<p>If you instead wrote the list in Markdown like this:</p>
+
+<pre><code>1.  Bird
+1.  McHale
+1.  Parish
+</code></pre>
+
+<p>or even:</p>
+
+<pre><code>3. Bird
+1. McHale
+8. Parish
+</code></pre>
+
+<p>you&#8217;d get the exact same HTML output. The point is, if you want to,
+you can use ordinal numbers in your ordered Markdown lists, so that
+the numbers in your source match the numbers in your published HTML.
+But if you want to be lazy, you don&#8217;t have to.</p>
+
+<p>If you do use lazy list numbering, however, you should still start the
+list with the number 1. At some point in the future, Markdown may support
+starting ordered lists at an arbitrary number.</p>
+
+<p>List markers typically start at the left margin, but may be indented by
+up to three spaces. List markers must be followed by one or more spaces
+or a tab.</p>
+
+<p>To make lists look nice, you can wrap items with hanging indents:</p>
+
+<pre><code>*   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+    Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+    viverra nec, fringilla in, laoreet vitae, risus.
+*   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+    Suspendisse id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>But if you want to be lazy, you don&#8217;t have to:</p>
+
+<pre><code>*   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+viverra nec, fringilla in, laoreet vitae, risus.
+*   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+Suspendisse id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>If list items are separated by blank lines, Markdown will wrap the
+items in <code>&lt;p&gt;</code> tags in the HTML output. For example, this input:</p>
+
+<pre><code>*   Bird
+*   Magic
+</code></pre>
+
+<p>will turn into:</p>
+
+<pre><code>&lt;ul&gt;
+&lt;li&gt;Bird&lt;/li&gt;
+&lt;li&gt;Magic&lt;/li&gt;
+&lt;/ul&gt;
+</code></pre>
+
+<p>But this:</p>
+
+<pre><code>*   Bird
+
+*   Magic
+</code></pre>
+
+<p>will turn into:</p>
+
+<pre><code>&lt;ul&gt;
+&lt;li&gt;&lt;p&gt;Bird&lt;/p&gt;&lt;/li&gt;
+&lt;li&gt;&lt;p&gt;Magic&lt;/p&gt;&lt;/li&gt;
+&lt;/ul&gt;
+</code></pre>
+
+<p>List items may consist of multiple paragraphs. Each subsequent
+paragraph in a list item must be indented by either 4 spaces
+or one tab:</p>
+
+<pre><code>1.  This is a list item with two paragraphs. Lorem ipsum dolor
+    sit amet, consectetuer adipiscing elit. Aliquam hendrerit
+    mi posuere lectus.
+
+    Vestibulum enim wisi, viverra nec, fringilla in, laoreet
+    vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
+    sit amet velit.
+
+2.  Suspendisse id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>It looks nice if you indent every line of the subsequent
+paragraphs, but here again, Markdown will allow you to be
+lazy:</p>
+
+<pre><code>*   This is a list item with two paragraphs.
+
+    This is the second paragraph in the list item. You're
+only required to indent the first line. Lorem ipsum dolor
+sit amet, consectetuer adipiscing elit.
+
+*   Another item in the same list.
+</code></pre>
+
+<p>To put a blockquote within a list item, the blockquote&#8217;s <code>&gt;</code>
+delimiters need to be indented:</p>
+
+<pre><code>*   A list item with a blockquote:
+
+    &gt; This is a blockquote
+    &gt; inside a list item.
+</code></pre>
+
+<p>To put a code block within a list item, the code block needs
+to be indented <em>twice</em> &#8211; 8 spaces or two tabs:</p>
+
+<pre><code>*   A list item with a code block:
+
+        &lt;code goes here&gt;
+</code></pre>
+
+<p>It&#8217;s worth noting that it&#8217;s possible to trigger an ordered list by
+accident, by writing something like this:</p>
+
+<pre><code>1986. What a great season.
+</code></pre>
+
+<p>In other words, a <em>number-period-space</em> sequence at the beginning of a
+line. To avoid this, you can backslash-escape the period:</p>
+
+<pre><code>1986\. What a great season.
+</code></pre>
+
+<h3 id="precode">Code Blocks</h3>
+
+<p>Pre-formatted code blocks are used for writing about programming or
+markup source code. Rather than forming normal paragraphs, the lines
+of a code block are interpreted literally. Markdown wraps a code block
+in both <code>&lt;pre&gt;</code> and <code>&lt;code&gt;</code> tags.</p>
+
+<p>To produce a code block in Markdown, simply indent every line of the
+block by at least 4 spaces or 1 tab. For example, given this input:</p>
+
+<pre><code>This is a normal paragraph:
+
+    This is a code block.
+</code></pre>
+
+<p>Markdown will generate:</p>
+
+<pre><code>&lt;p&gt;This is a normal paragraph:&lt;/p&gt;
+
+&lt;pre&gt;&lt;code&gt;This is a code block.
+&lt;/code&gt;&lt;/pre&gt;
+</code></pre>
+
+<p>One level of indentation &#8211; 4 spaces or 1 tab &#8211; is removed from each
+line of the code block. For example, this:</p>
+
+<pre><code>Here is an example of AppleScript:
+
+    tell application &quot;Foo&quot;
+        beep
+    end tell
+</code></pre>
+
+<p>will turn into:</p>
+
+<pre><code>&lt;p&gt;Here is an example of AppleScript:&lt;/p&gt;
+
+&lt;pre&gt;&lt;code&gt;tell application &quot;Foo&quot;
+    beep
+end tell
+&lt;/code&gt;&lt;/pre&gt;
+</code></pre>
+
+<p>A code block continues until it reaches a line that is not indented
+(or the end of the article).</p>
+
+<p>Within a code block, ampersands (<code>&amp;</code>) and angle brackets (<code>&lt;</code> and <code>&gt;</code>)
+are automatically converted into HTML entities. This makes it very
+easy to include example HTML source code using Markdown &#8211; just paste
+it and indent it, and Markdown will handle the hassle of encoding the
+ampersands and angle brackets. For example, this:</p>
+
+<pre><code>    &lt;div class=&quot;footer&quot;&gt;
+        &amp;copy; 2004 Foo Corporation
+    &lt;/div&gt;
+</code></pre>
+
+<p>will turn into:</p>
+
+<pre><code>&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;footer&quot;&amp;gt;
+    &amp;amp;copy; 2004 Foo Corporation
+&amp;lt;/div&amp;gt;
+&lt;/code&gt;&lt;/pre&gt;
+</code></pre>
+
+<p>Regular Markdown syntax is not processed within code blocks. E.g.,
+asterisks are just literal asterisks within a code block. This means
+it&#8217;s also easy to use Markdown to write about Markdown&#8217;s own syntax.</p>
+
+<h3 id="hr">Horizontal Rules</h3>
+
+<p>You can produce a horizontal rule tag (<code>&lt;hr /&gt;</code>) by placing three or
+more hyphens, asterisks, or underscores on a line by themselves. If you
+wish, you may use spaces between the hyphens or asterisks. Each of the
+following lines will produce a horizontal rule:</p>
+
+<pre><code>* * *
+
+***
+
+*****
+
+- - -
+
+---------------------------------------
+</code></pre>
+
+<hr />
+
+<h2 id="span">Span Elements</h2>
+
+<h3 id="link">Links</h3>
+
+<p>Markdown supports two style of links: <em>inline</em> and <em>reference</em>.</p>
+
+<p>In both styles, the link text is delimited by [square brackets].</p>
+
+<p>To create an inline link, use a set of regular parentheses immediately
+after the link text&#8217;s closing square bracket. Inside the parentheses,
+put the URL where you want the link to point, along with an <em>optional</em>
+title for the link, surrounded in quotes. For example:</p>
+
+<pre><code>This is [an example](http://example.com/ &quot;Title&quot;) inline link.
+
+[This link](http://example.net/) has no title attribute.
+</code></pre>
+
+<p>Will produce:</p>
+
+<pre><code>&lt;p&gt;This is &lt;a href=&quot;http://example.com/&quot; title=&quot;Title&quot;&gt;
+an example&lt;/a&gt; inline link.&lt;/p&gt;
+
+&lt;p&gt;&lt;a href=&quot;http://example.net/&quot;&gt;This link&lt;/a&gt; has no
+title attribute.&lt;/p&gt;
+</code></pre>
+
+<p>If you&#8217;re referring to a local resource on the same server, you can
+use relative paths:</p>
+
+<pre><code>See my [About](/about/) page for details.   
+</code></pre>
+
+<p>Reference-style links use a second set of square brackets, inside
+which you place a label of your choosing to identify the link:</p>
+
+<pre><code>This is [an example][id] reference-style link.
+</code></pre>
+
+<p>You can optionally use a space to separate the sets of brackets:</p>
+
+<pre><code>This is [an example] [id] reference-style link.
+</code></pre>
+
+<p>Then, anywhere in the document, you define your link label like this,
+on a line by itself:</p>
+
+<pre><code>[id]: http://example.com/  &quot;Optional Title Here&quot;
+</code></pre>
+
+<p>That is:</p>
+
+<ul>
+<li>Square brackets containing the link identifier (optionally
+indented from the left margin using up to three spaces);</li>
+<li>followed by a colon;</li>
+<li>followed by one or more spaces (or tabs);</li>
+<li>followed by the URL for the link;</li>
+<li>optionally followed by a title attribute for the link, enclosed
+in double or single quotes, or enclosed in parentheses.</li>
+</ul>
+
+<p>The following three link definitions are equivalent:</p>
+
+<pre><code>[foo]: http://example.com/  &quot;Optional Title Here&quot;
+[foo]: http://example.com/  'Optional Title Here'
+[foo]: http://example.com/  (Optional Title Here)
+</code></pre>
+
+<p><strong>Note:</strong> There is a known bug in Markdown.pl 1.0.1 which prevents
+single quotes from being used to delimit link titles.</p>
+
+<p>The link URL may, optionally, be surrounded by angle brackets:</p>
+
+<pre><code>[id]: &lt;http://example.com/&gt;  &quot;Optional Title Here&quot;
+</code></pre>
+
+<p>You can put the title attribute on the next line and use extra spaces
+or tabs for padding, which tends to look better with longer URLs:</p>
+
+<pre><code>[id]: http://example.com/longish/path/to/resource/here
+    &quot;Optional Title Here&quot;
+</code></pre>
+
+<p>Link definitions are only used for creating links during Markdown
+processing, and are stripped from your document in the HTML output.</p>
+
+<p>Link definition names may consist of letters, numbers, spaces, and
+punctuation &#8211; but they are <em>not</em> case sensitive. E.g. these two
+links:</p>
+
+<pre><code>[link text][a]
+[link text][A]
+</code></pre>
+
+<p>are equivalent.</p>
+
+<p>The <em>implicit link name</em> shortcut allows you to omit the name of the
+link, in which case the link text itself is used as the name.
+Just use an empty set of square brackets &#8211; e.g., to link the word
+&#8220;Google&#8221; to the google.com web site, you could simply write:</p>
+
+<pre><code>[Google][]
+</code></pre>
+
+<p>And then define the link:</p>
+
+<pre><code>[Google]: http://google.com/
+</code></pre>
+
+<p>Because link names may contain spaces, this shortcut even works for
+multiple words in the link text:</p>
+
+<pre><code>Visit [Daring Fireball][] for more information.
+</code></pre>
+
+<p>And then define the link:</p>
+
+<pre><code>[Daring Fireball]: http://daringfireball.net/
+</code></pre>
+
+<p>Link definitions can be placed anywhere in your Markdown document. I
+tend to put them immediately after each paragraph in which they&#8217;re
+used, but if you want, you can put them all at the end of your
+document, sort of like footnotes.</p>
+
+<p>Here&#8217;s an example of reference links in action:</p>
+
+<pre><code>I get 10 times more traffic from [Google] [1] than from
+[Yahoo] [2] or [MSN] [3].
+
+  [1]: http://google.com/        &quot;Google&quot;
+  [2]: http://search.yahoo.com/  &quot;Yahoo Search&quot;
+  [3]: http://search.msn.com/    &quot;MSN Search&quot;
+</code></pre>
+
+<p>Using the implicit link name shortcut, you could instead write:</p>
+
+<pre><code>I get 10 times more traffic from [Google][] than from
+[Yahoo][] or [MSN][].
+
+  [google]: http://google.com/        &quot;Google&quot;
+  [yahoo]:  http://search.yahoo.com/  &quot;Yahoo Search&quot;
+  [msn]:    http://search.msn.com/    &quot;MSN Search&quot;
+</code></pre>
+
+<p>Both of the above examples will produce the following HTML output:</p>
+
+<pre><code>&lt;p&gt;I get 10 times more traffic from &lt;a href=&quot;http://google.com/&quot;
+title=&quot;Google&quot;&gt;Google&lt;/a&gt; than from
+&lt;a href=&quot;http://search.yahoo.com/&quot; title=&quot;Yahoo Search&quot;&gt;Yahoo&lt;/a&gt;
+or &lt;a href=&quot;http://search.msn.com/&quot; title=&quot;MSN Search&quot;&gt;MSN&lt;/a&gt;.&lt;/p&gt;
+</code></pre>
+
+<p>For comparison, here is the same paragraph written using
+Markdown&#8217;s inline link style:</p>
+
+<pre><code>I get 10 times more traffic from [Google](http://google.com/ &quot;Google&quot;)
+than from [Yahoo](http://search.yahoo.com/ &quot;Yahoo Search&quot;) or
+[MSN](http://search.msn.com/ &quot;MSN Search&quot;).
+</code></pre>
+
+<p>The point of reference-style links is not that they&#8217;re easier to
+write. The point is that with reference-style links, your document
+source is vastly more readable. Compare the above examples: using
+reference-style links, the paragraph itself is only 81 characters
+long; with inline-style links, it&#8217;s 176 characters; and as raw HTML,
+it&#8217;s 234 characters. In the raw HTML, there&#8217;s more markup than there
+is text.</p>
+
+<p>With Markdown&#8217;s reference-style links, a source document much more
+closely resembles the final output, as rendered in a browser. By
+allowing you to move the markup-related metadata out of the paragraph,
+you can add links without interrupting the narrative flow of your
+prose.</p>
+
+<h3 id="em">Emphasis</h3>
+
+<p>Markdown treats asterisks (<code>*</code>) and underscores (<code>_</code>) as indicators of
+emphasis. Text wrapped with one <code>*</code> or <code>_</code> will be wrapped with an
+HTML <code>&lt;em&gt;</code> tag; double <code>*</code>&#8217;s or <code>_</code>&#8217;s will be wrapped with an HTML
+<code>&lt;strong&gt;</code> tag. E.g., this input:</p>
+
+<pre><code>*single asterisks*
+
+_single underscores_
+
+**double asterisks**
+
+__double underscores__
+</code></pre>
+
+<p>will produce:</p>
+
+<pre><code>&lt;em&gt;single asterisks&lt;/em&gt;
+
+&lt;em&gt;single underscores&lt;/em&gt;
+
+&lt;strong&gt;double asterisks&lt;/strong&gt;
+
+&lt;strong&gt;double underscores&lt;/strong&gt;
+</code></pre>
+
+<p>You can use whichever style you prefer; the lone restriction is that
+the same character must be used to open and close an emphasis span.</p>
+
+<p>Emphasis can be used in the middle of a word:</p>
+
+<pre><code>un*frigging*believable
+</code></pre>
+
+<p>But if you surround an <code>*</code> or <code>_</code> with spaces, it&#8217;ll be treated as a
+literal asterisk or underscore.</p>
+
+<p>To produce a literal asterisk or underscore at a position where it
+would otherwise be used as an emphasis delimiter, you can backslash
+escape it:</p>
+
+<pre><code>\*this text is surrounded by literal asterisks\*
+</code></pre>
+
+<h3 id="code">Code</h3>
+
+<p>To indicate a span of code, wrap it with backtick quotes (<code>`</code>).
+Unlike a pre-formatted code block, a code span indicates code within a
+normal paragraph. For example:</p>
+
+<pre><code>Use the `printf()` function.
+</code></pre>
+
+<p>will produce:</p>
+
+<pre><code>&lt;p&gt;Use the &lt;code&gt;printf()&lt;/code&gt; function.&lt;/p&gt;
+</code></pre>
+
+<p>To include a literal backtick character within a code span, you can use
+multiple backticks as the opening and closing delimiters:</p>
+
+<pre><code>``There is a literal backtick (`) here.``
+</code></pre>
+
+<p>which will produce this:</p>
+
+<pre><code>&lt;p&gt;&lt;code&gt;There is a literal backtick (`) here.&lt;/code&gt;&lt;/p&gt;
+</code></pre>
+
+<p>The backtick delimiters surrounding a code span may include spaces &#8211;
+one after the opening, one before the closing. This allows you to place
+literal backtick characters at the beginning or end of a code span:</p>
+
+<pre><code>A single backtick in a code span: `` ` ``
+
+A backtick-delimited string in a code span: `` `foo` ``
+</code></pre>
+
+<p>will produce:</p>
+
+<pre><code>&lt;p&gt;A single backtick in a code span: &lt;code&gt;`&lt;/code&gt;&lt;/p&gt;
+
+&lt;p&gt;A backtick-delimited string in a code span: &lt;code&gt;`foo`&lt;/code&gt;&lt;/p&gt;
+</code></pre>
+
+<p>With a code span, ampersands and angle brackets are encoded as HTML
+entities automatically, which makes it easy to include example HTML
+tags. Markdown will turn this:</p>
+
+<pre><code>Please don't use any `&lt;blink&gt;` tags.
+</code></pre>
+
+<p>into:</p>
+
+<pre><code>&lt;p&gt;Please don't use any &lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
+</code></pre>
+
+<p>You can write this:</p>
+
+<pre><code>`&amp;#8212;` is the decimal-encoded equivalent of `&amp;mdash;`.
+</code></pre>
+
+<p>to produce:</p>
+
+<pre><code>&lt;p&gt;&lt;code&gt;&amp;amp;#8212;&lt;/code&gt; is the decimal-encoded
+equivalent of &lt;code&gt;&amp;amp;mdash;&lt;/code&gt;.&lt;/p&gt;
+</code></pre>
+
+<h3 id="img">Images</h3>
+
+<p>Admittedly, it&#8217;s fairly difficult to devise a &#8220;natural&#8221; syntax for
+placing images into a plain text document format.</p>
+
+<p>Markdown uses an image syntax that is intended to resemble the syntax
+for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p>
+
+<p>Inline image syntax looks like this:</p>
+
+<pre><code>![Alt text](/path/to/img.jpg)
+
+![Alt text](/path/to/img.jpg &quot;Optional title&quot;)
+</code></pre>
+
+<p>That is:</p>
+
+<ul>
+<li>An exclamation mark: <code>!</code>;</li>
+<li>followed by a set of square brackets, containing the <code>alt</code>
+attribute text for the image;</li>
+<li>followed by a set of parentheses, containing the URL or path to
+the image, and an optional <code>title</code> attribute enclosed in double
+or single quotes.</li>
+</ul>
+
+<p>Reference-style image syntax looks like this:</p>
+
+<pre><code>![Alt text][id]
+</code></pre>
+
+<p>Where &#8220;id&#8221; is the name of a defined image reference. Image references
+are defined using syntax identical to link references:</p>
+
+<pre><code>[id]: url/to/image  &quot;Optional title attribute&quot;
+</code></pre>
+
+<p>As of this writing, Markdown has no syntax for specifying the
+dimensions of an image; if this is important to you, you can simply
+use regular HTML <code>&lt;img&gt;</code> tags.</p>
+
+<hr />
+
+<h2 id="misc">Miscellaneous</h2>
+
+<h3 id="autolink">Automatic Links</h3>
+
+<p>Markdown supports a shortcut style for creating &#8220;automatic&#8221; links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:</p>
+
+<pre><code>&lt;http://example.com/&gt;
+</code></pre>
+
+<p>Markdown will turn this into:</p>
+
+<pre><code>&lt;a href=&quot;http://example.com/&quot;&gt;http://example.com/&lt;/a&gt;
+</code></pre>
+
+<p>Automatic links for email addresses work similarly, except that
+Markdown will also perform a bit of randomized decimal and hex
+entity-encoding to help obscure your address from address-harvesting
+spambots. For example, Markdown will turn this:</p>
+
+<pre><code>&lt;address@example.com&gt;
+</code></pre>
+
+<p>into something like this:</p>
+
+<pre><code>&lt;a href=&quot;&amp;#x6D;&amp;#x61;i&amp;#x6C;&amp;#x74;&amp;#x6F;:&amp;#x61;&amp;#x64;&amp;#x64;&amp;#x72;&amp;#x65;
+&amp;#115;&amp;#115;&amp;#64;&amp;#101;&amp;#120;&amp;#x61;&amp;#109;&amp;#x70;&amp;#x6C;e&amp;#x2E;&amp;#99;&amp;#111;
+&amp;#109;&quot;&gt;&amp;#x61;&amp;#x64;&amp;#x64;&amp;#x72;&amp;#x65;&amp;#115;&amp;#115;&amp;#64;&amp;#101;&amp;#120;&amp;#x61;
+&amp;#109;&amp;#x70;&amp;#x6C;e&amp;#x2E;&amp;#99;&amp;#111;&amp;#109;&lt;/a&gt;
+</code></pre>
+
+<p>which will render in a browser as a clickable link to &#8220;address@example.com&#8221;.</p>
+
+<p>(This sort of entity-encoding trick will indeed fool many, if not
+most, address-harvesting bots, but it definitely won&#8217;t fool all of
+them. It&#8217;s better than nothing, but an address published in this way
+will probably eventually start receiving spam.)</p>
+
+<h3 id="backslash">Backslash Escapes</h3>
+
+<p>Markdown allows you to use backslash escapes to generate literal
+characters which would otherwise have special meaning in Markdown&#8217;s
+formatting syntax. For example, if you wanted to surround a word
+with literal asterisks (instead of an HTML <code>&lt;em&gt;</code> tag), you can use
+backslashes before the asterisks, like this:</p>
+
+<pre><code>\*literal asterisks\*
+</code></pre>
+
+<p>Markdown provides backslash escapes for the following characters:</p>
+
+<pre><code>\   backslash
+`   backtick
+*   asterisk
+_   underscore
+{}  curly braces
+[]  square brackets
+()  parentheses
+#   hash mark
++   plus sign
+-   minus sign (hyphen)
+.   dot
+!   exclamation mark
+</code></pre>
diff --git a/tests/MMD6Tests/Markdown Syntax.htmlc b/tests/MMD6Tests/Markdown Syntax.htmlc
new file mode 100644 (file)
index 0000000..be89b34
--- /dev/null
@@ -0,0 +1,956 @@
+<h1>Markdown: Syntax </h1>
+
+<ul id="ProjectSubmenu">
+    <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
+    <li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
+    <li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
+    <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
+    <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
+</ul>
+
+<ul>
+<li><a href="#overview">Overview</a>
+
+<ul>
+<li><a href="#philosophy">Philosophy</a></li>
+<li><a href="#html">Inline HTML</a></li>
+<li><a href="#autoescape">Automatic Escaping for Special Characters</a></li>
+</ul></li>
+<li><a href="#block">Block Elements</a>
+
+<ul>
+<li><a href="#p">Paragraphs and Line Breaks</a></li>
+<li><a href="#header">Headers</a></li>
+<li><a href="#blockquote">Blockquotes</a></li>
+<li><a href="#list">Lists</a></li>
+<li><a href="#precode">Code Blocks</a></li>
+<li><a href="#hr">Horizontal Rules</a></li>
+</ul></li>
+<li><a href="#span">Span Elements</a>
+
+<ul>
+<li><a href="#link">Links</a></li>
+<li><a href="#em">Emphasis</a></li>
+<li><a href="#code">Code</a></li>
+<li><a href="#img">Images</a></li>
+</ul></li>
+<li><a href="#misc">Miscellaneous</a>
+
+<ul>
+<li><a href="#backslash">Backslash Escapes</a></li>
+<li><a href="#autolink">Automatic Links</a></li>
+</ul></li>
+</ul>
+
+<p><strong>Note:</strong> This document is itself written using Markdown; you
+can <a href="/projects/markdown/syntax.text">see the source for it by adding '.text' to the URL</a>.</p>
+
+<hr />
+
+<h2 id="overview">Overview</h2>
+
+<h3 id="philosophy">Philosophy</h3>
+
+<p>Markdown is intended to be as easy-to-read and easy-to-write as is feasible.</p>
+
+<p>Readability, however, is emphasized above all else. A Markdown-formatted
+document should be publishable as-is, as plain text, without looking
+like it's been marked up with tags or formatting instructions. While
+Markdown's syntax has been influenced by several existing text-to-HTML
+filters -- including <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a>, <a href="http://www.aaronsw.com/2002/atx/">atx</a>, <a href="http://textism.com/tools/textile/">Textile</a>, <a href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>,
+<a href="http://www.triptico.com/software/grutatxt.html">Grutatext</a>, and <a href="http://ettext.taint.org/doc/">EtText</a> -- the single biggest source of
+inspiration for Markdown's syntax is the format of plain text email.</p>
+
+<p>To this end, Markdown's syntax is comprised entirely of punctuation
+characters, which punctuation characters have been carefully chosen so
+as to look like what they mean. E.g., asterisks around a word actually
+look like *emphasis*. Markdown lists look like, well, lists. Even
+blockquotes look like quoted passages of text, assuming you've ever
+used email.</p>
+
+<h3 id="html">Inline HTML</h3>
+
+<p>Markdown's syntax is intended for one purpose: to be used as a
+format for <em>writing</em> for the web.</p>
+
+<p>Markdown is not a replacement for HTML, or even close to it. Its
+syntax is very small, corresponding only to a very small subset of
+HTML tags. The idea is <em>not</em> to create a syntax that makes it easier
+to insert HTML tags. In my opinion, HTML tags are already easy to
+insert. The idea for Markdown is to make it easy to read, write, and
+edit prose. HTML is a <em>publishing</em> format; Markdown is a <em>writing</em>
+format. Thus, Markdown's formatting syntax only addresses issues that
+can be conveyed in plain text.</p>
+
+<p>For any markup that is not covered by Markdown's syntax, you simply
+use HTML itself. There's no need to preface it or delimit it to
+indicate that you're switching from Markdown to HTML; you just use
+the tags.</p>
+
+<p>The only restrictions are that block-level HTML elements -- e.g. <code>&lt;div&gt;</code>,
+<code>&lt;table&gt;</code>, <code>&lt;pre&gt;</code>, <code>&lt;p&gt;</code>, etc. -- must be separated from surrounding
+content by blank lines, and the start and end tags of the block should
+not be indented with tabs or spaces. Markdown is smart enough not
+to add extra (unwanted) <code>&lt;p&gt;</code> tags around HTML block-level tags.</p>
+
+<p>For example, to add an HTML table to a Markdown article:</p>
+
+<pre><code>This is a regular paragraph.
+
+&lt;table&gt;
+    &lt;tr&gt;
+        &lt;td&gt;Foo&lt;/td&gt;
+    &lt;/tr&gt;
+&lt;/table&gt;
+
+This is another regular paragraph.
+</code></pre>
+
+<p>Note that Markdown formatting syntax is not processed within block-level
+HTML tags. E.g., you can't use Markdown-style <code>*emphasis*</code> inside an
+HTML block.</p>
+
+<p>Span-level HTML tags -- e.g. <code>&lt;span&gt;</code>, <code>&lt;cite&gt;</code>, or <code>&lt;del&gt;</code> -- can be
+used anywhere in a Markdown paragraph, list item, or header. If you
+want, you can even use HTML tags instead of Markdown formatting; e.g. if
+you'd prefer to use HTML <code>&lt;a&gt;</code> or <code>&lt;img&gt;</code> tags instead of Markdown's
+link or image syntax, go right ahead.</p>
+
+<p>Unlike block-level HTML tags, Markdown syntax <em>is</em> processed within
+span-level tags.</p>
+
+<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
+
+<p>In HTML, there are two characters that demand special treatment: <code>&lt;</code>
+and <code>&amp;</code>. Left angle brackets are used to start tags; ampersands are
+used to denote HTML entities. If you want to use them as literal
+characters, you must escape them as entities, e.g. <code>&amp;lt;</code>, and
+<code>&amp;amp;</code>.</p>
+
+<p>Ampersands in particular are bedeviling for web writers. If you want to
+write about 'AT&amp;T', you need to write '<code>AT&amp;amp;T</code>'. You even need to
+escape ampersands within URLs. Thus, if you want to link to:</p>
+
+<pre><code>http://images.google.com/images?num=30&amp;q=larry+bird
+</code></pre>
+
+<p>you need to encode the URL as:</p>
+
+<pre><code>http://images.google.com/images?num=30&amp;amp;q=larry+bird
+</code></pre>
+
+<p>in your anchor tag <code>href</code> attribute. Needless to say, this is easy to
+forget, and is probably the single most common source of HTML validation
+errors in otherwise well-marked-up web sites.</p>
+
+<p>Markdown allows you to use these characters naturally, taking care of
+all the necessary escaping for you. If you use an ampersand as part of
+an HTML entity, it remains unchanged; otherwise it will be translated
+into <code>&amp;amp;</code>.</p>
+
+<p>So, if you want to include a copyright symbol in your article, you can write:</p>
+
+<pre><code>&amp;copy;
+</code></pre>
+
+<p>and Markdown will leave it alone. But if you write:</p>
+
+<pre><code>AT&amp;T
+</code></pre>
+
+<p>Markdown will translate it to:</p>
+
+<pre><code>AT&amp;amp;T
+</code></pre>
+
+<p>Similarly, because Markdown supports <a href="#html">inline HTML</a>, if you use
+angle brackets as delimiters for HTML tags, Markdown will treat them as
+such. But if you write:</p>
+
+<pre><code>4 &lt; 5
+</code></pre>
+
+<p>Markdown will translate it to:</p>
+
+<pre><code>4 &amp;lt; 5
+</code></pre>
+
+<p>However, inside Markdown code spans and blocks, angle brackets and
+ampersands are <em>always</em> encoded automatically. This makes it easy to use
+Markdown to write about HTML code. (As opposed to raw HTML, which is a
+terrible format for writing about HTML syntax, because every single <code>&lt;</code>
+and <code>&amp;</code> in your example code needs to be escaped.)</p>
+
+<hr />
+
+<h2 id="block">Block Elements</h2>
+
+<h3 id="p">Paragraphs and Line Breaks</h3>
+
+<p>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 but spaces or tabs is considered
+blank.) Normal paragraphs should not be indented with spaces or tabs.</p>
+
+<p>The implication of the &quot;one or more consecutive lines of text&quot; rule is
+that Markdown supports &quot;hard-wrapped&quot; text paragraphs. This differs
+significantly from most other text-to-HTML formatters (including Movable
+Type's &quot;Convert Line Breaks&quot; option) which translate every line break
+character in a paragraph into a <code>&lt;br /&gt;</code> tag.</p>
+
+<p>When you <em>do</em> want to insert a <code>&lt;br /&gt;</code> break tag using Markdown, you
+end a line with two or more spaces, then type return.</p>
+
+<p>Yes, this takes a tad more effort to create a <code>&lt;br /&gt;</code>, but a simplistic
+&quot;every line break is a <code>&lt;br /&gt;</code>&quot; rule wouldn't work for Markdown.
+Markdown's email-style <a href="#blockquote">blockquoting</a> and multi-paragraph <a href="#list">list items</a>
+work best -- and look better -- when you format them with hard breaks.</p>
+
+<h3 id="header">Headers</h3>
+
+<p>Markdown supports two styles of headers, <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a> and <a href="http://www.aaronsw.com/2002/atx/">atx</a>.</p>
+
+<p>Setext-style headers are &quot;underlined&quot; using equal signs (for first-level
+headers) and dashes (for second-level headers). For example:</p>
+
+<pre><code>This is an H1
+=============
+
+This is an H2
+-------------
+</code></pre>
+
+<p>Any number of underlining <code>=</code>'s or <code>-</code>'s will work.</p>
+
+<p>Atx-style headers use 1-6 hash characters at the start of the line,
+corresponding to header levels 1-6. For example:</p>
+
+<pre><code># This is an H1
+
+## This is an H2
+
+###### This is an H6
+</code></pre>
+
+<p>Optionally, you may &quot;close&quot; atx-style headers. This is purely
+cosmetic -- you can use this if you think it looks better. The
+closing hashes don't even need to match the number of hashes
+used to open the header. (The number of opening hashes
+determines the header level.) :</p>
+
+<pre><code># This is an H1 #
+
+## This is an H2 ##
+
+### This is an H3 ######
+</code></pre>
+
+<h3 id="blockquote">Blockquotes</h3>
+
+<p>Markdown uses email-style <code>&gt;</code> characters for blockquoting. If you're
+familiar with quoting passages of text in an email message, then you
+know how to create a blockquote in Markdown. It looks best if you hard
+wrap the text and put a <code>&gt;</code> before every line:</p>
+
+<pre><code>&gt; This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+&gt; consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+&gt; Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+&gt; 
+&gt; Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+&gt; id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>Markdown allows you to be lazy and only put the <code>&gt;</code> before the first
+line of a hard-wrapped paragraph:</p>
+
+<pre><code>&gt; This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+
+&gt; Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
+adding additional levels of <code>&gt;</code>:</p>
+
+<pre><code>&gt; This is the first level of quoting.
+&gt;
+&gt; &gt; This is nested blockquote.
+&gt;
+&gt; Back to the first level.
+</code></pre>
+
+<p>Blockquotes can contain other Markdown elements, including headers, lists,
+and code blocks:</p>
+
+<pre><code>&gt; ## This is a header.
+&gt; 
+&gt; 1.   This is the first list item.
+&gt; 2.   This is the second list item.
+&gt; 
+&gt; Here's some example code:
+&gt; 
+&gt;     return shell_exec(&quot;echo $input | $markdown_script&quot;);
+</code></pre>
+
+<p>Any decent text editor should make email-style quoting easy. For
+example, with BBEdit, you can make a selection and choose Increase
+Quote Level from the Text menu.</p>
+
+<h3 id="list">Lists</h3>
+
+<p>Markdown supports ordered (numbered) and unordered (bulleted) lists.</p>
+
+<p>Unordered lists use asterisks, pluses, and hyphens -- interchangably
+-- as list markers:</p>
+
+<pre><code>*   Red
+*   Green
+*   Blue
+</code></pre>
+
+<p>is equivalent to:</p>
+
+<pre><code>+   Red
++   Green
++   Blue
+</code></pre>
+
+<p>and:</p>
+
+<pre><code>-   Red
+-   Green
+-   Blue
+</code></pre>
+
+<p>Ordered lists use numbers followed by periods:</p>
+
+<pre><code>1.  Bird
+2.  McHale
+3.  Parish
+</code></pre>
+
+<p>It's important to note that the actual numbers you use to mark the
+list have no effect on the HTML output Markdown produces. The HTML
+Markdown produces from the above list is:</p>
+
+<pre><code>&lt;ol&gt;
+&lt;li&gt;Bird&lt;/li&gt;
+&lt;li&gt;McHale&lt;/li&gt;
+&lt;li&gt;Parish&lt;/li&gt;
+&lt;/ol&gt;
+</code></pre>
+
+<p>If you instead wrote the list in Markdown like this:</p>
+
+<pre><code>1.  Bird
+1.  McHale
+1.  Parish
+</code></pre>
+
+<p>or even:</p>
+
+<pre><code>3. Bird
+1. McHale
+8. Parish
+</code></pre>
+
+<p>you'd get the exact same HTML output. The point is, if you want to,
+you can use ordinal numbers in your ordered Markdown lists, so that
+the numbers in your source match the numbers in your published HTML.
+But if you want to be lazy, you don't have to.</p>
+
+<p>If you do use lazy list numbering, however, you should still start the
+list with the number 1. At some point in the future, Markdown may support
+starting ordered lists at an arbitrary number.</p>
+
+<p>List markers typically start at the left margin, but may be indented by
+up to three spaces. List markers must be followed by one or more spaces
+or a tab.</p>
+
+<p>To make lists look nice, you can wrap items with hanging indents:</p>
+
+<pre><code>*   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+    Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+    viverra nec, fringilla in, laoreet vitae, risus.
+*   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+    Suspendisse id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>But if you want to be lazy, you don't have to:</p>
+
+<pre><code>*   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+viverra nec, fringilla in, laoreet vitae, risus.
+*   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+Suspendisse id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>If list items are separated by blank lines, Markdown will wrap the
+items in <code>&lt;p&gt;</code> tags in the HTML output. For example, this input:</p>
+
+<pre><code>*   Bird
+*   Magic
+</code></pre>
+
+<p>will turn into:</p>
+
+<pre><code>&lt;ul&gt;
+&lt;li&gt;Bird&lt;/li&gt;
+&lt;li&gt;Magic&lt;/li&gt;
+&lt;/ul&gt;
+</code></pre>
+
+<p>But this:</p>
+
+<pre><code>*   Bird
+
+*   Magic
+</code></pre>
+
+<p>will turn into:</p>
+
+<pre><code>&lt;ul&gt;
+&lt;li&gt;&lt;p&gt;Bird&lt;/p&gt;&lt;/li&gt;
+&lt;li&gt;&lt;p&gt;Magic&lt;/p&gt;&lt;/li&gt;
+&lt;/ul&gt;
+</code></pre>
+
+<p>List items may consist of multiple paragraphs. Each subsequent
+paragraph in a list item must be indented by either 4 spaces
+or one tab:</p>
+
+<pre><code>1.  This is a list item with two paragraphs. Lorem ipsum dolor
+    sit amet, consectetuer adipiscing elit. Aliquam hendrerit
+    mi posuere lectus.
+
+    Vestibulum enim wisi, viverra nec, fringilla in, laoreet
+    vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
+    sit amet velit.
+
+2.  Suspendisse id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>It looks nice if you indent every line of the subsequent
+paragraphs, but here again, Markdown will allow you to be
+lazy:</p>
+
+<pre><code>*   This is a list item with two paragraphs.
+
+    This is the second paragraph in the list item. You're
+only required to indent the first line. Lorem ipsum dolor
+sit amet, consectetuer adipiscing elit.
+
+*   Another item in the same list.
+</code></pre>
+
+<p>To put a blockquote within a list item, the blockquote's <code>&gt;</code>
+delimiters need to be indented:</p>
+
+<pre><code>*   A list item with a blockquote:
+
+    &gt; This is a blockquote
+    &gt; inside a list item.
+</code></pre>
+
+<p>To put a code block within a list item, the code block needs
+to be indented <em>twice</em> -- 8 spaces or two tabs:</p>
+
+<pre><code>*   A list item with a code block:
+
+        &lt;code goes here&gt;
+</code></pre>
+
+<p>It's worth noting that it's possible to trigger an ordered list by
+accident, by writing something like this:</p>
+
+<pre><code>1986. What a great season.
+</code></pre>
+
+<p>In other words, a <em>number-period-space</em> sequence at the beginning of a
+line. To avoid this, you can backslash-escape the period:</p>
+
+<pre><code>1986\. What a great season.
+</code></pre>
+
+<h3 id="precode">Code Blocks</h3>
+
+<p>Pre-formatted code blocks are used for writing about programming or
+markup source code. Rather than forming normal paragraphs, the lines
+of a code block are interpreted literally. Markdown wraps a code block
+in both <code>&lt;pre&gt;</code> and <code>&lt;code&gt;</code> tags.</p>
+
+<p>To produce a code block in Markdown, simply indent every line of the
+block by at least 4 spaces or 1 tab. For example, given this input:</p>
+
+<pre><code>This is a normal paragraph:
+
+    This is a code block.
+</code></pre>
+
+<p>Markdown will generate:</p>
+
+<pre><code>&lt;p&gt;This is a normal paragraph:&lt;/p&gt;
+
+&lt;pre&gt;&lt;code&gt;This is a code block.
+&lt;/code&gt;&lt;/pre&gt;
+</code></pre>
+
+<p>One level of indentation -- 4 spaces or 1 tab -- is removed from each
+line of the code block. For example, this:</p>
+
+<pre><code>Here is an example of AppleScript:
+
+    tell application &quot;Foo&quot;
+        beep
+    end tell
+</code></pre>
+
+<p>will turn into:</p>
+
+<pre><code>&lt;p&gt;Here is an example of AppleScript:&lt;/p&gt;
+
+&lt;pre&gt;&lt;code&gt;tell application &quot;Foo&quot;
+    beep
+end tell
+&lt;/code&gt;&lt;/pre&gt;
+</code></pre>
+
+<p>A code block continues until it reaches a line that is not indented
+(or the end of the article).</p>
+
+<p>Within a code block, ampersands (<code>&amp;</code>) and angle brackets (<code>&lt;</code> and <code>&gt;</code>)
+are automatically converted into HTML entities. This makes it very
+easy to include example HTML source code using Markdown -- just paste
+it and indent it, and Markdown will handle the hassle of encoding the
+ampersands and angle brackets. For example, this:</p>
+
+<pre><code>    &lt;div class=&quot;footer&quot;&gt;
+        &amp;copy; 2004 Foo Corporation
+    &lt;/div&gt;
+</code></pre>
+
+<p>will turn into:</p>
+
+<pre><code>&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;footer&quot;&amp;gt;
+    &amp;amp;copy; 2004 Foo Corporation
+&amp;lt;/div&amp;gt;
+&lt;/code&gt;&lt;/pre&gt;
+</code></pre>
+
+<p>Regular Markdown syntax is not processed within code blocks. E.g.,
+asterisks are just literal asterisks within a code block. This means
+it's also easy to use Markdown to write about Markdown's own syntax.</p>
+
+<h3 id="hr">Horizontal Rules</h3>
+
+<p>You can produce a horizontal rule tag (<code>&lt;hr /&gt;</code>) by placing three or
+more hyphens, asterisks, or underscores on a line by themselves. If you
+wish, you may use spaces between the hyphens or asterisks. Each of the
+following lines will produce a horizontal rule:</p>
+
+<pre><code>* * *
+
+***
+
+*****
+
+- - -
+
+---------------------------------------
+</code></pre>
+
+<hr />
+
+<h2 id="span">Span Elements</h2>
+
+<h3 id="link">Links</h3>
+
+<p>Markdown supports two style of links: <em>inline</em> and <em>reference</em>.</p>
+
+<p>In both styles, the link text is delimited by [square brackets].</p>
+
+<p>To create an inline link, use a set of regular parentheses immediately
+after the link text's closing square bracket. Inside the parentheses,
+put the URL where you want the link to point, along with an <em>optional</em>
+title for the link, surrounded in quotes. For example:</p>
+
+<pre><code>This is [an example](http://example.com/ &quot;Title&quot;) inline link.
+
+[This link](http://example.net/) has no title attribute.
+</code></pre>
+
+<p>Will produce:</p>
+
+<pre><code>&lt;p&gt;This is &lt;a href=&quot;http://example.com/&quot; title=&quot;Title&quot;&gt;
+an example&lt;/a&gt; inline link.&lt;/p&gt;
+
+&lt;p&gt;&lt;a href=&quot;http://example.net/&quot;&gt;This link&lt;/a&gt; has no
+title attribute.&lt;/p&gt;
+</code></pre>
+
+<p>If you're referring to a local resource on the same server, you can
+use relative paths:</p>
+
+<pre><code>See my [About](/about/) page for details.   
+</code></pre>
+
+<p>Reference-style links use a second set of square brackets, inside
+which you place a label of your choosing to identify the link:</p>
+
+<pre><code>This is [an example][id] reference-style link.
+</code></pre>
+
+<p>You can optionally use a space to separate the sets of brackets:</p>
+
+<pre><code>This is [an example] [id] reference-style link.
+</code></pre>
+
+<p>Then, anywhere in the document, you define your link label like this,
+on a line by itself:</p>
+
+<pre><code>[id]: http://example.com/  &quot;Optional Title Here&quot;
+</code></pre>
+
+<p>That is:</p>
+
+<ul>
+<li>Square brackets containing the link identifier (optionally
+indented from the left margin using up to three spaces);</li>
+<li>followed by a colon;</li>
+<li>followed by one or more spaces (or tabs);</li>
+<li>followed by the URL for the link;</li>
+<li>optionally followed by a title attribute for the link, enclosed
+in double or single quotes, or enclosed in parentheses.</li>
+</ul>
+
+<p>The following three link definitions are equivalent:</p>
+
+<pre><code>[foo]: http://example.com/  &quot;Optional Title Here&quot;
+[foo]: http://example.com/  'Optional Title Here'
+[foo]: http://example.com/  (Optional Title Here)
+</code></pre>
+
+<p><strong>Note:</strong> There is a known bug in Markdown.pl 1.0.1 which prevents
+single quotes from being used to delimit link titles.</p>
+
+<p>The link URL may, optionally, be surrounded by angle brackets:</p>
+
+<pre><code>[id]: &lt;http://example.com/&gt;  &quot;Optional Title Here&quot;
+</code></pre>
+
+<p>You can put the title attribute on the next line and use extra spaces
+or tabs for padding, which tends to look better with longer URLs:</p>
+
+<pre><code>[id]: http://example.com/longish/path/to/resource/here
+    &quot;Optional Title Here&quot;
+</code></pre>
+
+<p>Link definitions are only used for creating links during Markdown
+processing, and are stripped from your document in the HTML output.</p>
+
+<p>Link definition names may consist of letters, numbers, spaces, and
+punctuation -- but they are <em>not</em> case sensitive. E.g. these two
+links:</p>
+
+<pre><code>[link text][a]
+[link text][A]
+</code></pre>
+
+<p>are equivalent.</p>
+
+<p>The <em>implicit link name</em> shortcut allows you to omit the name of the
+link, in which case the link text itself is used as the name.
+Just use an empty set of square brackets -- e.g., to link the word
+&quot;Google&quot; to the google.com web site, you could simply write:</p>
+
+<pre><code>[Google][]
+</code></pre>
+
+<p>And then define the link:</p>
+
+<pre><code>[Google]: http://google.com/
+</code></pre>
+
+<p>Because link names may contain spaces, this shortcut even works for
+multiple words in the link text:</p>
+
+<pre><code>Visit [Daring Fireball][] for more information.
+</code></pre>
+
+<p>And then define the link:</p>
+
+<pre><code>[Daring Fireball]: http://daringfireball.net/
+</code></pre>
+
+<p>Link definitions can be placed anywhere in your Markdown document. I
+tend to put them immediately after each paragraph in which they're
+used, but if you want, you can put them all at the end of your
+document, sort of like footnotes.</p>
+
+<p>Here's an example of reference links in action:</p>
+
+<pre><code>I get 10 times more traffic from [Google] [1] than from
+[Yahoo] [2] or [MSN] [3].
+
+  [1]: http://google.com/        &quot;Google&quot;
+  [2]: http://search.yahoo.com/  &quot;Yahoo Search&quot;
+  [3]: http://search.msn.com/    &quot;MSN Search&quot;
+</code></pre>
+
+<p>Using the implicit link name shortcut, you could instead write:</p>
+
+<pre><code>I get 10 times more traffic from [Google][] than from
+[Yahoo][] or [MSN][].
+
+  [google]: http://google.com/        &quot;Google&quot;
+  [yahoo]:  http://search.yahoo.com/  &quot;Yahoo Search&quot;
+  [msn]:    http://search.msn.com/    &quot;MSN Search&quot;
+</code></pre>
+
+<p>Both of the above examples will produce the following HTML output:</p>
+
+<pre><code>&lt;p&gt;I get 10 times more traffic from &lt;a href=&quot;http://google.com/&quot;
+title=&quot;Google&quot;&gt;Google&lt;/a&gt; than from
+&lt;a href=&quot;http://search.yahoo.com/&quot; title=&quot;Yahoo Search&quot;&gt;Yahoo&lt;/a&gt;
+or &lt;a href=&quot;http://search.msn.com/&quot; title=&quot;MSN Search&quot;&gt;MSN&lt;/a&gt;.&lt;/p&gt;
+</code></pre>
+
+<p>For comparison, here is the same paragraph written using
+Markdown's inline link style:</p>
+
+<pre><code>I get 10 times more traffic from [Google](http://google.com/ &quot;Google&quot;)
+than from [Yahoo](http://search.yahoo.com/ &quot;Yahoo Search&quot;) or
+[MSN](http://search.msn.com/ &quot;MSN Search&quot;).
+</code></pre>
+
+<p>The point of reference-style links is not that they're easier to
+write. The point is that with reference-style links, your document
+source is vastly more readable. Compare the above examples: using
+reference-style links, the paragraph itself is only 81 characters
+long; with inline-style links, it's 176 characters; and as raw HTML,
+it's 234 characters. In the raw HTML, there's more markup than there
+is text.</p>
+
+<p>With Markdown's reference-style links, a source document much more
+closely resembles the final output, as rendered in a browser. By
+allowing you to move the markup-related metadata out of the paragraph,
+you can add links without interrupting the narrative flow of your
+prose.</p>
+
+<h3 id="em">Emphasis</h3>
+
+<p>Markdown treats asterisks (<code>*</code>) and underscores (<code>_</code>) as indicators of
+emphasis. Text wrapped with one <code>*</code> or <code>_</code> will be wrapped with an
+HTML <code>&lt;em&gt;</code> tag; double <code>*</code>'s or <code>_</code>'s will be wrapped with an HTML
+<code>&lt;strong&gt;</code> tag. E.g., this input:</p>
+
+<pre><code>*single asterisks*
+
+_single underscores_
+
+**double asterisks**
+
+__double underscores__
+</code></pre>
+
+<p>will produce:</p>
+
+<pre><code>&lt;em&gt;single asterisks&lt;/em&gt;
+
+&lt;em&gt;single underscores&lt;/em&gt;
+
+&lt;strong&gt;double asterisks&lt;/strong&gt;
+
+&lt;strong&gt;double underscores&lt;/strong&gt;
+</code></pre>
+
+<p>You can use whichever style you prefer; the lone restriction is that
+the same character must be used to open and close an emphasis span.</p>
+
+<p>Emphasis can be used in the middle of a word:</p>
+
+<pre><code>un*frigging*believable
+</code></pre>
+
+<p>But if you surround an <code>*</code> or <code>_</code> with spaces, it'll be treated as a
+literal asterisk or underscore.</p>
+
+<p>To produce a literal asterisk or underscore at a position where it
+would otherwise be used as an emphasis delimiter, you can backslash
+escape it:</p>
+
+<pre><code>\*this text is surrounded by literal asterisks\*
+</code></pre>
+
+<h3 id="code">Code</h3>
+
+<p>To indicate a span of code, wrap it with backtick quotes (<code>`</code>).
+Unlike a pre-formatted code block, a code span indicates code within a
+normal paragraph. For example:</p>
+
+<pre><code>Use the `printf()` function.
+</code></pre>
+
+<p>will produce:</p>
+
+<pre><code>&lt;p&gt;Use the &lt;code&gt;printf()&lt;/code&gt; function.&lt;/p&gt;
+</code></pre>
+
+<p>To include a literal backtick character within a code span, you can use
+multiple backticks as the opening and closing delimiters:</p>
+
+<pre><code>``There is a literal backtick (`) here.``
+</code></pre>
+
+<p>which will produce this:</p>
+
+<pre><code>&lt;p&gt;&lt;code&gt;There is a literal backtick (`) here.&lt;/code&gt;&lt;/p&gt;
+</code></pre>
+
+<p>The backtick delimiters surrounding a code span may include spaces --
+one after the opening, one before the closing. This allows you to place
+literal backtick characters at the beginning or end of a code span:</p>
+
+<pre><code>A single backtick in a code span: `` ` ``
+
+A backtick-delimited string in a code span: `` `foo` ``
+</code></pre>
+
+<p>will produce:</p>
+
+<pre><code>&lt;p&gt;A single backtick in a code span: &lt;code&gt;`&lt;/code&gt;&lt;/p&gt;
+
+&lt;p&gt;A backtick-delimited string in a code span: &lt;code&gt;`foo`&lt;/code&gt;&lt;/p&gt;
+</code></pre>
+
+<p>With a code span, ampersands and angle brackets are encoded as HTML
+entities automatically, which makes it easy to include example HTML
+tags. Markdown will turn this:</p>
+
+<pre><code>Please don't use any `&lt;blink&gt;` tags.
+</code></pre>
+
+<p>into:</p>
+
+<pre><code>&lt;p&gt;Please don't use any &lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
+</code></pre>
+
+<p>You can write this:</p>
+
+<pre><code>`&amp;#8212;` is the decimal-encoded equivalent of `&amp;mdash;`.
+</code></pre>
+
+<p>to produce:</p>
+
+<pre><code>&lt;p&gt;&lt;code&gt;&amp;amp;#8212;&lt;/code&gt; is the decimal-encoded
+equivalent of &lt;code&gt;&amp;amp;mdash;&lt;/code&gt;.&lt;/p&gt;
+</code></pre>
+
+<h3 id="img">Images</h3>
+
+<p>Admittedly, it's fairly difficult to devise a &quot;natural&quot; syntax for
+placing images into a plain text document format.</p>
+
+<p>Markdown uses an image syntax that is intended to resemble the syntax
+for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p>
+
+<p>Inline image syntax looks like this:</p>
+
+<pre><code>![Alt text](/path/to/img.jpg)
+
+![Alt text](/path/to/img.jpg &quot;Optional title&quot;)
+</code></pre>
+
+<p>That is:</p>
+
+<ul>
+<li>An exclamation mark: <code>!</code>;</li>
+<li>followed by a set of square brackets, containing the <code>alt</code>
+attribute text for the image;</li>
+<li>followed by a set of parentheses, containing the URL or path to
+the image, and an optional <code>title</code> attribute enclosed in double
+or single quotes.</li>
+</ul>
+
+<p>Reference-style image syntax looks like this:</p>
+
+<pre><code>![Alt text][id]
+</code></pre>
+
+<p>Where &quot;id&quot; is the name of a defined image reference. Image references
+are defined using syntax identical to link references:</p>
+
+<pre><code>[id]: url/to/image  &quot;Optional title attribute&quot;
+</code></pre>
+
+<p>As of this writing, Markdown has no syntax for specifying the
+dimensions of an image; if this is important to you, you can simply
+use regular HTML <code>&lt;img&gt;</code> tags.</p>
+
+<hr />
+
+<h2 id="misc">Miscellaneous</h2>
+
+<h3 id="autolink">Automatic Links</h3>
+
+<p>Markdown supports a shortcut style for creating &quot;automatic&quot; links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:</p>
+
+<pre><code>&lt;http://example.com/&gt;
+</code></pre>
+
+<p>Markdown will turn this into:</p>
+
+<pre><code>&lt;a href=&quot;http://example.com/&quot;&gt;http://example.com/&lt;/a&gt;
+</code></pre>
+
+<p>Automatic links for email addresses work similarly, except that
+Markdown will also perform a bit of randomized decimal and hex
+entity-encoding to help obscure your address from address-harvesting
+spambots. For example, Markdown will turn this:</p>
+
+<pre><code>&lt;address@example.com&gt;
+</code></pre>
+
+<p>into something like this:</p>
+
+<pre><code>&lt;a href=&quot;&amp;#x6D;&amp;#x61;i&amp;#x6C;&amp;#x74;&amp;#x6F;:&amp;#x61;&amp;#x64;&amp;#x64;&amp;#x72;&amp;#x65;
+&amp;#115;&amp;#115;&amp;#64;&amp;#101;&amp;#120;&amp;#x61;&amp;#109;&amp;#x70;&amp;#x6C;e&amp;#x2E;&amp;#99;&amp;#111;
+&amp;#109;&quot;&gt;&amp;#x61;&amp;#x64;&amp;#x64;&amp;#x72;&amp;#x65;&amp;#115;&amp;#115;&amp;#64;&amp;#101;&amp;#120;&amp;#x61;
+&amp;#109;&amp;#x70;&amp;#x6C;e&amp;#x2E;&amp;#99;&amp;#111;&amp;#109;&lt;/a&gt;
+</code></pre>
+
+<p>which will render in a browser as a clickable link to &quot;address@example.com&quot;.</p>
+
+<p>(This sort of entity-encoding trick will indeed fool many, if not
+most, address-harvesting bots, but it definitely won't fool all of
+them. It's better than nothing, but an address published in this way
+will probably eventually start receiving spam.)</p>
+
+<h3 id="backslash">Backslash Escapes</h3>
+
+<p>Markdown allows you to use backslash escapes to generate literal
+characters which would otherwise have special meaning in Markdown's
+formatting syntax. For example, if you wanted to surround a word
+with literal asterisks (instead of an HTML <code>&lt;em&gt;</code> tag), you can use
+backslashes before the asterisks, like this:</p>
+
+<pre><code>\*literal asterisks\*
+</code></pre>
+
+<p>Markdown provides backslash escapes for the following characters:</p>
+
+<pre><code>\   backslash
+`   backtick
+*   asterisk
+_   underscore
+{}  curly braces
+[]  square brackets
+()  parentheses
+#   hash mark
++   plus sign
+-   minus sign (hyphen)
+.   dot
+!   exclamation mark
+</code></pre>
diff --git a/tests/MMD6Tests/Markdown Syntax.text b/tests/MMD6Tests/Markdown Syntax.text
new file mode 100644 (file)
index 0000000..487035a
--- /dev/null
@@ -0,0 +1,895 @@
+# Markdown: Syntax #
+
+<ul id="ProjectSubmenu">
+    <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
+    <li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
+    <li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
+    <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
+    <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
+</ul>
+
+
+*   [Overview](#overview)
+    *   [Philosophy](#philosophy)
+    *   [Inline HTML](#html)
+    *   [Automatic Escaping for Special Characters](#autoescape)
+*   [Block Elements](#block)
+    *   [Paragraphs and Line Breaks](#p)
+    *   [Headers](#header)
+    *   [Blockquotes](#blockquote)
+    *   [Lists](#list)
+    *   [Code Blocks](#precode)
+    *   [Horizontal Rules](#hr)
+*   [Span Elements](#span)
+    *   [Links](#link)
+    *   [Emphasis](#em)
+    *   [Code](#code)
+    *   [Images](#img)
+*   [Miscellaneous](#misc)
+    *   [Backslash Escapes](#backslash)
+    *   [Automatic Links](#autolink)
+
+
+**Note:** This document is itself written using Markdown; you
+can [see the source for it by adding '.text' to the URL][src].
+
+  [src]: /projects/markdown/syntax.text
+
+* * *
+
+<h2 id="overview">Overview</h2>
+
+<h3 id="philosophy">Philosophy</h3>
+
+Markdown is intended to be as easy-to-read and easy-to-write as is feasible.
+
+Readability, however, is emphasized above all else. A Markdown-formatted
+document should be publishable as-is, as plain text, without looking
+like it's been marked up with tags or formatting instructions. While
+Markdown's syntax has been influenced by several existing text-to-HTML
+filters -- including [Setext][1], [atx][2], [Textile][3], [reStructuredText][4],
+[Grutatext][5], and [EtText][6] -- the single biggest source of
+inspiration for Markdown's syntax is the format of plain text email.
+
+  [1]: http://docutils.sourceforge.net/mirror/setext.html
+  [2]: http://www.aaronsw.com/2002/atx/
+  [3]: http://textism.com/tools/textile/
+  [4]: http://docutils.sourceforge.net/rst.html
+  [5]: http://www.triptico.com/software/grutatxt.html
+  [6]: http://ettext.taint.org/doc/
+
+To this end, Markdown's syntax is comprised entirely of punctuation
+characters, which punctuation characters have been carefully chosen so
+as to look like what they mean. E.g., asterisks around a word actually
+look like \*emphasis\*. Markdown lists look like, well, lists. Even
+blockquotes look like quoted passages of text, assuming you've ever
+used email.
+
+
+
+<h3 id="html">Inline HTML</h3>
+
+Markdown's syntax is intended for one purpose: to be used as a
+format for *writing* for the web.
+
+Markdown is not a replacement for HTML, or even close to it. Its
+syntax is very small, corresponding only to a very small subset of
+HTML tags. The idea is *not* to create a syntax that makes it easier
+to insert HTML tags. In my opinion, HTML tags are already easy to
+insert. The idea for Markdown is to make it easy to read, write, and
+edit prose. HTML is a *publishing* format; Markdown is a *writing*
+format. Thus, Markdown's formatting syntax only addresses issues that
+can be conveyed in plain text.
+
+For any markup that is not covered by Markdown's syntax, you simply
+use HTML itself. There's no need to preface it or delimit it to
+indicate that you're switching from Markdown to HTML; you just use
+the tags.
+
+The only restrictions are that block-level HTML elements -- e.g. `<div>`,
+`<table>`, `<pre>`, `<p>`, etc. -- must be separated from surrounding
+content by blank lines, and the start and end tags of the block should
+not be indented with tabs or spaces. Markdown is smart enough not
+to add extra (unwanted) `<p>` tags around HTML block-level tags.
+
+For example, to add an HTML table to a Markdown article:
+
+    This is a regular paragraph.
+
+    <table>
+        <tr>
+            <td>Foo</td>
+        </tr>
+    </table>
+
+    This is another regular paragraph.
+
+Note that Markdown formatting syntax is not processed within block-level
+HTML tags. E.g., you can't use Markdown-style `*emphasis*` inside an
+HTML block.
+
+Span-level HTML tags -- e.g. `<span>`, `<cite>`, or `<del>` -- can be
+used anywhere in a Markdown paragraph, list item, or header. If you
+want, you can even use HTML tags instead of Markdown formatting; e.g. if
+you'd prefer to use HTML `<a>` or `<img>` tags instead of Markdown's
+link or image syntax, go right ahead.
+
+Unlike block-level HTML tags, Markdown syntax *is* processed within
+span-level tags.
+
+
+<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
+
+In HTML, there are two characters that demand special treatment: `<`
+and `&`. Left angle brackets are used to start tags; ampersands are
+used to denote HTML entities. If you want to use them as literal
+characters, you must escape them as entities, e.g. `&lt;`, and
+`&amp;`.
+
+Ampersands in particular are bedeviling for web writers. If you want to
+write about 'AT&T', you need to write '`AT&amp;T`'. You even need to
+escape ampersands within URLs. Thus, if you want to link to:
+
+    http://images.google.com/images?num=30&q=larry+bird
+
+you need to encode the URL as:
+
+    http://images.google.com/images?num=30&amp;q=larry+bird
+
+in your anchor tag `href` attribute. Needless to say, this is easy to
+forget, and is probably the single most common source of HTML validation
+errors in otherwise well-marked-up web sites.
+
+Markdown allows you to use these characters naturally, taking care of
+all the necessary escaping for you. If you use an ampersand as part of
+an HTML entity, it remains unchanged; otherwise it will be translated
+into `&amp;`.
+
+So, if you want to include a copyright symbol in your article, you can write:
+
+    &copy;
+
+and Markdown will leave it alone. But if you write:
+
+    AT&T
+
+Markdown will translate it to:
+
+    AT&amp;T
+
+Similarly, because Markdown supports [inline HTML](#html), if you use
+angle brackets as delimiters for HTML tags, Markdown will treat them as
+such. But if you write:
+
+    4 < 5
+
+Markdown will translate it to:
+
+    4 &lt; 5
+
+However, inside Markdown code spans and blocks, angle brackets and
+ampersands are *always* encoded automatically. This makes it easy to use
+Markdown to write about HTML code. (As opposed to raw HTML, which is a
+terrible format for writing about HTML syntax, because every single `<`
+and `&` in your example code needs to be escaped.)
+
+
+* * *
+
+
+<h2 id="block">Block Elements</h2>
+
+
+<h3 id="p">Paragraphs and Line Breaks</h3>
+
+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 but spaces or tabs is considered
+blank.) Normal paragraphs should not be indented with spaces or tabs.
+
+The implication of the "one or more consecutive lines of text" rule is
+that Markdown supports "hard-wrapped" text paragraphs. This differs
+significantly from most other text-to-HTML formatters (including Movable
+Type's "Convert Line Breaks" option) which translate every line break
+character in a paragraph into a `<br />` tag.
+
+When you *do* want to insert a `<br />` break tag using Markdown, you
+end a line with two or more spaces, then type return.
+
+Yes, this takes a tad more effort to create a `<br />`, but a simplistic
+"every line break is a `<br />`" rule wouldn't work for Markdown.
+Markdown's email-style [blockquoting][bq] and multi-paragraph [list items][l]
+work best -- and look better -- when you format them with hard breaks.
+
+  [bq]: #blockquote
+  [l]:  #list
+
+
+
+<h3 id="header">Headers</h3>
+
+Markdown supports two styles of headers, [Setext][1] and [atx][2].
+
+Setext-style headers are "underlined" using equal signs (for first-level
+headers) and dashes (for second-level headers). For example:
+
+    This is an H1
+    =============
+
+    This is an H2
+    -------------
+
+Any number of underlining `=`'s or `-`'s will work.
+
+Atx-style headers use 1-6 hash characters at the start of the line,
+corresponding to header levels 1-6. For example:
+
+    # This is an H1
+
+    ## This is an H2
+
+    ###### This is an H6
+
+Optionally, you may "close" atx-style headers. This is purely
+cosmetic -- you can use this if you think it looks better. The
+closing hashes don't even need to match the number of hashes
+used to open the header. (The number of opening hashes
+determines the header level.) :
+
+    # This is an H1 #
+
+    ## This is an H2 ##
+
+    ### This is an H3 ######
+
+
+<h3 id="blockquote">Blockquotes</h3>
+
+Markdown uses email-style `>` characters for blockquoting. If you're
+familiar with quoting passages of text in an email message, then you
+know how to create a blockquote in Markdown. It looks best if you hard
+wrap the text and put a `>` before every line:
+
+    > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+    > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+    > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+    > 
+    > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+    > id sem consectetuer libero luctus adipiscing.
+
+Markdown allows you to be lazy and only put the `>` before the first
+line of a hard-wrapped paragraph:
+
+    > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+    consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+    Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+
+    > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+    id sem consectetuer libero luctus adipiscing.
+
+Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
+adding additional levels of `>`:
+
+    > This is the first level of quoting.
+    >
+    > > This is nested blockquote.
+    >
+    > Back to the first level.
+
+Blockquotes can contain other Markdown elements, including headers, lists,
+and code blocks:
+
+       > ## This is a header.
+       > 
+       > 1.   This is the first list item.
+       > 2.   This is the second list item.
+       > 
+       > Here's some example code:
+       > 
+       >     return shell_exec("echo $input | $markdown_script");
+
+Any decent text editor should make email-style quoting easy. For
+example, with BBEdit, you can make a selection and choose Increase
+Quote Level from the Text menu.
+
+
+<h3 id="list">Lists</h3>
+
+Markdown supports ordered (numbered) and unordered (bulleted) lists.
+
+Unordered lists use asterisks, pluses, and hyphens -- interchangably
+-- as list markers:
+
+    *   Red
+    *   Green
+    *   Blue
+
+is equivalent to:
+
+    +   Red
+    +   Green
+    +   Blue
+
+and:
+
+    -   Red
+    -   Green
+    -   Blue
+
+Ordered lists use numbers followed by periods:
+
+    1.  Bird
+    2.  McHale
+    3.  Parish
+
+It's important to note that the actual numbers you use to mark the
+list have no effect on the HTML output Markdown produces. The HTML
+Markdown produces from the above list is:
+
+    <ol>
+    <li>Bird</li>
+    <li>McHale</li>
+    <li>Parish</li>
+    </ol>
+
+If you instead wrote the list in Markdown like this:
+
+    1.  Bird
+    1.  McHale
+    1.  Parish
+
+or even:
+
+    3. Bird
+    1. McHale
+    8. Parish
+
+you'd get the exact same HTML output. The point is, if you want to,
+you can use ordinal numbers in your ordered Markdown lists, so that
+the numbers in your source match the numbers in your published HTML.
+But if you want to be lazy, you don't have to.
+
+If you do use lazy list numbering, however, you should still start the
+list with the number 1. At some point in the future, Markdown may support
+starting ordered lists at an arbitrary number.
+
+List markers typically start at the left margin, but may be indented by
+up to three spaces. List markers must be followed by one or more spaces
+or a tab.
+
+To make lists look nice, you can wrap items with hanging indents:
+
+    *   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+        Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+        viverra nec, fringilla in, laoreet vitae, risus.
+    *   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+        Suspendisse id sem consectetuer libero luctus adipiscing.
+
+But if you want to be lazy, you don't have to:
+
+    *   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+    Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+    viverra nec, fringilla in, laoreet vitae, risus.
+    *   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+    Suspendisse id sem consectetuer libero luctus adipiscing.
+
+If list items are separated by blank lines, Markdown will wrap the
+items in `<p>` tags in the HTML output. For example, this input:
+
+    *   Bird
+    *   Magic
+
+will turn into:
+
+    <ul>
+    <li>Bird</li>
+    <li>Magic</li>
+    </ul>
+
+But this:
+
+    *   Bird
+
+    *   Magic
+
+will turn into:
+
+    <ul>
+    <li><p>Bird</p></li>
+    <li><p>Magic</p></li>
+    </ul>
+
+List items may consist of multiple paragraphs. Each subsequent
+paragraph in a list item must be indented by either 4 spaces
+or one tab:
+
+    1.  This is a list item with two paragraphs. Lorem ipsum dolor
+        sit amet, consectetuer adipiscing elit. Aliquam hendrerit
+        mi posuere lectus.
+
+        Vestibulum enim wisi, viverra nec, fringilla in, laoreet
+        vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
+        sit amet velit.
+
+    2.  Suspendisse id sem consectetuer libero luctus adipiscing.
+
+It looks nice if you indent every line of the subsequent
+paragraphs, but here again, Markdown will allow you to be
+lazy:
+
+    *   This is a list item with two paragraphs.
+
+        This is the second paragraph in the list item. You're
+    only required to indent the first line. Lorem ipsum dolor
+    sit amet, consectetuer adipiscing elit.
+
+    *   Another item in the same list.
+
+To put a blockquote within a list item, the blockquote's `>`
+delimiters need to be indented:
+
+    *   A list item with a blockquote:
+
+        > This is a blockquote
+        > inside a list item.
+
+To put a code block within a list item, the code block needs
+to be indented *twice* -- 8 spaces or two tabs:
+
+    *   A list item with a code block:
+
+            <code goes here>
+
+
+It's worth noting that it's possible to trigger an ordered list by
+accident, by writing something like this:
+
+    1986. What a great season.
+
+In other words, a *number-period-space* sequence at the beginning of a
+line. To avoid this, you can backslash-escape the period:
+
+    1986\. What a great season.
+
+
+
+<h3 id="precode">Code Blocks</h3>
+
+Pre-formatted code blocks are used for writing about programming or
+markup source code. Rather than forming normal paragraphs, the lines
+of a code block are interpreted literally. Markdown wraps a code block
+in both `<pre>` and `<code>` tags.
+
+To produce a code block in Markdown, simply indent every line of the
+block by at least 4 spaces or 1 tab. For example, given this input:
+
+    This is a normal paragraph:
+
+        This is a code block.
+
+Markdown will generate:
+
+    <p>This is a normal paragraph:</p>
+
+    <pre><code>This is a code block.
+    </code></pre>
+
+One level of indentation -- 4 spaces or 1 tab -- is removed from each
+line of the code block. For example, this:
+
+    Here is an example of AppleScript:
+
+        tell application "Foo"
+            beep
+        end tell
+
+will turn into:
+
+    <p>Here is an example of AppleScript:</p>
+
+    <pre><code>tell application "Foo"
+        beep
+    end tell
+    </code></pre>
+
+A code block continues until it reaches a line that is not indented
+(or the end of the article).
+
+Within a code block, ampersands (`&`) and angle brackets (`<` and `>`)
+are automatically converted into HTML entities. This makes it very
+easy to include example HTML source code using Markdown -- just paste
+it and indent it, and Markdown will handle the hassle of encoding the
+ampersands and angle brackets. For example, this:
+
+        <div class="footer">
+            &copy; 2004 Foo Corporation
+        </div>
+
+will turn into:
+
+    <pre><code>&lt;div class="footer"&gt;
+        &amp;copy; 2004 Foo Corporation
+    &lt;/div&gt;
+    </code></pre>
+
+Regular Markdown syntax is not processed within code blocks. E.g.,
+asterisks are just literal asterisks within a code block. This means
+it's also easy to use Markdown to write about Markdown's own syntax.
+
+
+
+<h3 id="hr">Horizontal Rules</h3>
+
+You can produce a horizontal rule tag (`<hr />`) by placing three or
+more hyphens, asterisks, or underscores on a line by themselves. If you
+wish, you may use spaces between the hyphens or asterisks. Each of the
+following lines will produce a horizontal rule:
+
+    * * *
+
+    ***
+
+    *****
+
+    - - -
+
+    ---------------------------------------
+
+
+* * *
+
+<h2 id="span">Span Elements</h2>
+
+<h3 id="link">Links</h3>
+
+Markdown supports two style of links: *inline* and *reference*.
+
+In both styles, the link text is delimited by [square brackets].
+
+To create an inline link, use a set of regular parentheses immediately
+after the link text's closing square bracket. Inside the parentheses,
+put the URL where you want the link to point, along with an *optional*
+title for the link, surrounded in quotes. For example:
+
+    This is [an example](http://example.com/ "Title") inline link.
+
+    [This link](http://example.net/) has no title attribute.
+
+Will produce:
+
+    <p>This is <a href="http://example.com/" title="Title">
+    an example</a> inline link.</p>
+
+    <p><a href="http://example.net/">This link</a> has no
+    title attribute.</p>
+
+If you're referring to a local resource on the same server, you can
+use relative paths:
+
+    See my [About](/about/) page for details.   
+
+Reference-style links use a second set of square brackets, inside
+which you place a label of your choosing to identify the link:
+
+    This is [an example][id] reference-style link.
+
+You can optionally use a space to separate the sets of brackets:
+
+    This is [an example] [id] reference-style link.
+
+Then, anywhere in the document, you define your link label like this,
+on a line by itself:
+
+    [id]: http://example.com/  "Optional Title Here"
+
+That is:
+
+*   Square brackets containing the link identifier (optionally
+    indented from the left margin using up to three spaces);
+*   followed by a colon;
+*   followed by one or more spaces (or tabs);
+*   followed by the URL for the link;
+*   optionally followed by a title attribute for the link, enclosed
+    in double or single quotes, or enclosed in parentheses.
+
+The following three link definitions are equivalent:
+
+       [foo]: http://example.com/  "Optional Title Here"
+       [foo]: http://example.com/  'Optional Title Here'
+       [foo]: http://example.com/  (Optional Title Here)
+
+**Note:** There is a known bug in Markdown.pl 1.0.1 which prevents
+single quotes from being used to delimit link titles.
+
+The link URL may, optionally, be surrounded by angle brackets:
+
+    [id]: <http://example.com/>  "Optional Title Here"
+
+You can put the title attribute on the next line and use extra spaces
+or tabs for padding, which tends to look better with longer URLs:
+
+    [id]: http://example.com/longish/path/to/resource/here
+        "Optional Title Here"
+
+Link definitions are only used for creating links during Markdown
+processing, and are stripped from your document in the HTML output.
+
+Link definition names may consist of letters, numbers, spaces, and
+punctuation -- but they are *not* case sensitive. E.g. these two
+links:
+
+       [link text][a]
+       [link text][A]
+
+are equivalent.
+
+The *implicit link name* shortcut allows you to omit the name of the
+link, in which case the link text itself is used as the name.
+Just use an empty set of square brackets -- e.g., to link the word
+"Google" to the google.com web site, you could simply write:
+
+       [Google][]
+
+And then define the link:
+
+       [Google]: http://google.com/
+
+Because link names may contain spaces, this shortcut even works for
+multiple words in the link text:
+
+       Visit [Daring Fireball][] for more information.
+
+And then define the link:
+       
+       [Daring Fireball]: http://daringfireball.net/
+
+Link definitions can be placed anywhere in your Markdown document. I
+tend to put them immediately after each paragraph in which they're
+used, but if you want, you can put them all at the end of your
+document, sort of like footnotes.
+
+Here's an example of reference links in action:
+
+    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"
+
+Using the implicit link name shortcut, you could instead write:
+
+    I get 10 times more traffic from [Google][] than from
+    [Yahoo][] or [MSN][].
+
+      [google]: http://google.com/        "Google"
+      [yahoo]:  http://search.yahoo.com/  "Yahoo Search"
+      [msn]:    http://search.msn.com/    "MSN Search"
+
+Both of the above examples will produce the following HTML output:
+
+    <p>I get 10 times more traffic from <a href="http://google.com/"
+    title="Google">Google</a> than from
+    <a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>
+    or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
+
+For comparison, here is the same paragraph written using
+Markdown's inline link style:
+
+    I get 10 times more traffic from [Google](http://google.com/ "Google")
+    than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
+    [MSN](http://search.msn.com/ "MSN Search").
+
+The point of reference-style links is not that they're easier to
+write. The point is that with reference-style links, your document
+source is vastly more readable. Compare the above examples: using
+reference-style links, the paragraph itself is only 81 characters
+long; with inline-style links, it's 176 characters; and as raw HTML,
+it's 234 characters. In the raw HTML, there's more markup than there
+is text.
+
+With Markdown's reference-style links, a source document much more
+closely resembles the final output, as rendered in a browser. By
+allowing you to move the markup-related metadata out of the paragraph,
+you can add links without interrupting the narrative flow of your
+prose.
+
+
+<h3 id="em">Emphasis</h3>
+
+Markdown treats asterisks (`*`) and underscores (`_`) as indicators of
+emphasis. Text wrapped with one `*` or `_` will be wrapped with an
+HTML `<em>` tag; double `*`'s or `_`'s will be wrapped with an HTML
+`<strong>` tag. E.g., this input:
+
+    *single asterisks*
+
+    _single underscores_
+
+    **double asterisks**
+
+    __double underscores__
+
+will produce:
+
+    <em>single asterisks</em>
+
+    <em>single underscores</em>
+
+    <strong>double asterisks</strong>
+
+    <strong>double underscores</strong>
+
+You can use whichever style you prefer; the lone restriction is that
+the same character must be used to open and close an emphasis span.
+
+Emphasis can be used in the middle of a word:
+
+    un*frigging*believable
+
+But if you surround an `*` or `_` with spaces, it'll be treated as a
+literal asterisk or underscore.
+
+To produce a literal asterisk or underscore at a position where it
+would otherwise be used as an emphasis delimiter, you can backslash
+escape it:
+
+    \*this text is surrounded by literal asterisks\*
+
+
+
+<h3 id="code">Code</h3>
+
+To indicate a span of code, wrap it with backtick quotes (`` ` ``).
+Unlike a pre-formatted code block, a code span indicates code within a
+normal paragraph. For example:
+
+    Use the `printf()` function.
+
+will produce:
+
+    <p>Use the <code>printf()</code> function.</p>
+
+To include a literal backtick character within a code span, you can use
+multiple backticks as the opening and closing delimiters:
+
+    ``There is a literal backtick (`) here.``
+
+which will produce this:
+
+    <p><code>There is a literal backtick (`) here.</code></p>
+
+The backtick delimiters surrounding a code span may include spaces --
+one after the opening, one before the closing. This allows you to place
+literal backtick characters at the beginning or end of a code span:
+
+       A single backtick in a code span: `` ` ``
+       
+       A backtick-delimited string in a code span: `` `foo` ``
+
+will produce:
+
+       <p>A single backtick in a code span: <code>`</code></p>
+       
+       <p>A backtick-delimited string in a code span: <code>`foo`</code></p>
+
+With a code span, ampersands and angle brackets are encoded as HTML
+entities automatically, which makes it easy to include example HTML
+tags. Markdown will turn this:
+
+    Please don't use any `<blink>` tags.
+
+into:
+
+    <p>Please don't use any <code>&lt;blink&gt;</code> tags.</p>
+
+You can write this:
+
+    `&#8212;` is the decimal-encoded equivalent of `&mdash;`.
+
+to produce:
+
+    <p><code>&amp;#8212;</code> is the decimal-encoded
+    equivalent of <code>&amp;mdash;</code>.</p>
+
+
+
+<h3 id="img">Images</h3>
+
+Admittedly, it's fairly difficult to devise a "natural" syntax for
+placing images into a plain text document format.
+
+Markdown uses an image syntax that is intended to resemble the syntax
+for links, allowing for two styles: *inline* and *reference*.
+
+Inline image syntax looks like this:
+
+    ![Alt text](/path/to/img.jpg)
+
+    ![Alt text](/path/to/img.jpg "Optional title")
+
+That is:
+
+*   An exclamation mark: `!`;
+*   followed by a set of square brackets, containing the `alt`
+    attribute text for the image;
+*   followed by a set of parentheses, containing the URL or path to
+    the image, and an optional `title` attribute enclosed in double
+    or single quotes.
+
+Reference-style image syntax looks like this:
+
+    ![Alt text][id]
+
+Where "id" is the name of a defined image reference. Image references
+are defined using syntax identical to link references:
+
+    [id]: url/to/image  "Optional title attribute"
+
+As of this writing, Markdown has no syntax for specifying the
+dimensions of an image; if this is important to you, you can simply
+use regular HTML `<img>` tags.
+
+
+* * *
+
+
+<h2 id="misc">Miscellaneous</h2>
+
+<h3 id="autolink">Automatic Links</h3>
+
+Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:
+
+    <http://example.com/>
+    
+Markdown will turn this into:
+
+    <a href="http://example.com/">http://example.com/</a>
+
+Automatic links for email addresses work similarly, except that
+Markdown will also perform a bit of randomized decimal and hex
+entity-encoding to help obscure your address from address-harvesting
+spambots. For example, Markdown will turn this:
+
+    <address@example.com>
+
+into something like this:
+
+    <a href="&#x6D;&#x61;i&#x6C;&#x74;&#x6F;:&#x61;&#x64;&#x64;&#x72;&#x65;
+    &#115;&#115;&#64;&#101;&#120;&#x61;&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;
+    &#109;">&#x61;&#x64;&#x64;&#x72;&#x65;&#115;&#115;&#64;&#101;&#120;&#x61;
+    &#109;&#x70;&#x6C;e&#x2E;&#99;&#111;&#109;</a>
+
+which will render in a browser as a clickable link to "address@example.com".
+
+(This sort of entity-encoding trick will indeed fool many, if not
+most, address-harvesting bots, but it definitely won't fool all of
+them. It's better than nothing, but an address published in this way
+will probably eventually start receiving spam.)
+
+
+
+<h3 id="backslash">Backslash Escapes</h3>
+
+Markdown allows you to use backslash escapes to generate literal
+characters which would otherwise have special meaning in Markdown's
+formatting syntax. For example, if you wanted to surround a word
+with literal asterisks (instead of an HTML `<em>` tag), you can use
+backslashes before the asterisks, like this:
+
+    \*literal asterisks\*
+
+Markdown provides backslash escapes for the following characters:
+
+    \   backslash
+    `   backtick
+    *   asterisk
+    _   underscore
+    {}  curly braces
+    []  square brackets
+    ()  parentheses
+    #   hash mark
+       +   plus sign
+       -   minus sign (hyphen)
+    .   dot
+    !   exclamation mark
diff --git a/tests/MMD6Tests/Math.html b/tests/MMD6Tests/Math.html
new file mode 100644 (file)
index 0000000..7791c2c
--- /dev/null
@@ -0,0 +1,51 @@
+<p>foo <span class="math">\({e}^{i\pi }+1=0\)</span> bar</p>
+
+<p><span class="math">\[ {x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a} \]</span></p>
+
+<p>foo <span class="math">\({e}^{i\pi }+1=0\)</span> bar</p>
+
+<p>foo <span class="math">\({e}^{i\pi }+1=0\)</span>, bar</p>
+
+<p><span class="math">\[{x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a}\]</span></p>
+
+<p>5</p>
+
+<p>foo $ {e}^{i\pi }+1=0$ bar</p>
+
+<p>$$ {x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a}$$</p>
+
+<p>foo ${e}^{i\pi }+1=0 $ bar</p>
+
+<p>$${x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a} $$</p>
+
+<p>foo a${e}^{i\pi }+1=0$ bar</p>
+
+<p>10</p>
+
+<p>a$${x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a}$$</p>
+
+<p>foo ${e}^{i\pi }+1=0$b bar</p>
+
+<p>$${x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a}$$b</p>
+
+<p><span class="math">\(\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\)</span></p>
+
+<p><span class="math">\[\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\]</span></p>
+
+<p>15</p>
+
+<p><span class="math">\(\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\)</span></p>
+
+<p><span class="math">\[\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\]</span></p>
+
+<p><span class="math">\(\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}\)</span></p>
+
+<p><span class="math">\[\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}\]</span></p>
+
+<p><span class="math">\(\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}\)</span></p>
+
+<p>20</p>
+
+<p><span class="math">\[\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}\]</span></p>
+
+<p><code>\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}</code></p>
diff --git a/tests/MMD6Tests/Math.htmlc b/tests/MMD6Tests/Math.htmlc
new file mode 100644 (file)
index 0000000..627ef2f
--- /dev/null
@@ -0,0 +1,51 @@
+<p>foo \({e}^{i\pi }+1=0\) bar</p>
+
+<p>\[ {x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a} \]</p>
+
+<p>foo ${e}^{i\pi }+1=0$ bar</p>
+
+<p>foo ${e}^{i\pi }+1=0$, bar</p>
+
+<p>$${x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a}$$</p>
+
+<p>5</p>
+
+<p>foo $ {e}^{i\pi }+1=0$ bar</p>
+
+<p>$$ {x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a}$$</p>
+
+<p>foo ${e}^{i\pi }+1=0 $ bar</p>
+
+<p>$${x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a} $$</p>
+
+<p>foo a${e}^{i\pi }+1=0$ bar</p>
+
+<p>10</p>
+
+<p>a$${x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a}$$</p>
+
+<p>foo ${e}^{i\pi }+1=0$b bar</p>
+
+<p>$${x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a}$$b</p>
+
+<p>$\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}$</p>
+
+<p>$$\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}$$</p>
+
+<p>15</p>
+
+<p>\(\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\)</p>
+
+<p>\[\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\]</p>
+
+<p>$\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}$</p>
+
+<p>$$\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}$$</p>
+
+<p>\(\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}\)</p>
+
+<p>20</p>
+
+<p>\[\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}\]</p>
+
+<p><code>\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}</code></p>
diff --git a/tests/MMD6Tests/Math.text b/tests/MMD6Tests/Math.text
new file mode 100644 (file)
index 0000000..8e6788b
--- /dev/null
@@ -0,0 +1,51 @@
+foo \\({e}^{i\pi }+1=0\\) bar
+
+\\[ {x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a} \\]
+
+foo ${e}^{i\pi }+1=0$ bar
+
+foo ${e}^{i\pi }+1=0$, bar
+
+$${x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a}$$
+
+5
+
+foo $ {e}^{i\pi }+1=0$ bar
+
+$$ {x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a}$$
+
+foo ${e}^{i\pi }+1=0 $ bar
+
+$${x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a} $$
+
+foo a${e}^{i\pi }+1=0$ bar
+
+10
+
+a$${x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a}$$
+
+foo ${e}^{i\pi }+1=0$b bar
+
+$${x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a}$$b
+
+$\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}$
+
+$$\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}$$
+
+15
+
+\\(\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\\)
+
+\\[\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\\]
+
+$\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}$
+
+$$\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}$$
+
+\\(\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}\\)
+
+20
+
+\\[\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}\\]
+
+`\begin{equation}\nabla \times \mathbf{E} = - \frac{\partial \mathbf{B}}{\partial t}\end{equation}`
diff --git a/tests/MMD6Tests/Nested Lists.html b/tests/MMD6Tests/Nested Lists.html
new file mode 100644 (file)
index 0000000..e0e954c
--- /dev/null
@@ -0,0 +1,99 @@
+<ul>
+<li>foo
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li>foo
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li>foo
+
+<ul>
+<li>bar</li>
+</ul></li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+</ul>
+
+<p>5</p>
+
+<ul>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+</ul>
+
+<p>bar</p>
diff --git a/tests/MMD6Tests/Nested Lists.htmlc b/tests/MMD6Tests/Nested Lists.htmlc
new file mode 100644 (file)
index 0000000..e0e954c
--- /dev/null
@@ -0,0 +1,99 @@
+<ul>
+<li>foo
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li>foo
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li>foo
+
+<ul>
+<li>bar</li>
+</ul></li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+</ul>
+
+<p>5</p>
+
+<ul>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+</ul>
+
+<p>bar</p>
+
+<ul>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+<li><p>foo</p>
+
+<ul>
+<li>bar</li>
+</ul></li>
+</ul>
+
+<p>bar</p>
diff --git a/tests/MMD6Tests/Nested Lists.text b/tests/MMD6Tests/Nested Lists.text
new file mode 100644 (file)
index 0000000..f9d5c1e
--- /dev/null
@@ -0,0 +1,58 @@
+* foo
+       * bar
+* foo
+       * bar
+* foo
+       * bar
+
+bar
+
+* foo
+
+       * bar
+* foo
+
+       * bar
+* foo
+
+       * bar
+
+bar
+
+* foo
+       * bar
+
+* foo
+       * bar
+
+* foo
+       * bar
+
+5
+
+* foo
+       * bar
+
+* foo
+       * bar
+
+* foo
+       * bar
+
+
+bar
+
+* foo
+
+       * bar
+
+* foo
+
+       * bar
+
+* foo
+
+       * bar
+
+bar
+
diff --git a/tests/MMD6Tests/Reference Footnotes.html b/tests/MMD6Tests/Reference Footnotes.html
new file mode 100644 (file)
index 0000000..eeb3645
--- /dev/null
@@ -0,0 +1,20 @@
+<p>Reference.<a href="#fn:1" id="fnref:1" title="see footnote" class="footnote">[1]</a></p>
+
+<p>Reference.<a href="#fn:2" id="fnref:2" title="see footnote" class="footnote">[2]</a></p>
+
+<div class="footnotes">
+<hr />
+<ol>
+
+<li id="fn:1">
+<p>This is a <em>short</em> footnote. <a href="#fnref:1" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
+</li>
+
+<li id="fn:2">
+<p>This is a longer footnote.
+With two lines. <a href="#fnref:2" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
+</li>
+
+</ol>
+</div>
+
diff --git a/tests/MMD6Tests/Reference Footnotes.htmlc b/tests/MMD6Tests/Reference Footnotes.htmlc
new file mode 100644 (file)
index 0000000..e7a323c
--- /dev/null
@@ -0,0 +1,7 @@
+<p>Reference.[^foo]</p>
+
+<p>Reference.[^foo2]</p>
+
+<p>[^foo]: This is a <em>short</em> footnote.
+[^foo2]: This is a longer footnote.
+With two lines.</p>
diff --git a/tests/MMD6Tests/Reference Footnotes.text b/tests/MMD6Tests/Reference Footnotes.text
new file mode 100644 (file)
index 0000000..c254336
--- /dev/null
@@ -0,0 +1,8 @@
+Reference.[^foo]
+
+Reference.[^foo2]
+
+
+[^foo]: This is a *short* footnote.
+[^foo2]: This is a longer footnote.
+With two lines.
diff --git a/tests/MMD6Tests/Reference Images.html b/tests/MMD6Tests/Reference Images.html
new file mode 100644 (file)
index 0000000..c277d09
--- /dev/null
@@ -0,0 +1,17 @@
+<p>Test <img src="http://test.1/" alt="foo" />.</p>
+
+<p>Test <img src="http://test.1/" alt="foo" />.</p>
+
+<p>Test <img src="http://test.3/" alt="foo" title="title" />.</p>
+
+<p>Test <img src="http://test.4/" alt="foo" />.</p>
+
+<p>Test <img src="http://test.4/" alt="foo" />.</p>
+
+<p>5</p>
+
+<p>Test <img src="http://test.6/" alt="foo" title="title" />.</p>
+
+<p>Test <img src="http://test.0/" alt="foo" />.</p>
+
+<p>Test <img src="http://test.0/" alt="foo" />.</p>
diff --git a/tests/MMD6Tests/Reference Images.htmlc b/tests/MMD6Tests/Reference Images.htmlc
new file mode 100644 (file)
index 0000000..c277d09
--- /dev/null
@@ -0,0 +1,17 @@
+<p>Test <img src="http://test.1/" alt="foo" />.</p>
+
+<p>Test <img src="http://test.1/" alt="foo" />.</p>
+
+<p>Test <img src="http://test.3/" alt="foo" title="title" />.</p>
+
+<p>Test <img src="http://test.4/" alt="foo" />.</p>
+
+<p>Test <img src="http://test.4/" alt="foo" />.</p>
+
+<p>5</p>
+
+<p>Test <img src="http://test.6/" alt="foo" title="title" />.</p>
+
+<p>Test <img src="http://test.0/" alt="foo" />.</p>
+
+<p>Test <img src="http://test.0/" alt="foo" />.</p>
diff --git a/tests/MMD6Tests/Reference Images.text b/tests/MMD6Tests/Reference Images.text
new file mode 100644 (file)
index 0000000..2eeba99
--- /dev/null
@@ -0,0 +1,27 @@
+Test ![*foo*][bar].
+
+Test ![*foo*][BAR].
+
+Test ![*foo*][foobar].
+
+Test ![*foo*][foo bar].
+
+Test ![*foo*][foo  bar].
+
+5
+
+Test ![*foo*][long].
+
+Test ![foo][].
+
+Test ![foo].
+
+
+[foo]: http://test.0/
+[bar]: http://test.1/
+[BAR]: http://test.2/
+[foobar]: http://test.3/       "title"
+[foo bar]: http://test.4/
+[foo  bar]: http://test.5/     ""
+[long]: http://test.6/
+"title"
diff --git a/tests/MMD6Tests/Reference Links.html b/tests/MMD6Tests/Reference Links.html
new file mode 100644 (file)
index 0000000..e6d8f09
--- /dev/null
@@ -0,0 +1,32 @@
+<p><a href="http://test.1/file.txt"><em>foo</em></a>.</p>
+
+<p><a href="http://test.1/file.txt"><em>foo</em></a>.</p>
+
+<p><a href="http://test.3/file.txt" title="title"><em>foo</em></a>.</p>
+
+<p><a href="http://test.4/"><em>foo</em></a>.</p>
+
+<p><a href="http://test.4/"><em>foo</em></a>.</p>
+
+<p>5</p>
+
+<p><a href="http://test.6/" title="title"><em>foo</em></a>.</p>
+
+<p><a href="http://test.0/">foo</a>.</p>
+
+<p><a href="http://test.0/">foo</a>.</p>
+
+<p><a href="http://test.1/file.txt"><a href="http://test.0/">foo</a></a></p>
+
+<p><a href="http://test.0/"><a href="http://test.0/">foo</a></a></p>
+
+<p>10</p>
+
+<p><a href="http://test.3/file.txt" title="title"><a href="http://test.1/file.txt">foo</a></a></p>
+
+<p><a href="http://test.1/file.txt">foo</a></p>
+
+<p><a href="http://test.0/">foo</a> <a href="http://test.1/file.txt">bar</a></p>
+
+<p><a href="http://test.0/">foo</a>
+<a href="http://test.1/file.txt">bar</a></p>
diff --git a/tests/MMD6Tests/Reference Links.htmlc b/tests/MMD6Tests/Reference Links.htmlc
new file mode 100644 (file)
index 0000000..e6d8f09
--- /dev/null
@@ -0,0 +1,32 @@
+<p><a href="http://test.1/file.txt"><em>foo</em></a>.</p>
+
+<p><a href="http://test.1/file.txt"><em>foo</em></a>.</p>
+
+<p><a href="http://test.3/file.txt" title="title"><em>foo</em></a>.</p>
+
+<p><a href="http://test.4/"><em>foo</em></a>.</p>
+
+<p><a href="http://test.4/"><em>foo</em></a>.</p>
+
+<p>5</p>
+
+<p><a href="http://test.6/" title="title"><em>foo</em></a>.</p>
+
+<p><a href="http://test.0/">foo</a>.</p>
+
+<p><a href="http://test.0/">foo</a>.</p>
+
+<p><a href="http://test.1/file.txt"><a href="http://test.0/">foo</a></a></p>
+
+<p><a href="http://test.0/"><a href="http://test.0/">foo</a></a></p>
+
+<p>10</p>
+
+<p><a href="http://test.3/file.txt" title="title"><a href="http://test.1/file.txt">foo</a></a></p>
+
+<p><a href="http://test.1/file.txt">foo</a></p>
+
+<p><a href="http://test.0/">foo</a> <a href="http://test.1/file.txt">bar</a></p>
+
+<p><a href="http://test.0/">foo</a>
+<a href="http://test.1/file.txt">bar</a></p>
diff --git a/tests/MMD6Tests/Reference Links.text b/tests/MMD6Tests/Reference Links.text
new file mode 100644 (file)
index 0000000..45cc503
--- /dev/null
@@ -0,0 +1,42 @@
+[*foo*][bar].
+
+[*foo*][BAR].
+
+[*foo*][foobar].
+
+[*foo*][foo bar].
+
+[*foo*][foo  bar].
+
+5
+
+[*foo*][long].
+
+[foo][].
+
+[foo].
+
+[[foo]][bar]
+
+[[foo]][]
+
+10
+
+[[foo][bar]][]
+
+[foo][bar]
+
+[foo] [bar]
+
+[foo]
+[bar]
+
+
+[foo]: http://test.0/
+[bar]: http://test.1/file.txt
+[BAR]:      http://test.2/
+[foobar]: http://test.3/file.txt       "title"
+[foo bar]: http://test.4/
+[foo  bar]: http://test.5/     ""
+[long]: http://test.6/
+"title"
diff --git a/tests/MMD6Tests/Smart Quotes.html b/tests/MMD6Tests/Smart Quotes.html
new file mode 100644 (file)
index 0000000..5fd0b38
--- /dev/null
@@ -0,0 +1,69 @@
+<p>&#8216;foo&#8217;</p>
+
+<p>&#8220;foo&#8221;</p>
+
+<p>&#8220;foo&#8221; &#8216;bar&#8217;</p>
+
+<p>&#8216;foo&#8217; &#8220;bar&#8221;</p>
+
+<p>&#8216;.foo&#8217;</p>
+
+<p>5</p>
+
+<p>&quot;foo&quot;.</p>
+
+<p>'foo'.</p>
+
+<p>`foo'</p>
+
+<p>&#8220;foo&#8221;</p>
+
+<p>```foo'''</p>
+
+<p>10</p>
+
+<p>&#8220;&#8221; foo &#8220;&#8221;?</p>
+
+<p>'' foo ''?</p>
+
+<p>isn&#8217;t</p>
+
+<p>foo &#8211; bar</p>
+
+<p>foo &#8212; bar</p>
+
+<p>15</p>
+
+<p>1&#8211;2</p>
+
+<p>1&#8211;2</p>
+
+<p>1&#8212;3</p>
+
+<p><code>--</code></p>
+
+<p><code>---</code></p>
+
+<p>20</p>
+
+<p>&#8230;</p>
+
+<p>&#8230;</p>
+
+<p><code>...</code></p>
+
+<p><code>. . .</code></p>
+
+<p>l&#8217;année l&#8217;année</p>
+
+<p>25</p>
+
+<p>l&#8217;été l&#8217;année</p>
+
+<p>l&#8217;été l&#8217;été</p>
+
+<p>l&#8217;année l&#8217;été</p>
+
+<p>foo&#8217;s and bar&#8217;s</p>
+
+<p><code>foo</code>&#8217;s and <code>bar</code>&#8217;s</p>
diff --git a/tests/MMD6Tests/Smart Quotes.htmlc b/tests/MMD6Tests/Smart Quotes.htmlc
new file mode 100644 (file)
index 0000000..73f9ea2
--- /dev/null
@@ -0,0 +1,69 @@
+<p>'foo'</p>
+
+<p>&quot;foo&quot;</p>
+
+<p>&quot;foo&quot; 'bar'</p>
+
+<p>'foo' &quot;bar&quot;</p>
+
+<p>'.foo'</p>
+
+<p>5</p>
+
+<p>&quot;foo&quot;.</p>
+
+<p>'foo'.</p>
+
+<p>`foo'</p>
+
+<p>``foo''</p>
+
+<p>```foo'''</p>
+
+<p>10</p>
+
+<p>&quot;&quot; foo &quot;&quot;?</p>
+
+<p>'' foo ''?</p>
+
+<p>isn't</p>
+
+<p>foo -- bar</p>
+
+<p>foo --- bar</p>
+
+<p>15</p>
+
+<p>1-2</p>
+
+<p>1--2</p>
+
+<p>1---3</p>
+
+<p><code>--</code></p>
+
+<p><code>---</code></p>
+
+<p>20</p>
+
+<p>...</p>
+
+<p>. . .</p>
+
+<p><code>...</code></p>
+
+<p><code>. . .</code></p>
+
+<p>l'année l'année</p>
+
+<p>25</p>
+
+<p>l'été l'année</p>
+
+<p>l'été l'été</p>
+
+<p>l'année l'été</p>
+
+<p>foo's and bar's</p>
+
+<p><code>foo</code>'s and <code>bar</code>'s</p>
diff --git a/tests/MMD6Tests/Smart Quotes.text b/tests/MMD6Tests/Smart Quotes.text
new file mode 100644 (file)
index 0000000..64993dc
--- /dev/null
@@ -0,0 +1,69 @@
+'foo'
+
+"foo"
+
+"foo" 'bar'
+
+'foo' "bar"
+
+'.foo'
+
+5
+
+\"foo\".
+
+\'foo\'.
+
+`foo'
+
+``foo''
+
+```foo'''
+
+10
+
+"" foo ""?
+
+'' foo ''?
+
+isn't
+
+foo -- bar
+
+foo --- bar
+
+15
+
+1-2
+
+1--2
+
+1---3
+
+`--`
+
+`---`
+
+20
+
+...
+
+. . .
+
+`...`
+
+`. . .`
+
+l'année l'année
+
+25
+
+l'été l'année
+
+l'été l'été
+
+l'année l'été
+
+foo's and bar's
+
+`foo`'s and `bar`'s
diff --git a/tests/MMD6Tests/Superscript.html b/tests/MMD6Tests/Superscript.html
new file mode 100644 (file)
index 0000000..adbce18
--- /dev/null
@@ -0,0 +1,27 @@
+<p>x<sup>2</sup>.</p>
+
+<p>x<sup>2xz</sup>.</p>
+
+<p>x<sup>2.</sup></p>
+
+<p>x<sup>2</sup> 3^</p>
+
+<p>x<sup>2</sup> 3<sup>2</sup></p>
+
+<p>5</p>
+
+<p>x<sub>z</sub>.</p>
+
+<p>x<sub>xyz</sub>.</p>
+
+<p>z<sub>z.</sub></p>
+
+<p>~/Library/MultiMarkdown</p>
+
+<p>^test</p>
+
+<p>10</p>
+
+<p>x^y</p>
+
+<p>x~y</p>
diff --git a/tests/MMD6Tests/Superscript.htmlc b/tests/MMD6Tests/Superscript.htmlc
new file mode 100644 (file)
index 0000000..81a1a55
--- /dev/null
@@ -0,0 +1,27 @@
+<p>x^2.</p>
+
+<p>x^2xz.</p>
+
+<p>x^2.^</p>
+
+<p>x^2 3^</p>
+
+<p>x^2 3^2</p>
+
+<p>5</p>
+
+<p>x~z.</p>
+
+<p>x~xyz.</p>
+
+<p>z~z.~</p>
+
+<p>~/Library/MultiMarkdown</p>
+
+<p>^test</p>
+
+<p>10</p>
+
+<p>x^y</p>
+
+<p>x~y</p>
diff --git a/tests/MMD6Tests/Superscript.text b/tests/MMD6Tests/Superscript.text
new file mode 100644 (file)
index 0000000..2e521a7
--- /dev/null
@@ -0,0 +1,27 @@
+x^2.
+
+x^2xz.
+
+x^2.^
+
+x^2 3^
+
+x^2 3^2
+
+5
+
+x~z.
+
+x~xyz.
+
+z~z.~
+
+~/Library/MultiMarkdown
+
+^test
+
+10
+
+x\^y
+
+x\~y
diff --git a/tests/MarkdownTest.pl b/tests/MarkdownTest.pl
new file mode 100755 (executable)
index 0000000..9a521c1
--- /dev/null
@@ -0,0 +1,184 @@
+#!/usr/bin/perl
+
+#
+# MarkdownTester -- Run tests for Markdown implementations
+#
+# Copyright (c) 2004-2005 John Gruber
+# <http://daringfireball.net/projects/markdown/>
+#
+
+use strict;
+use warnings;
+use Getopt::Long;
+use Benchmark;
+
+our $VERSION = '1.0.2';
+# Sat 24 Dec 2005
+
+my $time_start = new Benchmark;
+my $test_dir = "Tests";
+my $script  = "./Markdown.pl";
+my $use_tidy = 0;
+my ($flag_version);
+my $flags = "";
+my $file_ext = "html";
+my $trail = "";
+
+GetOptions (
+                       "script=s"   => \$script,
+                       "testdir=s"  => \$test_dir,
+                       "tidy"       => \$use_tidy,
+                       "version"    => \$flag_version,
+                       "flags=s"        => \$flags,
+                       "ext=s"          => \$file_ext,
+                       "trailflags=s" => \$trail,
+                       );
+
+if($flag_version) {
+       my $progname = $0;
+       $progname =~ s{.*/}{};
+       die "$progname version $VERSION\n";
+}
+
+unless (-d $test_dir) { die "'$test_dir' is not a directory.\n"; }
+unless (-f $script)   { die "$script does not exist.\n"; }
+unless (-x $script)   { die "$script is not executable.\n"; }
+
+my $tests_passed = 0;
+my $tests_failed = 0;
+
+TEST:
+foreach my $testfile (glob "$test_dir/*.text") {
+       my $testname = $testfile;
+       $testname =~ s{.*/(.+)\.text$}{$1}i; 
+       print "$testname ... ";
+
+       # Look for a corresponding .html file for each .text file:
+       my $resultfile = $testfile;
+       $resultfile =~ s{\.text$}{\.$file_ext}i;
+       unless (-f $resultfile) {
+               print "'$resultfile' does not exist.\n\n";
+               $tests_failed++;
+               next TEST;
+       }
+       
+       # open(TEST, $testfile)     || die("Can't open testfile: $!");
+       open(RESULT, $resultfile) || die("Can't open resultfile: $!");
+       undef $/;
+       # my $t_input = <TEST>;
+       my $t_result = <RESULT>;
+
+       my $t_output = `'$script' $flags '$testfile' $trail`;
+
+       # Normalize the output and expected result strings:
+       $t_result =~ s/\s+\z//; # trim trailing whitespace
+       $t_output =~ s/\s+\z//; # trim trailing whitespace
+       if ($use_tidy) {
+               #  Escape the strings, pass them through to CLI tidy tool for tag-level equivalency
+               $t_result =~ s{'}{'\\''}g; # escape ' chars for shell
+               $t_output =~ s{'}{'\\''}g;
+               $t_result = `echo '$t_result' | tidy --show-body-only 1 --quiet 1 --show-warnings 0`;
+               $t_output = `echo '$t_output' | tidy --show-body-only 1 --quiet 1 --show-warnings 0`;
+       }
+
+       if ($t_output eq $t_result) {
+               print "OK\n";
+               $tests_passed++;
+       }
+       else {
+               print "FAILED\n\n";
+# This part added by JM to print diffs
+        open(OUT, '>tmp1') or die $!;
+        print OUT $t_output or die $!;
+        open(RES, '>tmp2') or die $!;
+        print RES $t_result or die $!;
+        print `diff tmp1 tmp2`;
+        close RES;
+        close OUT;
+        print "\n";
+        `rm tmp?`;
+# End of added part
+               $tests_failed++;
+       }
+}
+
+print "\n\n";
+print "$tests_passed passed; $tests_failed failed.\n";
+
+my $time_end = new Benchmark;
+my $time_diff = timediff($time_end, $time_start);
+print "Benchmark: ", timestr($time_diff), "\n";
+
+exit($tests_failed);
+
+__END__
+
+=pod
+
+=head1 NAME
+
+B<MarkdownTest>
+
+
+=head1 SYNOPSIS
+
+B<MarkdownTest.pl> [ B<--options> ]  [ I<file> ... ]
+
+
+=head1 DESCRIPTION
+
+
+=head1 OPTIONS
+
+Use "--" to end switch parsing. For example, to open a file named "-z", use:
+
+       MarkdownTest.pl -- -z
+
+=over 4
+
+=item B<--script>
+
+Specify the path to the Markdown script to test. Defaults to
+"./Markdown.pl". Example:
+
+       ./MarkdownTest.pl --script ./PHP-Markdown/php-markdown
+
+=item B<--testdir>
+
+Specify the path to a directory containing test data. Defaults to "Tests".
+
+=item B<--tidy>
+
+Flag to turn on using the command line 'tidy' tool to normalize HTML
+output before comparing script output to the expected test result.
+Assumes that the 'tidy' command is available in your PATH. Defaults to
+off.
+
+=back
+
+
+
+=head1 BUGS
+
+
+
+=head1 VERSION HISTORY
+
+1.0    Mon 13 Dec 2004-2005
+
+1.0.1 Mon 19 Sep 2005
+
+       +       Better handling of case when foo.text exists, but foo.html doesn't.
+               It now prints a message and moves on, rather than dying.
+
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2004-2005 John Gruber  
+<http://daringfireball.net/>   
+All rights reserved.
+
+This is free software; you may redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=cut