diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7bd9f10f..cb778940 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,14 +8,14 @@ cmake_minimum_required (VERSION 2.6)
set (My_Project_Title "MultiMarkdown")
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-11-20")
+set (My_Project_Revised_Date "2018-02-05")
set (My_Project_Version_Major 6)
-set (My_Project_Version_Minor 2)
-set (My_Project_Version_Patch 3)
+set (My_Project_Version_Minor 3)
+set (My_Project_Version_Patch 0)
set (My_Project_Version "${My_Project_Version_Major}.${My_Project_Version_Minor}.${My_Project_Version_Patch}")
-set (My_Project_Copyright_Date "2016 - 2017")
+set (My_Project_Copyright_Date "2016 - 2018")
set (My_Project_Copyright "Copyright © ${My_Project_Copyright_Date} ${My_Project_Author}.")
string(TOUPPER ${My_Project_Title} My_Project_Title_Caps )
@@ -104,7 +104,7 @@ MACRO(ADD_PUBLIC_HEADER target filename)
SET_TARGET_PROPERTIES(${target} PROPERTIES
XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS
- "macos iphonesimulator iphoneos"
+ "macosx iphonesimulator iphoneos"
)
SET_TARGET_PROPERTIES(${target} PROPERTIES
@@ -184,7 +184,6 @@ set(src_files
Sources/libMultiMarkdown/d_string.c
Sources/libMultiMarkdown/epub.c
Sources/libMultiMarkdown/file.c
- Sources/libMultiMarkdown/fodt.c
Sources/libMultiMarkdown/html.c
Sources/libMultiMarkdown/latex.c
Sources/libMultiMarkdown/lexer.c
@@ -216,7 +215,6 @@ set(header_files
Sources/libMultiMarkdown/include/d_string.h
Sources/libMultiMarkdown/epub.h
Sources/libMultiMarkdown/file.h
- Sources/libMultiMarkdown/fodt.h
Sources/libMultiMarkdown/html.h
Sources/libMultiMarkdown/latex.h
Sources/libMultiMarkdown/lexer.h
@@ -270,6 +268,15 @@ set (latex
texmf/tex/latex/mmd6/article/mmd6-article-footer.tex
texmf/tex/latex/mmd6/article/mmd6-article-leader.tex
+ texmf/tex/latex/mmd6/beamer/beamerthemekeynote-gradient.sty
+ texmf/tex/latex/mmd6/beamer/beamerthemekeynote-portfolio.sty
+ texmf/tex/latex/mmd6/beamer/beamerthemekeynote-vintage.sty
+ texmf/tex/latex/mmd6/beamer/mmd6-beamer-begin.tex
+ texmf/tex/latex/mmd6/beamer/mmd6-beamer-footer.tex
+ texmf/tex/latex/mmd6/beamer/mmd6-beamer-leader.tex
+ texmf/tex/latex/mmd6/beamer/Portfolio.png
+ texmf/tex/latex/mmd6/beamer/Vintage.png
+
texmf/tex/latex/mmd6/letterhead/mmd-envelope.sty
texmf/tex/latex/mmd6/letterhead/mmd-letterhead.sty
texmf/tex/latex/mmd6/letterhead/mmd6-letterhead-begin.tex
@@ -426,13 +433,15 @@ endif (WIN32)
# ==============
# Is libcurl available?
-find_package(CURL)
-if (CURL_FOUND)
- add_definitions(-DUSE_CURL)
- message (STATUS "libcurl found")
-else ()
- message (STATUS "libcurl not found")
-endif (CURL_FOUND)
+if (NOT DEFINED TEST)
+ find_package(CURL)
+ if (CURL_FOUND)
+ add_definitions(-DUSE_CURL)
+ message (STATUS "libcurl found")
+ else ()
+ message (STATUS "libcurl not found")
+ endif (CURL_FOUND)
+endif ()
# Create a library?
if (NOT DEFINED TEST)
diff --git a/DevelopmentNotes/DevelopmentNotes.epub b/DevelopmentNotes/DevelopmentNotes.epub
index dbf317ae..919076f4 100644
Binary files a/DevelopmentNotes/DevelopmentNotes.epub and b/DevelopmentNotes/DevelopmentNotes.epub differ
diff --git a/DevelopmentNotes/DevelopmentNotes.fodt b/DevelopmentNotes/DevelopmentNotes.fodt
index 8e071cc2..76037dbe 100644
--- a/DevelopmentNotes/DevelopmentNotes.fodt
+++ b/DevelopmentNotes/DevelopmentNotes.fodt
@@ -276,7 +276,7 @@ office:mimetype="application/vnd.oasis.opendocument.text">
2018–02–05 - v 6.3.0: 2017–11–20 - v 6.2.3: Version: 6.2.2 Version: 6.3.0 This document serves as a description of MultiMarkdown (MMD) v6, as well as a sample
document to demonstrate the various features. Specifically, differences from
@@ -354,7 +354,7 @@ In addition, there is a new shortcut key – Dependencies/Libraries
Changelog
+
+
diff --git a/DevelopmentNotes/DevelopmentNotes.pdf b/DevelopmentNotes/DevelopmentNotes.pdf
index 813636e8..db948c0d 100644
Binary files a/DevelopmentNotes/DevelopmentNotes.pdf and b/DevelopmentNotes/DevelopmentNotes.pdf differ
diff --git a/DevelopmentNotes/DevelopmentNotes.txt b/DevelopmentNotes/DevelopmentNotes.txt
index 45ad9181..80a19e5f 100644
--- a/DevelopmentNotes/DevelopmentNotes.txt
+++ b/DevelopmentNotes/DevelopmentNotes.txt
@@ -1,6 +1,6 @@
Title: MultiMarkdown v6 Development Notes
Author: Fletcher T. Penney
-Date: 2017-11-20
+Date: 2018-02-05
LaTeX Config: tufte-handout
Base Header Level: 3
uuid: dd2d8e76-dc2d-416d-9acd-5395d20871c2
@@ -471,6 +471,39 @@ TextBundle/TextPack, OpenDocument, etc.
# Changelog #
+* 2018-02-05 - v 6.3.0:
+
+ * ADDED: Add additional CM tests
+ * ADDED: Add beamer LaTeX support files to installer
+ * ADDED: Update beamer latex support files for MMD 6 latex config metadata support
+ * FIXED: All test build on path with spaces
+ * FIXED: Don't use libcurl on test build
+ * FIXED: Fix HTML 5 compliance with image dimensions; Fix CriticMarkup inside code spans/blocks
+ * FIXED: Fix bug in token pruning
+ * FIXED: Fix bug with setting tail in token prune/graft
+ * FIXED: Fix edge case with superscripts and punctuation
+ * FIXED: Fix issue in Windows code
+ * FIXED: Fix issue with list bullets in fenced code blocks
+ * FIXED: Fix reject/accept with highlighting
+ * FIXED: Fix typo in QuickStart.txt (fixes #111)
+ * FIXED: Properly assign ambidextrous tokens in tables
+ * Fix encoding of some markup inside LaTeX texttt environment (fixes #110 and #108)
+ * UPDATED: Add Spanish style quotes support
+ * UPDATED: Add test suite to d_string
+ * UPDATED: Apply astyle to source
+ * UPDATED: Improve commands for accepting/rejecting CriticMarkup
+ * UPDATED: Remove deprecated fodt.c and fodt.h
+ * UPDATED: Update dates
+ * UPDATED: specify types to silence warnings and prevent theoretical errors
+ * add cocoaconv.rb enum conversion script
+ * change d_string_erase argument docstring
+ * drop redundant enum case prefixes in Swift
+ * drop redundant enum name prefixes from enum cases
+ * expose singular-S type to Swift code generator
+ * fix target platform spelling (macosx, not macos)
+ * remove plural S from enum type names
+
+
* 2017-11-20 - v 6.2.3:
* CHANGED: Fix typos
diff --git a/QuickStart/QuickStart.epub b/QuickStart/QuickStart.epub
index 0618429b..6534f83d 100644
Binary files a/QuickStart/QuickStart.epub and b/QuickStart/QuickStart.epub differ
diff --git a/QuickStart/QuickStart.fodt b/QuickStart/QuickStart.fodt
index dd8e8ee5..b3a30e3d 100644
--- a/QuickStart/QuickStart.fodt
+++ b/QuickStart/QuickStart.fodt
@@ -276,7 +276,7 @@ office:mimetype="application/vnd.oasis.opendocument.text">
Introduction
-LaTeX Changes
latex config
. This allows
you to specify a “document name” that is used to automatically identify the
corresponding latex leader
, latex begin
, and latex footer
files. For
-example, using latex config: artice
is the same as using:latex config: article
is the same as using:
latex leader: mmd6-article-leader
latex begin: mmd6-article-begin
diff --git a/QuickStart/QuickStart.pdf b/QuickStart/QuickStart.pdf
index 7fa0b272..16e3ccf5 100644
Binary files a/QuickStart/QuickStart.pdf and b/QuickStart/QuickStart.pdf differ
diff --git a/QuickStart/QuickStart.txt b/QuickStart/QuickStart.txt
index 21f3f73d..6e4e22ac 100644
--- a/QuickStart/QuickStart.txt
+++ b/QuickStart/QuickStart.txt
@@ -1,6 +1,6 @@
Title: MultiMarkdown v6 Quick Start Guide
Author: Fletcher T. Penney
-Version: 6.2.2
+Version: 6.3.0
LaTeX Config: tufte-handout
Base Header Level: 3
uuid: 0d6313fa-9135-477e-9c14-7d62c1977833
@@ -334,7 +334,7 @@ new system.
***In addition***, there is a new shortcut key -- `latex config`. This allows
you to specify a "document name" that is used to automatically identify the
corresponding `latex leader`, `latex begin`, and `latex footer` files. For
-example, using `latex config: artice` is the same as using:
+example, using `latex config: article` is the same as using:
latex leader: mmd6-article-leader
latex begin: mmd6-article-begin
diff --git a/README.md b/README.md
index 5f64b52a..4d459cd1 100644
--- a/README.md
+++ b/README.md
@@ -4,9 +4,9 @@
| ---------- | ------------------------- |
| Title: | MultiMarkdown |
| Author: | Fletcher T. Penney |
-| Date: | 2017-11-20 |
-| Copyright: | Copyright © 2016 - 2017 Fletcher T. Penney. |
-| Version: | 6.2.3 |
+| Date: | 2018-02-05 |
+| Copyright: | Copyright © 2016 - 2018 Fletcher T. Penney. |
+| Version: | 6.3.0 |
master branch: [![Build Status](https://travis-ci.org/fletcher/MultiMarkdown-6.svg?branch=master)](https://travis-ci.org/fletcher/MultiMarkdown-6)
develop branch: [![Build Status](https://travis-ci.org/fletcher/MultiMarkdown-6.svg?branch=develop)](https://travis-ci.org/fletcher/MultiMarkdown-6)
diff --git a/Sources/libMultiMarkdown/aho-corasick.c b/Sources/libMultiMarkdown/aho-corasick.c
index 90cd8bcb..a9963806 100644
--- a/Sources/libMultiMarkdown/aho-corasick.c
+++ b/Sources/libMultiMarkdown/aho-corasick.c
@@ -478,9 +478,9 @@ void match_set_filter_leftmost_longest(match * header) {
m->next->start > m->start &&
m->next->start < m->start + m->len) {
// This match is "lefter" than next
-#ifndef __clang_analyzer__
+ #ifndef __clang_analyzer__
match_excise(m->next);
-#endif
+ #endif
}
while (m->next &&
@@ -497,9 +497,9 @@ void match_set_filter_leftmost_longest(match * header) {
m->prev->start >= m->start) {
// We are "lefter" than previous
n = m->prev;
-#ifndef __clang_analyzer__
+ #ifndef __clang_analyzer__
match_excise(n);
-#endif
+ #endif
}
m = m->next;
diff --git a/Sources/libMultiMarkdown/critic_markup.c b/Sources/libMultiMarkdown/critic_markup.c
index 0afe3cda..0ad27c58 100644
--- a/Sources/libMultiMarkdown/critic_markup.c
+++ b/Sources/libMultiMarkdown/critic_markup.c
@@ -191,6 +191,8 @@ void accept_token(DString * d, token * t) {
case CM_SUB_OPEN:
case CM_ADD_OPEN:
case CM_ADD_CLOSE:
+ case CM_HI_OPEN:
+ case CM_HI_CLOSE:
if (!t->mate) {
break;
}
@@ -233,8 +235,9 @@ void accept_token_tree(DString * d, token * t) {
}
}
-void mmd_critic_markup_accept(DString * d) {
- token * t = critic_parse_substring(d->str, 0, d->currentStringLength);
+
+void mmd_critic_markup_accept_range(DString * d, size_t start, size_t len) {
+ token * t = critic_parse_substring(d->str, start, len);
if (t && t->child) {
accept_token_tree(d, t->child->tail);
@@ -244,6 +247,11 @@ void mmd_critic_markup_accept(DString * d) {
}
+void mmd_critic_markup_accept(DString * d) {
+ mmd_critic_markup_accept_range(d, 0, d->currentStringLength);
+}
+
+
void reject_token_tree(DString * d, token * t);
void reject_token(DString * d, token * t);
@@ -275,6 +283,8 @@ void reject_token(DString * d, token * t) {
case CM_SUB_OPEN:
case CM_DEL_OPEN:
case CM_DEL_CLOSE:
+ case CM_HI_OPEN:
+ case CM_HI_CLOSE:
if (!t->mate) {
break;
}
@@ -317,8 +327,9 @@ void reject_token_tree(DString * d, token * t) {
}
}
-void mmd_critic_markup_reject(DString * d) {
- token * t = critic_parse_substring(d->str, 0, d->currentStringLength);
+
+void mmd_critic_markup_reject_range(DString * d, size_t start, size_t len) {
+ token * t = critic_parse_substring(d->str, start, len);
if (t && t->child) {
reject_token_tree(d, t->child->tail);
@@ -328,3 +339,88 @@ void mmd_critic_markup_reject(DString * d) {
}
+
+void mmd_critic_markup_reject(DString * d) {
+ mmd_critic_markup_reject_range(d, 0, d->currentStringLength);
+}
+
+
+#ifdef TEST
+void Test_critic(CuTest* tc) {
+ #ifdef kUseObjectPool
+ token_pool_init();
+ #endif
+
+ DString * test = d_string_new("{--foo bar--}");
+ mmd_critic_markup_reject(test);
+ CuAssertStrEquals(tc, "foo bar", test->str);
+
+ d_string_erase(test, 0, -1);
+ d_string_append(test, "{++foo bar++}");
+ mmd_critic_markup_reject(test);
+ CuAssertStrEquals(tc, "", test->str);
+
+
+ d_string_erase(test, 0, -1);
+ d_string_append(test, "{--foo bar--}");
+ mmd_critic_markup_accept(test);
+ CuAssertStrEquals(tc, "", test->str);
+
+ d_string_erase(test, 0, -1);
+ d_string_append(test, "{++foo bar++}");
+ mmd_critic_markup_accept(test);
+ CuAssertStrEquals(tc, "foo bar", test->str);
+
+ d_string_erase(test, 0, -1);
+ d_string_append(test, "{++foo{--bat--}bar++}");
+ mmd_critic_markup_accept(test);
+ CuAssertStrEquals(tc, "foobar", test->str);
+
+ d_string_erase(test, 0, -1);
+ d_string_append(test, "{--foo{-- bat --}bar--}");
+ mmd_critic_markup_reject(test);
+ CuAssertStrEquals(tc, "foo bat bar", test->str);
+
+ d_string_erase(test, 0, -1);
+ d_string_append(test, "{--foo{++ bat ++}bar--}");
+ mmd_critic_markup_reject(test);
+ CuAssertStrEquals(tc, "foobar", test->str);
+
+ d_string_erase(test, 0, -1);
+ d_string_append(test, "{==foo bar==}");
+ mmd_critic_markup_reject(test);
+ CuAssertStrEquals(tc, "foo bar", test->str);
+
+ d_string_erase(test, 0, -1);
+ d_string_append(test, "{==foo bar==}");
+ mmd_critic_markup_accept(test);
+ CuAssertStrEquals(tc, "foo bar", test->str);
+
+ d_string_erase(test, 0, -1);
+ d_string_append(test, "{>>foo bar<<}");
+ mmd_critic_markup_reject(test);
+ CuAssertStrEquals(tc, "", test->str);
+
+ d_string_erase(test, 0, -1);
+ d_string_append(test, "{>>foo bar<<}");
+ mmd_critic_markup_accept(test);
+ CuAssertStrEquals(tc, "", test->str);
+
+ d_string_erase(test, 0, -1);
+ d_string_append(test, "{++foo++}{>>bar<<}");
+ mmd_critic_markup_accept(test);
+ CuAssertStrEquals(tc, "foo", test->str);
+
+ d_string_erase(test, 0, -1);
+ d_string_append(test, "{++foo++}{>>bar<<}");
+ mmd_critic_markup_reject(test);
+ CuAssertStrEquals(tc, "", test->str);
+
+ #ifdef kUseObjectPool
+ // Decrement counter and clean up token pool
+ token_pool_drain();
+
+ token_pool_free();
+ #endif
+}
+#endif
diff --git a/Sources/libMultiMarkdown/critic_markup.h b/Sources/libMultiMarkdown/critic_markup.h
index 167668c7..c5c58ce4 100644
--- a/Sources/libMultiMarkdown/critic_markup.h
+++ b/Sources/libMultiMarkdown/critic_markup.h
@@ -60,6 +60,11 @@
#include "d_string.h"
+#ifdef TEST
+ #include "CuTest.h"
+#endif
+
+
enum cm_types {
CM_ADD_OPEN = 1, // Can't use type 0
CM_ADD_CLOSE,
@@ -88,7 +93,9 @@ enum cm_types {
void mmd_critic_markup_accept(DString * d);
+void mmd_critic_markup_accept_range(DString * d, size_t start, size_t len);
void mmd_critic_markup_reject(DString * d);
+void mmd_critic_markup_reject_range(DString * d, size_t start, size_t len);
#endif
diff --git a/Sources/libMultiMarkdown/d_string.c b/Sources/libMultiMarkdown/d_string.c
index 697fab24..036cce42 100644
--- a/Sources/libMultiMarkdown/d_string.c
+++ b/Sources/libMultiMarkdown/d_string.c
@@ -17,7 +17,7 @@
/*
Copyright © 2011 Daniel Jalkut.
- Modifications by Fletcher T. Penney, Copyright © 2011-2017 Fletcher T. Penney.
+ Modifications by Fletcher T. Penney, Copyright © 2011-2018 Fletcher T. Penney.
Modifications by Dan Lowe, Copyright © 2011 Dan Lowe.
@@ -64,6 +64,10 @@
#include "d_string.h"
+#ifdef TEST
+ #include "CuTest.h"
+#endif
+
/*
* The following section came from:
@@ -145,6 +149,31 @@ DString* d_string_new(const char * startingString) {
}
+#ifdef TEST
+void Test_d_string_new(CuTest* tc) {
+ char * test = "foo";
+
+ DString * result = d_string_new(test);
+
+ CuAssertIntEquals(tc, 3, result->currentStringLength);
+ CuAssertIntEquals(tc, kStringBufferStartingSize, result->currentStringBufferSize);
+ CuAssertStrEquals(tc, test, result->str);
+ CuAssertIntEquals(tc, '\0', result->str[strlen(test)]);
+
+ d_string_free(result, true);
+
+ result = d_string_new(NULL);
+
+ CuAssertIntEquals(tc, 0, result->currentStringLength);
+ CuAssertIntEquals(tc, kStringBufferStartingSize, result->currentStringBufferSize);
+ CuAssertStrEquals(tc, "", result->str);
+ CuAssertIntEquals(tc, '\0', 0);
+
+ d_string_free(result, true);
+}
+#endif
+
+
/// Free dynamic string
char* d_string_free(DString * ripString, bool freeCharacterData) {
if (ripString == NULL) {
@@ -169,234 +198,584 @@ char* d_string_free(DString * ripString, bool freeCharacterData) {
/// Ensure that dynamic string has specified capacity
static void ensureStringBufferCanHold(DString * baseString, size_t newStringSize) {
- size_t newBufferSizeNeeded = newStringSize + 1;
+ if (baseString) {
+ size_t newBufferSizeNeeded = newStringSize + 1;
+
+ if (newBufferSizeNeeded > baseString->currentStringBufferSize) {
+ size_t newBufferSize = baseString->currentStringBufferSize;
+
+ while (newBufferSizeNeeded > newBufferSize) {
+ if (newBufferSize > kStringBufferMaxIncrement) {
+ newBufferSize += kStringBufferMaxIncrement;
+ } else {
+ newBufferSize *= kStringBufferGrowthMultiplier;
+ }
+ }
+
+ char *temp;
+ temp = realloc(baseString->str, newBufferSize);
- if (newBufferSizeNeeded > baseString->currentStringBufferSize) {
- size_t newBufferSize = baseString->currentStringBufferSize;
+ if (temp == NULL) {
+ /* realloc failed */
+ fprintf(stderr, "Error reallocating memory for d_string. Current buffer size %lu.\n", baseString->currentStringBufferSize);
- while (newBufferSizeNeeded > newBufferSize) {
- if (newBufferSize > kStringBufferMaxIncrement) {
- newBufferSize += kStringBufferMaxIncrement;
- } else {
- newBufferSize *= kStringBufferGrowthMultiplier;
+ exit(1);
}
+
+ baseString->str = temp;
+ baseString->currentStringBufferSize = newBufferSize;
}
+ }
+}
- char *temp;
- temp = realloc(baseString->str, newBufferSize);
- if (temp == NULL) {
- /* realloc failed */
- fprintf(stderr, "Error reallocating memory for d_string. Current buffer size %lu.\n", baseString->currentStringBufferSize);
+#ifdef TEST
+void Test_ensureStringBufferCanHold(CuTest* tc) {
+ char * test = "foo";
- exit(1);
- }
+ DString * result = d_string_new(test);
- baseString->str = temp;
- baseString->currentStringBufferSize = newBufferSize;
- }
+ ensureStringBufferCanHold(result, 1024);
+ CuAssertIntEquals(tc, 2048, result->currentStringBufferSize);
+
+ ensureStringBufferCanHold(result, 1024);
+ CuAssertIntEquals(tc, 2048, result->currentStringBufferSize);
+
+ /* This becomes 0 after we add 1 for the '\0' */
+ ensureStringBufferCanHold(result, -1);
+ CuAssertIntEquals(tc, 2048, result->currentStringBufferSize);
+
+ ensureStringBufferCanHold(result, 1024 * 1024 - 1);
+ CuAssertIntEquals(tc, 1024 * 1024, result->currentStringBufferSize);
+
+ ensureStringBufferCanHold(result, 1024 * 1024 - 1);
+ CuAssertIntEquals(tc, 1024 * 1024, result->currentStringBufferSize);
+
+ ensureStringBufferCanHold(NULL, 1024);
+
+ d_string_free(result, true);
}
+#endif
/// Append null-terminated string to end of dynamic string
void d_string_append(DString * baseString, const char * appendedString) {
- size_t appendedStringLength = strlen(appendedString);
+ if (baseString && appendedString) {
+ size_t appendedStringLength = strlen(appendedString);
- if ((appendedString != NULL) && (appendedStringLength > 0)) {
- size_t newStringLength = baseString->currentStringLength + appendedStringLength;
- ensureStringBufferCanHold(baseString, newStringLength);
+ if (appendedStringLength > 0) {
+ size_t newStringLength = baseString->currentStringLength + appendedStringLength;
+ ensureStringBufferCanHold(baseString, newStringLength);
- /* We already know where the current string ends, so pass that as the starting address for strncat */
- strncat(baseString->str + baseString->currentStringLength, appendedString, appendedStringLength);
- baseString->currentStringLength = newStringLength;
+ /* We already know where the current string ends, so pass that as the starting address for strncat */
+ strncat(baseString->str + baseString->currentStringLength, appendedString, appendedStringLength);
+ baseString->currentStringLength = newStringLength;
+ }
}
}
+#ifdef TEST
+void Test_d_string_append(CuTest* tc) {
+ char * test = "foo";
+
+ DString * result = d_string_new(test);
+
+ d_string_append(result, "bar");
+ CuAssertStrEquals(tc, "foobar", result->str);
+
+ d_string_append(result, "");
+ CuAssertStrEquals(tc, "foobar", result->str);
+
+ d_string_append(result, NULL);
+ CuAssertStrEquals(tc, "foobar", result->str);
+
+ d_string_append(NULL, "foo");
+
+ d_string_free(result, true);
+}
+#endif
+
+
/// 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);
+ if (baseString && appendedCharacter) {
+ size_t newSizeNeeded = baseString->currentStringLength + 1;
+ ensureStringBufferCanHold(baseString, newSizeNeeded);
+
+ baseString->str[baseString->currentStringLength] = appendedCharacter;
+ baseString->currentStringLength++;
+ baseString->str[baseString->currentStringLength] = '\0';
+ }
+}
+
+
+#ifdef TEST
+void Test_d_string_append_c(CuTest* tc) {
+ char * test = "foo";
- baseString->str[baseString->currentStringLength] = appendedCharacter;
- baseString->currentStringLength++;
- baseString->str[baseString->currentStringLength] = '\0';
+ DString * result = d_string_new(test);
+
+ d_string_append_c(result, 'z');
+ CuAssertStrEquals(tc, "fooz", result->str);
+ CuAssertIntEquals(tc, 4, result->currentStringLength);
+
+ d_string_append_c(result, 0);
+ CuAssertStrEquals(tc, "fooz", result->str);
+ CuAssertIntEquals(tc, 4, result->currentStringLength);
+
+ d_string_append_c(NULL, 'f');
+
+ d_string_free(result, true);
}
+#endif
/// 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);
+ if (baseString && appendedChars) {
+ if (bytes == -1) {
+ // This is the same as regular append
+ d_string_append(baseString, appendedChars);
+ } else {
+ if (appendedChars) {
+ size_t newSizeNeeded = baseString->currentStringLength + bytes;
+ ensureStringBufferCanHold(baseString, newSizeNeeded);
+
+ memcpy(baseString->str + baseString->currentStringLength, appendedChars, bytes);
+
+ baseString->currentStringLength = newSizeNeeded;
+ baseString->str[baseString->currentStringLength] = '\0';
+ }
+ }
+ }
+}
+
+
+#ifdef TEST
+void Test_d_string_append_c_array(CuTest* tc) {
+ char * test = "foo";
- memcpy(baseString->str + baseString->currentStringLength, appendedChars, bytes);
+ DString * result = d_string_new(test);
- baseString->currentStringLength = newSizeNeeded;
- baseString->str[baseString->currentStringLength] = '\0';
+ d_string_append_c_array(result, "bar", 3);
+ CuAssertStrEquals(tc, "foobar", result->str);
+ CuAssertIntEquals(tc, 6, result->currentStringLength);
+
+ d_string_append_c_array(result, "baz", -1);
+ CuAssertStrEquals(tc, "foobarbaz", result->str);
+ CuAssertIntEquals(tc, 9, result->currentStringLength);
+
+ d_string_append_c_array(result, NULL, 0);
+ CuAssertStrEquals(tc, "foobarbaz", result->str);
+ CuAssertIntEquals(tc, 9, result->currentStringLength);
+
+ d_string_append_c_array(result, NULL, -1);
+ CuAssertStrEquals(tc, "foobarbaz", result->str);
+ CuAssertIntEquals(tc, 9, result->currentStringLength);
+
+ d_string_append_c_array(NULL, "foo", -1);
+
+ d_string_free(result, true);
}
+#endif
/// 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);
+ if (baseString && format) {
+ va_list args;
+ va_start(args, format);
- char* formattedString = NULL;
- vasprintf(&formattedString, format, args);
+ char* formattedString = NULL;
+ vasprintf(&formattedString, format, args);
- if (formattedString != NULL) {
- d_string_append(baseString, formattedString);
- free(formattedString);
+ if (formattedString != NULL) {
+ d_string_append(baseString, formattedString);
+ free(formattedString);
+ }
+
+ va_end(args);
}
+}
+
+
+#ifdef TEST
+void Test_d_string_append_printf(CuTest* tc) {
+ char * test = "foo";
- va_end(args);
+ DString * result = d_string_new(test);
+
+ d_string_append_printf(result, "%dbar%d", 5, 7);
+ CuAssertStrEquals(tc, "foo5bar7", result->str);
+ CuAssertIntEquals(tc, 8, result->currentStringLength);
+
+ d_string_append_printf(result, NULL);
+ CuAssertStrEquals(tc, "foo5bar7", result->str);
+ CuAssertIntEquals(tc, 8, result->currentStringLength);
+
+ d_string_append_printf(result, NULL, 5, 7);
+ CuAssertStrEquals(tc, "foo5bar7", result->str);
+ CuAssertIntEquals(tc, 8, result->currentStringLength);
+
+ d_string_append_printf(NULL, "foo");
+
+ d_string_free(result, true);
}
+#endif
/// Prepend null-terminated string to end of dynamic string
void d_string_prepend(DString * baseString, const char * prependedString) {
- size_t prependedStringLength = strlen(prependedString);
+ if (baseString && prependedString) {
+ size_t prependedStringLength = strlen(prependedString);
- if ((prependedString != NULL) && (prependedStringLength > 0)) {
- size_t newStringLength = baseString->currentStringLength + prependedStringLength;
- ensureStringBufferCanHold(baseString, newStringLength);
+ if (prependedStringLength > 0) {
+ size_t newStringLength = baseString->currentStringLength + prependedStringLength;
+ ensureStringBufferCanHold(baseString, newStringLength);
- memmove(baseString->str + prependedStringLength, baseString->str, baseString->currentStringLength);
- strncpy(baseString->str, prependedString, prependedStringLength);
- baseString->currentStringLength = newStringLength;
- baseString->str[baseString->currentStringLength] = '\0';
+ memmove(baseString->str + prependedStringLength, baseString->str, baseString->currentStringLength);
+ strncpy(baseString->str, prependedString, prependedStringLength);
+ baseString->currentStringLength = newStringLength;
+ baseString->str[baseString->currentStringLength] = '\0';
+ }
}
}
+#ifdef TEST
+void Test_d_string_prepend(CuTest* tc) {
+ char * test = "foo";
+
+ DString * result = d_string_new(test);
+
+ d_string_prepend(result, "bar");
+ CuAssertStrEquals(tc, "barfoo", result->str);
+ CuAssertIntEquals(tc, 6, result->currentStringLength);
+
+ d_string_prepend(result, NULL);
+ CuAssertStrEquals(tc, "barfoo", result->str);
+ CuAssertIntEquals(tc, 6, result->currentStringLength);
+
+ d_string_prepend(NULL, "bar");
+
+ d_string_free(result, true);
+}
+#endif
+
+
/// Insert null-terminated string inside dynamic string
void d_string_insert(DString * baseString, size_t pos, const char * insertedString) {
- size_t insertedStringLength = strlen(insertedString);
+ if (baseString && insertedString) {
+ size_t insertedStringLength = strlen(insertedString);
+
+ if (insertedStringLength > 0) {
+ if (pos > baseString->currentStringLength) {
+ pos = baseString->currentStringLength;
+ }
+
+ size_t newStringLength = baseString->currentStringLength + insertedStringLength;
+ ensureStringBufferCanHold(baseString, newStringLength);
+
+ /* Shift following string to 'right' */
+ memmove(baseString->str + pos + insertedStringLength, baseString->str + pos, baseString->currentStringLength - pos);
+ strncpy(baseString->str + pos, insertedString, insertedStringLength);
+ baseString->currentStringLength = newStringLength;
+ baseString->str[baseString->currentStringLength] = '\0';
+ }
+ }
+}
+
+
+#ifdef TEST
+void Test_d_string_insert(CuTest* tc) {
+ char * test = "foo";
+
+ DString * result = d_string_new(test);
+
+ d_string_insert(result, 2, "bar");
+ CuAssertStrEquals(tc, "fobaro", result->str);
+ CuAssertIntEquals(tc, 6, result->currentStringLength);
+
+ d_string_insert(result, -1, "bar");
+ CuAssertStrEquals(tc, "fobarobar", result->str);
+ CuAssertIntEquals(tc, 9, result->currentStringLength);
+
+ d_string_insert(result, -1, NULL);
+ CuAssertStrEquals(tc, "fobarobar", result->str);
+ CuAssertIntEquals(tc, 9, result->currentStringLength);
+
+ d_string_insert(NULL, 0, NULL);
- if ((insertedString != NULL) && (insertedStringLength > 0)) {
+ d_string_free(result, true);
+}
+#endif
+
+
+/// Insert single character inside dynamic string
+void d_string_insert_c(DString * baseString, size_t pos, char insertedCharacter) {
+ if (baseString && insertedCharacter) {
if (pos > baseString->currentStringLength) {
pos = baseString->currentStringLength;
}
- size_t newStringLength = baseString->currentStringLength + insertedStringLength;
- ensureStringBufferCanHold(baseString, newStringLength);
+ size_t newSizeNeeded = baseString->currentStringLength + 1;
+ ensureStringBufferCanHold(baseString, newSizeNeeded);
/* Shift following string to 'right' */
- memmove(baseString->str + pos + insertedStringLength, baseString->str + pos, baseString->currentStringLength - pos);
- strncpy(baseString->str + pos, insertedString, insertedStringLength);
- baseString->currentStringLength = newStringLength;
+ memmove(baseString->str + pos + 1, baseString->str + pos, baseString->currentStringLength - pos);
+
+ baseString->str[pos] = insertedCharacter;
+ baseString->currentStringLength++;
baseString->str[baseString->currentStringLength] = '\0';
}
}
-/// 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;
- }
+#ifdef TEST
+void Test_d_string_insert_c(CuTest* tc) {
+ char * test = "foo";
+
+ DString * result = d_string_new(test);
- size_t newSizeNeeded = baseString->currentStringLength + 1;
- ensureStringBufferCanHold(baseString, newSizeNeeded);
+ d_string_insert_c(result, 2, 'b');
+ CuAssertStrEquals(tc, "fobo", result->str);
+ CuAssertIntEquals(tc, 4, result->currentStringLength);
- /* Shift following string to 'right' */
- memmove(baseString->str + pos + 1, baseString->str + pos, baseString->currentStringLength - pos);
+ d_string_insert_c(result, -1, 'z');
+ CuAssertStrEquals(tc, "foboz", result->str);
+ CuAssertIntEquals(tc, 5, result->currentStringLength);
- baseString->str[pos] = insertedCharacter;
- baseString->currentStringLength++;
- baseString->str[baseString->currentStringLength] = '\0';
+ d_string_insert_c(result, 3, 0);
+ CuAssertStrEquals(tc, "foboz", result->str);
+ CuAssertIntEquals(tc, 5, result->currentStringLength);
+
+ d_string_insert_c(NULL, 0, 0);
+
+ d_string_free(result, true);
}
+#endif
/// 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);
+ if (baseString && format) {
+ va_list args;
+ va_start(args, format);
- char* formattedString = NULL;
- vasprintf(&formattedString, format, args);
+ char* formattedString = NULL;
+ vasprintf(&formattedString, format, args);
- if (formattedString != NULL) {
- d_string_insert(baseString, pos, formattedString);
- free(formattedString);
+ if (formattedString != NULL) {
+ d_string_insert(baseString, pos, formattedString);
+ free(formattedString);
+ }
+
+ va_end(args);
}
+}
+
+
+#ifdef TEST
+void Test_d_string_insert_printf(CuTest* tc) {
+ char * test = "foo";
+
+ DString * result = d_string_new(test);
+
+ d_string_insert_printf(result, 2, "%dbar%d", 5, 7);
+ CuAssertStrEquals(tc, "fo5bar7o", result->str);
+ CuAssertIntEquals(tc, 8, result->currentStringLength);
+
+ d_string_insert_printf(result, -1, "z", 5, 7);
+ CuAssertStrEquals(tc, "fo5bar7oz", result->str);
+ CuAssertIntEquals(tc, 9, result->currentStringLength);
- va_end(args);
+ d_string_insert_printf(NULL, 0, NULL);
+
+ d_string_free(result, true);
}
+#endif
/// Erase portion of dynamic string
void d_string_erase(DString * baseString, size_t pos, size_t len) {
- if ((pos > baseString->currentStringLength) || (len <= 0)) {
- return;
- }
+ if (baseString) {
+ if ((pos > baseString->currentStringLength) || (len <= 0)) {
+ return;
+ }
- if ((pos + len) >= baseString->currentStringLength) {
- len = -1;
- }
+ if ((pos + len) >= baseString->currentStringLength) {
+ len = -1;
+ }
- if (len == -1) {
- baseString->currentStringLength = pos;
- } else {
- memmove(baseString->str + pos, baseString->str + pos + len, baseString->currentStringLength - pos - len);
- baseString->currentStringLength -= len;
+ if (len == -1) {
+ baseString->currentStringLength = pos;
+ } else {
+ memmove(baseString->str + pos, baseString->str + pos + len, baseString->currentStringLength - pos - len);
+ baseString->currentStringLength -= len;
+ }
+
+ baseString->str[baseString->currentStringLength] = '\0';
}
+}
+
+
+#ifdef TEST
+void Test_d_string_erase(CuTest* tc) {
+ char * test = "foobar";
+
+ DString * result = d_string_new(test);
+
+ d_string_erase(result, 2, 1);
+ CuAssertStrEquals(tc, "fobar", result->str);
+ CuAssertIntEquals(tc, 5, result->currentStringLength);
- baseString->str[baseString->currentStringLength] = '\0';
+ d_string_erase(result, -1, -1);
+ CuAssertStrEquals(tc, "fobar", result->str);
+ CuAssertIntEquals(tc, 5, result->currentStringLength);
+
+ d_string_erase(result, 2, -1);
+ CuAssertStrEquals(tc, "fo", result->str);
+ CuAssertIntEquals(tc, 2, result->currentStringLength);
+
+ d_string_erase(NULL, 0, 0);
+
+ d_string_free(result, true);
}
+#endif
+
/// Copy a portion of dynamic string
char * d_string_copy_substring(DString * d, size_t start, size_t len) {
- char * result;
+ if (d) {
+ char * result;
+
+ if ((len == -1) && (start < d->currentStringLength)) {
+ 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';
- if (len == -1) {
- len = d->currentStringLength - start;
+ return result;
} 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;
- }
+ return NULL;
}
+}
+
+
+#ifdef TEST
+void Test_d_string_copy_substring(CuTest* tc) {
+ char * test = "foobar";
+
+ DString * result = d_string_new(test);
+
+ test = d_string_copy_substring(result, 0, -1);
+ CuAssertStrEquals(tc, "foobar", test);
+ free(test);
+
+ test = d_string_copy_substring(result, 2, 3);
+ CuAssertStrEquals(tc, "oba", test);
+ free(test);
- result = malloc(len + 1);
- strncpy(result, &d->str[start], len);
- result[len] = '\0';
+ test = d_string_copy_substring(result, 8, 2);
+ CuAssertStrEquals(tc, NULL, test);
+ free(test);
- return result;
+ test = d_string_copy_substring(result, -1, -1);
+ CuAssertStrEquals(tc, NULL, test);
+ free(test);
+
+ test = d_string_copy_substring(NULL, -1, -1);
+ CuAssertStrEquals(tc, NULL, test);
+
+ d_string_free(result, true);
}
+#endif
/// Replace occurences of "original" with "replace" inside the specified range
/// Returns the change in overall length
long d_string_replace_text_in_range(DString * d, size_t pos, size_t len, const char * original, const char * replace) {
- long delta = 0; // Overall change in length
+ if (d && original && replace) {
+ long delta = 0; // Overall change in length
+
+ long len_o = strlen(original);
+ long len_r = strlen(replace);
+ long change = len_r - len_o; // Change in length for each replacement
+
+ size_t stop;
+
+ if (len == -1) {
+ stop = d->currentStringLength;
+ } else {
+ stop = pos + len;
- long len_o = strlen(original);
- long len_r = strlen(replace);
- long change = len_r - len_o; // Change in length for each replacement
+ if (stop > d->currentStringLength) {
+ stop = d->currentStringLength;
+ }
+ }
+
+ char * match = strstr(&(d->str[pos]), original);
- size_t stop;
+ while (match && (match - d->str < stop)) {
+ pos = match - d->str;
+ d_string_erase(d, match - d->str, len_o);
+ d_string_insert(d, match - d->str, replace);
+
+ delta += change;
+ stop += change;
+ match = strstr(d->str + pos + len_r, original);
+ }
- if (len == -1) {
- stop = d->currentStringLength;
+ return delta;
} else {
- stop = pos + len;
+ return 0;
}
+}
- char * match = strstr(&(d->str[pos]), original);
- while (match && (match - d->str < stop)) {
- pos = match - d->str;
- d_string_erase(d, match - d->str, len_o);
- d_string_insert(d, match - d->str, replace);
+#ifdef TEST
+void Test_d_string_replace_text_in_range(CuTest* tc) {
+ char * test = "foobarfoobarfoo";
+ long delta = 0;
- delta += change;
- stop += change;
- match = strstr(d->str + pos + len_r, original);
- }
+ DString * result = d_string_new(test);
- return delta;
-}
+ delta = d_string_replace_text_in_range(result, 100, 3, "foo", "zapz");
+ CuAssertIntEquals(tc, 15, result->currentStringLength);
+ CuAssertStrEquals(tc, "foobarfoobarfoo", result->str);
+ CuAssertIntEquals(tc, delta, 0);
+
+ delta = d_string_replace_text_in_range(result, 0, 3, "foo", "zapz");
+ CuAssertIntEquals(tc, 16, result->currentStringLength);
+ CuAssertStrEquals(tc, "zapzbarfoobarfoo", result->str);
+ CuAssertIntEquals(tc, delta, 1);
+
+ delta = d_string_replace_text_in_range(result, 0, 100, "foo", "zapz");
+ CuAssertIntEquals(tc, 18, result->currentStringLength);
+ CuAssertStrEquals(tc, "zapzbarzapzbarzapz", result->str);
+ CuAssertIntEquals(tc, delta, 2);
+ delta = d_string_replace_text_in_range(result, 0, -1, NULL, "zap");
+ CuAssertIntEquals(tc, 18, result->currentStringLength);
+ CuAssertStrEquals(tc, "zapzbarzapzbarzapz", result->str);
+ CuAssertIntEquals(tc, delta, 0);
+
+ d_string_replace_text_in_range(result, 0, -1, "foo", NULL);
+ CuAssertIntEquals(tc, 18, result->currentStringLength);
+ CuAssertStrEquals(tc, "zapzbarzapzbarzapz", result->str);
+
+ d_string_replace_text_in_range(NULL, 0, -1, "foo", NULL);
+
+ d_string_free(result, true);
+}
+#endif
diff --git a/Sources/libMultiMarkdown/file.c b/Sources/libMultiMarkdown/file.c
index cc4edabf..e87bdcd9 100644
--- a/Sources/libMultiMarkdown/file.c
+++ b/Sources/libMultiMarkdown/file.c
@@ -4,11 +4,11 @@
@file file.c
- @brief
+ @brief
@author Fletcher T. Penney
- @bug
+ @bug
**/
@@ -18,38 +18,38 @@
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.
-
+
uthash library:
Copyright (c) 2005-2016, Troy D. Hanson
-
+
Licensed under Revised BSD license
-
+
miniz library:
Copyright 2013-2014 RAD Game Tools and Valve Software
Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
-
+
Licensed under the MIT license
-
+
argtable3 library:
Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
All rights reserved.
-
+
Licensed under the Revised BSD 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
@@ -57,10 +57,10 @@
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.
@@ -68,10 +68,10 @@
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.
-
-
+
+
## Revised BSD License ##
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -85,7 +85,7 @@
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
@@ -97,7 +97,7 @@
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.
-
+
*/
diff --git a/Sources/libMultiMarkdown/file.h b/Sources/libMultiMarkdown/file.h
index 6c13a3af..03df7360 100644
--- a/Sources/libMultiMarkdown/file.h
+++ b/Sources/libMultiMarkdown/file.h
@@ -4,11 +4,11 @@
@file file.h
- @brief
+ @brief
@author Fletcher T. Penney
- @bug
+ @bug
**/
@@ -18,38 +18,38 @@
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.
-
+
uthash library:
Copyright (c) 2005-2016, Troy D. Hanson
-
+
Licensed under Revised BSD license
-
+
miniz library:
Copyright 2013-2014 RAD Game Tools and Valve Software
Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
-
+
Licensed under the MIT license
-
+
argtable3 library:
Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
All rights reserved.
-
+
Licensed under the Revised BSD 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
@@ -57,10 +57,10 @@
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.
@@ -68,10 +68,10 @@
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.
-
-
+
+
## Revised BSD License ##
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -85,7 +85,7 @@
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
@@ -97,7 +97,7 @@
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.
-
+
*/
@@ -144,4 +144,10 @@ void split_path_file(char ** dir, char ** file, const char * path);
// Convert argument to absolute path
char * absolute_path_for_argument(const char * arg);
+
+#if (defined(_WIN32) || defined(__WIN32__))
+ // Windows does not know realpath(), so we need a "windows port"
+ char *realpath(const char *path, char *resolved_path);
+#endif
+
#endif
diff --git a/Sources/libMultiMarkdown/fodt.c b/Sources/libMultiMarkdown/fodt.c
deleted file mode 100644
index d98b1647..00000000
--- a/Sources/libMultiMarkdown/fodt.c
+++ /dev/null
@@ -1,2290 +0,0 @@
-/**
-
- MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
-
- @file fodt.c
-
- @brief Convert token tree to Flat OpenDocument (ODF/FODT) 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
-#include
-#include
-#include
-
-#include "char.h"
-#include "i18n.h"
-#include "fodt.h"
-#include "parser.h"
-#include "scanners.h"
-
-#define print(x) d_string_append(out, x)
-#define print_const(x) d_string_append_c_array(out, x, sizeof(x) - 1)
-#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]), t->len)
-#define print_localized(x) mmd_print_localized_char_odf(out, x, scratch)
-
-
-/// strdup() not available on all platforms
-static char * my_strdup(const char * source) {
- if (source == NULL) {
- return NULL;
- }
-
- char * result = malloc(strlen(source) + 1);
-
- if (result) {
- strcpy(result, source);
- }
-
- return result;
-}
-
-
-void mmd_print_char_odf(DString * out, char c) {
- switch (c) {
- case '"':
- print_const(""");
- break;
-
- case '&':
- print_const("&");
- break;
-
- case '<':
- print_const("<");
- break;
-
- case '>':
- print_const(">");
- break;
-
- case '\t':
- print_const(" ");
-
- default:
- print_char(c);
- break;
- }
-}
-
-
-void mmd_print_string_odf(DString * out, const char * str) {
- if (str == NULL) {
- return;
- }
-
- while (*str != '\0') {
- mmd_print_char_odf(out, *str);
- str++;
- }
-}
-
-
-void mmd_print_localized_char_odf(DString * out, unsigned short type, scratch_pad * scratch) {
- switch (type) {
- case DASH_N:
- print_const("–");
- break;
-
- case DASH_M:
- print_const("—");
- break;
-
- case ELLIPSIS:
- print_const("…");
- break;
-
- case APOSTROPHE:
- print_const("’");
- break;
-
- case QUOTE_LEFT_SINGLE:
- switch (scratch->quotes_lang) {
- case SWEDISH:
- print( "’");
- break;
-
- case FRENCH:
- print_const("'");
- break;
-
- case GERMAN:
- print_const("‚");
- break;
-
- case GERMANGUILL:
- print_const("›");
- break;
-
- default:
- print_const("‘");
- }
-
- break;
-
- case QUOTE_RIGHT_SINGLE:
- switch (scratch->quotes_lang) {
- case GERMAN:
- print_const("‘");
- break;
-
- case GERMANGUILL:
- print_const("‹");
- break;
-
- default:
- print_const("’");
- }
-
- break;
-
- case QUOTE_LEFT_DOUBLE:
- switch (scratch->quotes_lang) {
- case DUTCH:
- case GERMAN:
- print_const("„");
- break;
-
- case GERMANGUILL:
- print_const("»");
- break;
-
- case FRENCH:
- print_const("«");
- break;
-
- case SWEDISH:
- print( "”");
- break;
-
- default:
- print_const("“");
- }
-
- break;
-
- case QUOTE_RIGHT_DOUBLE:
- switch (scratch->quotes_lang) {
- case GERMAN:
- print_const("“");
- break;
-
- case GERMANGUILL:
- print_const("«");
- break;
-
- case FRENCH:
- print_const("»");
- break;
-
- case SWEDISH:
- case DUTCH:
- default:
- print_const("”");
- }
-
- break;
- }
-}
-
-
-void mmd_export_link_odf(DString * out, const char * source, token * text, link * link, scratch_pad * scratch) {
- if (link->url) {
- print_const("url);
- print_const("\"");
- } else {
- print_const("title && link->title[0] != '\0') {
- print_const(" office:name=\"");
- mmd_print_string_odf(out, link->title);
- print_const("\"");
- }
-
- print_const(">");
-
- // If we're printing contents of bracket as text, then ensure we include it all
- if (text && text->child && text->child->len > 1) {
- text->child->next->start--;
- text->child->next->len++;
- }
-
- if (text && text->child) {
- mmd_export_token_tree_odf(out, source, text->child, scratch);
- }
-
- print_const(" ");
-}
-
-
-static char * correct_dimension_units(char *original) {
- char *result;
- int i;
-
- result = my_strdup(original);
-
- for (i = 0; result[i]; i++) {
- result[i] = tolower(result[i]);
- }
-
- if (strstr(&result[strlen(result) - 2], "px")) {
- result[strlen(result) - 2] = '\0';
- strcat(result, "pt");
- }
-
- return result;
-}
-
-
-void mmd_export_image_odf(DString * out, const char * source, token * text, link * link, scratch_pad * scratch, bool is_figure) {
- attr * a = link->attributes;
- char * height = NULL;
- char * width = NULL;
-
- print_const("key) == 0) {
- height = correct_dimension_units(a->value);
- } else if (strcmp("width", a->key) == 0) {
- width = correct_dimension_units(a->value);
- }
-
- a = a->next;
- }
-
- if (width) {
- printf(" svg:width=\"%s\">\n", width);
- } else {
- print_const(" svg:width=\"95%\">\n");
- }
-
- print_const("url) {
- printf(">\nurl);
- }
-
- print_const(" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\" draw:filter-name=\"<All formats>\"/>\n ");
-
- if (is_figure) {
- if (text) {
- print_const("\nFigure Update Fields to calculate numbers : ");
- mmd_export_token_tree_odf(out, source, text->child, scratch);
- print_const(" ");
- }
- }
-
- print_const("\n \n");
-
- scratch->padded = 1;
-}
-
-
-
-void mmd_export_toc_entry_odf(DString * out, const char * source, scratch_pad * scratch, size_t * counter, short level) {
- token * entry, * next;
- short entry_level, next_level;
- char * temp_char;
-
- // Iterate over tokens
- while (*counter < scratch->header_stack->size) {
- // Get token for header
- entry = stack_peek_index(scratch->header_stack, *counter);
- entry_level = raw_level_for_header(entry);
-
- if (entry_level >= level) {
- // This entry is a direct descendant of the parent
- temp_char = label_from_header(source, entry);
- printf("", temp_char);
- mmd_export_token_tree_odf(out, source, entry->child, scratch);
- print_const(" 1 \n");
-
- if (*counter < scratch->header_stack->size - 1) {
- next = stack_peek_index(scratch->header_stack, *counter + 1);
- next_level = next->type - BLOCK_H1 + 1;
-
- if (next_level > entry_level) {
- // This entry has children
- (*counter)++;
- mmd_export_toc_entry_odf(out, source, scratch, counter, entry_level + 1);
- }
- }
-
- free(temp_char);
- } else if (entry_level < level ) {
- // If entry < level, exit this level
- // Decrement counter first, so that we can test it again later
- (*counter)--;
- break;
- }
-
- // Increment counter
- (*counter)++;
- }
-}
-
-void mmd_export_toc_odf(DString * out, const char * source, scratch_pad * scratch) {
- size_t counter = 0;
-
- // TODO: Could use LC to internationalize this
- print_const("\n");
- print_const("\n");
- print_const("Table of Contents \n");
- print_const(" \n\n");
- print_const("\n");
- print_const("Table of Contents \n");
- print_const(" \n");
-
- mmd_export_toc_entry_odf(out, source, scratch, &counter, 0);
-
- print_const(" \n \n\n");
-}
-
-
-void mmd_export_token_odf(DString * out, const char * source, token * t, scratch_pad * scratch) {
- if (t == NULL) {
- return;
- }
-
- short temp_short;
- short temp_short2;
- short temp_short3;
- link * temp_link = NULL;
- char * temp_char = NULL;
- char * temp_char2 = NULL;
- bool temp_bool = 0;
- token * temp_token = NULL;
- footnote * temp_note = NULL;
-
- switch (t->type) {
- case DOC_START_TOKEN:
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- break;
-
- case AMPERSAND:
- case AMPERSAND_LONG:
- print_const("&");
- break;
-
- case ANGLE_LEFT:
- print_const("<");
- break;
-
- case ANGLE_RIGHT:
- print_const(">");
- 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_const("");
- } else {
- print_const(" ");
- }
-
- break;
-
- case BLOCK_BLOCKQUOTE:
- pad(out, 2, scratch);
- scratch->padded = 2;
- temp_short2 = scratch->odf_para_type;
-
- scratch->odf_para_type = BLOCK_BLOCKQUOTE;
-
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- scratch->padded = 0;
- scratch->odf_para_type = temp_short2;
- break;
-
- case BLOCK_CODE_FENCED:
- pad(out, 2, scratch);
-
- temp_char = get_fence_language_specifier(t->child->child, source);
-
- if (temp_char) {
- if (strncmp("{=", temp_char, 2) == 0) {
- // Raw source
- if (raw_filter_text_matches(temp_char, FORMAT_ODT)) {
- switch (t->child->tail->type) {
- case LINE_FENCE_BACKTICK_3:
- case LINE_FENCE_BACKTICK_4:
- case LINE_FENCE_BACKTICK_5:
- temp_token = t->child->tail;
- break;
-
- default:
- temp_token = NULL;
- }
-
- if (temp_token) {
- d_string_append_c_array(out, &source[t->child->next->start], temp_token->start - t->child->next->start);
- scratch->padded = 1;
- } else {
- d_string_append_c_array(out, &source[t->child->start + t->child->len], t->start + t->len - t->child->next->start);
- scratch->padded = 0;
- }
- }
-
- free(temp_char);
- break;
- }
- }
-
- free(temp_char);
-
- print_const("");
- mmd_export_token_tree_odf_raw(out, source, t->child->next, scratch);
- print_const(" ");
- scratch->padded = 0;
- break;
-
- case BLOCK_CODE_INDENTED:
- pad(out, 2, scratch);
- print_const("");
- mmd_export_token_tree_odf_raw(out, source, t->child, scratch);
- print_const(" ");
- scratch->padded = 0;
- break;
-
- case BLOCK_DEFINITION:
- pad(out, 2, scratch);
- temp_short2 = scratch->odf_para_type;
- scratch->odf_para_type = BLOCK_DEFINITION;
-
- temp_short = scratch->list_is_tight;
-
- if (!(t->child->next && (t->child->next->type == BLOCK_EMPTY) && t->child->next->next)) {
- scratch->list_is_tight = true;
- }
-
- if (t->child && t->child->type != BLOCK_PARA) {
- print_const("");
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- print_const(" ");
- } else {
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- }
-
- scratch->padded = 0;
-
- scratch->list_is_tight = temp_short;
- scratch->odf_para_type = temp_short2;
- break;
-
- case BLOCK_DEFLIST:
- pad(out, 2, scratch);
-
- // Group consecutive definition lists into a single list.
- // lemon's LALR(1) parser can't properly handle this (to my understanding).
-
-// if (!(t->prev && (t->prev->type == BLOCK_DEFLIST)))
-// print_const("\n");
-
- scratch->padded = 2;
-
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- pad(out, 1, scratch);
-
-// if (!(t->next && (t->next->type == BLOCK_DEFLIST)))
-// print_const("
\n");
-
- scratch->padded = 1;
- break;
-
- case BLOCK_EMPTY:
- break;
-
- case BLOCK_H1:
- case BLOCK_H2:
- case BLOCK_H3:
- case BLOCK_H4:
- case BLOCK_H5:
- case BLOCK_H6:
- case BLOCK_SETEXT_1:
- case BLOCK_SETEXT_2:
- pad(out, 2, scratch);
-
- switch (t->type) {
- case BLOCK_SETEXT_1:
- temp_short = 1;
- break;
-
- case BLOCK_SETEXT_2:
- temp_short = 2;
- break;
-
- default:
- temp_short = t->type - BLOCK_H1 + 1;
- }
-
- printf("", temp_short + scratch->base_header_level - 1);
-
- if (scratch->extensions & EXT_NO_LABELS) {
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- } else {
- temp_char = label_from_header(source, t);
- printf("", temp_char);
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- //printf("", temp_char);
- free(temp_char);
- }
-
- print_const(" ");
- scratch->padded = 0;
- break;
-
- case BLOCK_HR:
- pad(out, 2, scratch);
- print_const("");
- scratch->padded = 0;
- break;
-
- case BLOCK_HTML:
- // Don't print HTML
- 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_const("");
- scratch->padded = 1;
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- pad(out, 2, scratch);
- print_const(" ");
- 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_const("");
- scratch->padded = 1;
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- pad(out, 2, scratch);
- print_const(" ");
- scratch->padded = 0;
- scratch->list_is_tight = temp_short;
- break;
-
- case BLOCK_LIST_ITEM:
- pad(out, 2, scratch);
- print_const("\n");
- scratch->padded = 2;
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- print_const(" ");
- scratch->padded = 0;
- break;
-
- case BLOCK_LIST_ITEM_TIGHT:
- pad(out, 2, scratch);
- print_const("\n");
-
- if (t->child && t->child->type != BLOCK_PARA) {
- print_const("\n");
- }
-
- scratch->padded = 2;
- mmd_export_token_tree_odf(out, source, t->child, scratch);
-
- if (t->child && t->child->type != BLOCK_PARA) {
- print_const(" ");
- }
-
- print_const(" ");
- scratch->padded = 0;
- break;
-
- case BLOCK_META:
- break;
-
- case BLOCK_PARA:
- pad(out, 2, scratch);
- print_const("odf_para_type) {
- case BLOCK_BLOCKQUOTE:
- case BLOCK_DEFINITION:
- print_const(" text:style-name=\"Quotations\">");
- break;
-
- case PAIR_BRACKET_ABBREVIATION:
- case PAIR_BRACKET_CITATION:
- case PAIR_BRACKET_FOOTNOTE:
- case PAIR_BRACKET_GLOSSARY:
- print_const(" text:style-name=\"Footnote\">");
- break;
-
- default:
- print_const(" text:style-name=\"Standard\">");
- break;
- }
-
- mmd_export_token_tree_odf(out, source, t->child, scratch);
-
- print_const(" ");
- scratch->padded = 0;
- break;
-
- case BLOCK_TABLE:
- pad(out, 2, scratch);
- print_const("\n");
-
- scratch->padded = 2;
- read_table_column_alignments(source, t, scratch);
-
- for (int i = 0; i < scratch->table_column_count; ++i) {
- print_const(" \n");
-// switch (scratch->table_alignment[i]) {
-// case 'l':
-// print_const(" \n");
-// break;
-// case 'L':
-// print_const(" \n");
-// break;
-// case 'r':
-// print_const(" \n");
-// break;
-// case 'R':
-// print_const(" \n");
-// break;
-// case 'c':
-// print_const(" \n");
-// break;
-// case 'C':
-// print_const(" \n");
-// break;
-// default:
-// print_const(" \n");
-// break;
-// }
- }
-
- scratch->padded = 1;
-
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- pad(out, 1, scratch);
- print_const(" \n");
-
- // Are we followed by a caption?
- if (table_has_caption(t)) {
- temp_token = t->next->child;
-
- if (temp_token->next &&
- temp_token->next->type == PAIR_BRACKET) {
- temp_token = temp_token->next;
- }
-
- temp_char = label_from_token(source, temp_token);
- printf("Table Update Fields to calculate numbers :", temp_char);
-
- t->next->child->child->type = TEXT_EMPTY;
- t->next->child->child->mate->type = TEXT_EMPTY;
- mmd_export_token_tree_odf(out, source, t->next->child->child, scratch);
-
- printf(" \n", temp_char);
-
- free(temp_char);
- temp_short = 1;
- } else {
- temp_short = 0;
- }
-
- scratch->padded = 0;
- scratch->skip_token = temp_short;
-
- break;
-
- case BLOCK_TABLE_HEADER:
- pad(out, 2, scratch);
- scratch->in_table_header = 1;
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- scratch->in_table_header = 0;
- scratch->padded = 1;
- break;
-
- case BLOCK_TABLE_SECTION:
- pad(out, 2, scratch);
- scratch->padded = 2;
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- scratch->padded = 0;
- break;
-
- case BLOCK_TOC:
- pad(out, 2, scratch);
-
- mmd_export_toc_odf(out, source, scratch);
-
- scratch->padded = 1;
- break;
-
- case BLOCK_TERM:
- pad(out, 2, scratch);
- print_const("");
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- print_const(" \n");
- scratch->padded = 2;
- break;
-
- case BRACE_DOUBLE_LEFT:
- print_const("{{");
- break;
-
- case BRACE_DOUBLE_RIGHT:
- print_const("}}");
- break;
-
- case BRACKET_ABBREVIATION_LEFT:
- print_const("[>");
- break;
-
- case BRACKET_CITATION_LEFT:
- print_const("[#");
- break;
-
- case BRACKET_LEFT:
- print_const("[");
- break;
-
- case BRACKET_RIGHT:
- print_const("]");
- break;
-
- case BRACKET_VARIABLE_LEFT:
- print_const("[\%");
- break;
-
- case COLON:
- print_char(':');
- break;
-
- case CRITIC_ADD_OPEN:
- print_const("{++");
- break;
-
- case CRITIC_ADD_CLOSE:
- print_const("++}");
- break;
-
- case CRITIC_COM_OPEN:
- print_const("{>>");
- break;
-
- case CRITIC_COM_CLOSE:
- print_const("<<}");
- break;
-
- case CRITIC_DEL_OPEN:
- print_const("{--");
- break;
-
- case CRITIC_DEL_CLOSE:
- print_const("--}");
- break;
-
- case CRITIC_HI_OPEN:
- print_const("{==");
- break;
-
- case CRITIC_HI_CLOSE:
- print_const("==}");
- break;
-
- case CRITIC_SUB_OPEN:
- print_const("{~~");
- break;
-
- case CRITIC_SUB_DIV:
- print_const("~>");
- break;
-
- case CRITIC_SUB_CLOSE:
- print_const("~~}");
- 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 ELLIPSIS:
- if (!(scratch->extensions & EXT_SMART)) {
- print_token(t);
- } else {
- print_localized(ELLIPSIS);
- }
-
- break;
-
- case EMPH_START:
- print_const("");
- break;
-
- case EMPH_STOP:
- print_const(" ");
- break;
-
- case EQUAL:
- print_char('=');
- break;
-
- case ESCAPED_CHARACTER:
- if (!(scratch->extensions & EXT_COMPATIBILITY) &&
- (source[t->start + 1] == ' ')) {
- print_const(" "); // This is a non-breaking space character
- } else {
- mmd_print_char_odf(out, source[t->start + 1]);
- }
-
- break;
-
- case HASH1:
- case HASH2:
- case HASH3:
- case HASH4:
- case HASH5:
- case HASH6:
- print_token(t);
- break;
-
- case HTML_ENTITY:
- print_const("&");
- d_string_append_c_array(out, &(source[t->start + 1]), t->len - 1);
- break;
-
- case HTML_COMMENT_START:
- if (!(scratch->extensions & EXT_SMART)) {
- print_const("<!--");
- } else {
- print_const("<!");
- print_localized(DASH_N);
- }
-
- break;
-
- case HTML_COMMENT_STOP:
- if (!(scratch->extensions & EXT_SMART)) {
- print_const("-->");
- } else {
- print_localized(DASH_N);
- print_const(">");
- }
-
- break;
-
- case INDENT_SPACE:
- print_char(' ');
- break;
-
- case INDENT_TAB:
- print_const(" ");
- break;
-
- case LINE_LIST_BULLETED:
- case LINE_LIST_ENUMERATED:
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- break;
-
- case LINE_SETEXT_2:
- case MANUAL_LABEL:
- case MARKER_BLOCKQUOTE:
- case MARKER_H1:
- case MARKER_H2:
- case MARKER_H3:
- case MARKER_H4:
- case MARKER_H5:
- case MARKER_H6:
- case MARKER_LIST_BULLET:
- case MARKER_LIST_ENUMERATOR:
- break;
-
- case MATH_BRACKET_OPEN:
- if (t->mate) {
- print_const("\\[");
- } else {
- print_const("\\[");
- }
-
- break;
-
- case MATH_BRACKET_CLOSE:
- if (t->mate) {
- print_const("\\] ");
- } else {
- print_const("\\]");
- }
-
- break;
-
- case MATH_DOLLAR_SINGLE:
- if (t->mate) {
- (t->start < t->mate->start) ? ( print_const("\\(") ) : ( print_const("\\) ") );
- } else {
- print_const("$");
- }
-
- break;
-
- case MATH_DOLLAR_DOUBLE:
- if (t->mate) {
- (t->start < t->mate->start) ? ( print_const("\\[") ) : ( print_const("\\] ") );
- } else {
- print_const("$$");
- }
-
- break;
-
- case MATH_PAREN_OPEN:
- if (t->mate) {
- print_const("\\(");
- } else {
- print_const("\\(");
- }
-
- break;
-
- case MATH_PAREN_CLOSE:
- if (t->mate) {
- print_const("\\) ");
- } else {
- print_const("\\)");
- }
-
- break;
-
- case NON_INDENT_SPACE:
- print_char(' ');
- break;
-
- case PAIR_ANGLE:
- temp_char = url_accept(source, t->start + 1, t->len - 2, NULL, true);
-
- if (temp_char) {
- print_const("");
- mmd_print_string_odf(out, temp_char);
- print_const(" ");
- } else if (scan_html(&source[t->start])) {
- // We ignore HTML blocks
- if (scan_html_comment(&source[t->start])) {
- // But allow HTML comments as raw LaTeX
- d_string_append_c_array(out, &source[t->start + 4], t->len - 4 - 3);
- }
- } else {
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- }
-
- free(temp_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;
-
- if (t->next && t->next->type == PAIR_RAW_FILTER) {
- // Raw text?
- if (raw_filter_matches(t->next, source, FORMAT_FODT)) {
- d_string_append_c_array(out, &(source[t->child->start + t->child->len]), t->child->mate->start - t->child->start - t->child->len);
- }
-
- // Skip over PAIR_RAW_FILTER
- scratch->skip_token = 1;
- break;
- }
-
- print_const("");
- mmd_export_token_tree_odf_raw(out, source, t->child, scratch);
- print_const(" ");
- break;
-
- case PAIR_BRACE:
- case PAIR_BRACES:
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- break;
-
- case PAIR_BRACKET:
- if ((scratch->extensions & EXT_NOTES) &&
- (t->next && t->next->type == PAIR_BRACKET_CITATION)) {
- goto parse_citation;
- }
-
- 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_odf(out, source, t, temp_link, scratch);
- } else {
- // Image -- should it be a figure (e.g. image is only thing in paragraph)?
- temp_token = t->next;
-
- if (temp_token &&
- ((temp_token->type == PAIR_BRACKET) ||
- (temp_token->type == PAIR_PAREN))) {
- temp_token = temp_token->next;
- }
-
- if (temp_token && temp_token->type == TEXT_NL) {
- temp_token = temp_token->next;
- }
-
- if (temp_token && temp_token->type == TEXT_LINEBREAK) {
- temp_token = temp_token->next;
- }
-
- if (t->prev || temp_token) {
- mmd_export_image_odf(out, source, t, temp_link, scratch, false);
- } else {
- mmd_export_image_odf(out, source, t, temp_link, scratch, true);
- }
- }
-
- if (temp_bool) {
- link_free(temp_link);
- }
-
- scratch->skip_token = temp_short;
-
- return;
- }
-
- // No links exist, so treat as normal
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- break;
-
- case PAIR_BRACKET_CITATION:
-parse_citation:
- temp_bool = true; // Track whether this is regular vs 'not cited'
- temp_token = t; // Remember whether we need to skip ahead
-
- if (scratch->extensions & EXT_NOTES) {
- // Note-based syntax enabled
-
- if (t->type == PAIR_BRACKET) {
- // This is a locator for a subsequent citation (e.g. `[foo][#bar]`)
- temp_char = text_inside_pair(source, t);
- temp_char2 = label_from_string(temp_char);
-
- if (strcmp(temp_char2, "notcited") == 0) {
- free(temp_char);
- temp_char = my_strdup("");
- temp_bool = false;
- }
-
- free(temp_char2);
-
- // Move ahead to actual citation
- t = t->next;
- } else {
- // This is the actual citation (e.g. `[#foo]`)
- // No locator
- temp_char = my_strdup("");
- }
-
- // Classify this use
- temp_short2 = scratch->used_citations->size;
- citation_from_bracket(source, scratch, t, &temp_short);
-
- if (temp_short == -1) {
- // This instance is not properly formed
- print_const("[#");
- mmd_export_token_tree_odf(out, source, t->child->next, scratch);
- print_const("]");
-
- free(temp_char);
- break;
- }
-
-
- temp_short3 = scratch->odf_para_type;
- scratch->odf_para_type = PAIR_BRACKET_FOOTNOTE;
-
- if (temp_bool) {
- // This is a regular citation
-
- if (temp_char[0] == '\0') {
- // No locator
-
- if (temp_short2 == scratch->used_citations->size) {
- // This is a re-use of a previously used note
- print_const("%d ", temp_short, temp_short);
- } else {
- // This is the first time this note was used
- printf("", temp_short);
- temp_note = stack_peek_index(scratch->used_citations, temp_short - 1);
-
- mmd_export_token_tree_odf(out, source, temp_note->content, scratch);
- print_const(" ");
- }
- } else {
- // Locator present
-
- if (temp_short2 == scratch->used_citations->size) {
- // This is a re-use of a previously used note
- print_const("%d ", temp_short, temp_short);
- } else {
- // This is the first time this note was used
- printf("", temp_short);
- temp_note = stack_peek_index(scratch->used_citations, temp_short - 1);
-
- mmd_export_token_tree_odf(out, source, temp_note->content, scratch);
- print_const(" ");
- }
- }
- } else {
- if (temp_short2 == scratch->used_citations->size) {
- // This is a re-use of a previously used note
- } else {
- // This is the first time this note was used
- // TODO: Not sure how to add an endnote without inserting a marker in the text
- printf("", temp_short);
- temp_note = stack_peek_index(scratch->used_citations, temp_short - 1);
-
- mmd_export_token_tree_odf(out, source, temp_note->content, scratch);
- print_const(" ");
- }
- }
-
- if (temp_token != t) {
- // Skip citation on next pass
- scratch->skip_token = 1;
- }
-
- scratch->odf_para_type = temp_short3;
-
- free(temp_char);
- } else {
- // Note-based syntax disabled
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- }
-
- break;
-
- case PAIR_BRACKET_FOOTNOTE:
- if (scratch->extensions & EXT_NOTES) {
- // Note-based syntax enabled
-
- // Classify this use
- temp_short2 = scratch->used_footnotes->size;
- footnote_from_bracket(source, scratch, t, &temp_short);
-
- if (temp_short == -1) {
- // This instance is not properly formed
- print_const("[?");
- mmd_export_token_tree_odf(out, source, t->child->next, scratch);
- print_const("]");
- break;
- }
-
- temp_short3 = scratch->odf_para_type;
- scratch->odf_para_type = PAIR_BRACKET_FOOTNOTE;
-
- if (temp_short2 == scratch->used_footnotes->size) {
- // This is a re-use of a previously used note
-
- printf("", temp_short);
- temp_note = stack_peek_index(scratch->used_footnotes, temp_short - 1);
-
- mmd_export_token_tree_odf(out, source, temp_note->content, scratch);
- print_const(" ");
- } else {
- // This is the first time this note was used
-
- // This is a new footnote
- printf("", temp_short);
- temp_note = stack_peek_index(scratch->used_footnotes, temp_short - 1);
-
- mmd_export_token_tree_odf(out, source, temp_note->content, scratch);
- print_const(" ");
- }
-
- scratch->odf_para_type = temp_short3;
- } else {
- // Note-based syntax disabled
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- }
-
- break;
-
- case PAIR_BRACKET_ABBREVIATION:
-
- // Which might also be an "auto-tagged" abbreviation
- if (scratch->extensions & EXT_NOTES) {
- // Note-based syntax enabled
-
- // Classify this use
- temp_short2 = scratch->used_abbreviations->size;
- temp_short3 = scratch->inline_abbreviations_to_free->size;
- abbreviation_from_bracket(source, scratch, t, &temp_short);
-
- if (temp_short == -1) {
- // This instance is not properly formed
- print_const("[>");
- mmd_export_token_tree_odf(out, source, t->child->next, scratch);
- print_const("]");
- break;
- }
-
- // Get instance of the note used
- temp_note = stack_peek_index(scratch->used_abbreviations, temp_short - 1);
-
- if (t->child) {
- t->child->type = TEXT_EMPTY;
- t->child->mate->type = TEXT_EMPTY;
- }
-
- if (temp_short2 == scratch->used_abbreviations->size) {
- // This is a re-use of a previously used note
-
- if (temp_short3 == scratch->inline_abbreviations_to_free->size) {
- // This is a reference definition
- mmd_print_string_odf(out, temp_note->label_text);
-// mmd_export_token_tree_odf(out, source, t->child, scratch);
- } else {
- // This is an inline definition
- mmd_print_string_odf(out, temp_note->label_text);
-// mmd_export_token_tree_odf(out, source, t->child, scratch);
- }
- } else {
- // This is the first time this note was used
- temp_short2 = scratch->odf_para_type;
- scratch->odf_para_type = PAIR_BRACKET_ABBREVIATION;
-
- if (temp_short3 == scratch->inline_abbreviations_to_free->size) {
- // This is a reference definition
- mmd_print_string_odf(out, temp_note->clean_text);
- print_const(" (");
- mmd_print_string_odf(out, temp_note->label_text);
- print_const(")");
- } else {
- // This is an inline definition
- mmd_print_string_odf(out, temp_note->clean_text);
- print_const(" (");
- mmd_print_string_odf(out, temp_note->label_text);
- print_const(")");
- }
-
- scratch->odf_para_type = temp_short2;
- }
- } else {
- // Note-based syntax disabled
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- }
-
- break;
-
- case PAIR_BRACKET_GLOSSARY:
-
- // Which might also be an "auto-tagged" glossary
- if (scratch->extensions & EXT_NOTES) {
- // Note-based syntax enabled
-
- // Classify this use
- temp_short2 = scratch->used_glossaries->size;
- glossary_from_bracket(source, scratch, t, &temp_short);
-
- if (temp_short == -1) {
- // This instance is not properly formed
- print_const("[?");
- mmd_export_token_tree_odf(out, source, t->child->next, scratch);
- print_const("]");
- break;
- }
-
- // Get instance of the note used
- temp_note = stack_peek_index(scratch->used_glossaries, temp_short - 1);
-
- temp_short3 = scratch->odf_para_type;
- scratch->odf_para_type = PAIR_BRACKET_GLOSSARY;
-
- if (temp_short2 == scratch->used_glossaries->size) {
- // This is a re-use of a previously used note
-
- mmd_print_string_odf(out, temp_note->clean_text);
- } else {
- // This is the first time this note was used
-
- mmd_print_string_odf(out, temp_note->clean_text);
-
- printf("", temp_short);
- mmd_export_token_tree_odf(out, source, temp_note->content, scratch);
- print_const(" ");
- }
-
- scratch->odf_para_type = temp_short3;
- } else {
- // Note-based syntax disabled
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- }
-
- break;
-
- case PAIR_BRACKET_VARIABLE:
- temp_char = text_inside_pair(source, t);
- temp_char2 = extract_metadata(scratch, temp_char);
-
- if (temp_char2) {
- mmd_print_string_odf(out, temp_char2);
- } else {
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- }
-
- // Don't free temp_char2 (it belongs to meta *)
- free(temp_char);
- 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_odf(out, source, t->child, scratch);
- } else {
- print_const("");
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- print_const(" ");
- }
- } else {
- mmd_export_token_tree_odf(out, source, t->child, 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_odf(out, source, t->child, scratch);
- } else {
- print_const("");
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- print_const(" ");
- }
- } else {
- mmd_export_token_tree_odf(out, source, t->child, 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_const("");
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- print_const(" ");
- } else {
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- }
-
- break;
-
- case PAIR_CRITIC_HI:
-
- // Ignore if we're rejecting or accepting
- if ((scratch->extensions & EXT_CRITIC_REJECT) ||
- (scratch->extensions & EXT_CRITIC_ACCEPT)) {
- t->child->type = TEXT_EMPTY;
- t->child->mate->type = TEXT_EMPTY;
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- break;
- }
-
- if (scratch->extensions & EXT_CRITIC) {
- t->child->type = TEXT_EMPTY;
- t->child->mate->type = TEXT_EMPTY;
- print_const("");
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- print_const(" ");
- } else {
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- }
-
- break;
-
- case CRITIC_SUB_DIV_A:
- print_const("~");
- break;
-
- case CRITIC_SUB_DIV_B:
- print_const(">");
- break;
-
- case PAIR_CRITIC_SUB_DEL:
- if ((scratch->extensions & EXT_CRITIC) &&
- (t->next) &&
- (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_odf(out, source, t->child, scratch);
- } else {
- print_const("");
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- print_const(" ");
- }
- } else {
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- }
-
- break;
-
- case PAIR_CRITIC_SUB_ADD:
- if ((scratch->extensions & EXT_CRITIC) &&
- (t->prev) &&
- (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_odf(out, source, t->child, scratch);
- } else {
- print_const("");
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- print_const(" ");
- }
- } else {
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- }
-
- break;
-
- case PAIR_HTML_COMMENT:
- break;
-
- case PAIR_EMPH:
- case PAIR_MATH:
- case PAIR_PAREN:
- case PAIR_QUOTE_DOUBLE:
- case PAIR_QUOTE_SINGLE:
- case PAIR_STAR:
- case PAIR_STRONG:
- case PAIR_SUBSCRIPT:
- case PAIR_SUPERSCRIPT:
- case PAIR_UL:
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- break;
-
- case PAREN_LEFT:
- print_char('(');
- break;
-
- case PAREN_RIGHT:
- print_char(')');
- break;
-
- case PIPE:
- print_token(t);
- break;
-
- case PLUS:
- print_char('+');
- break;
-
- case QUOTE_SINGLE:
- if ((t->mate == NULL) || (!(scratch->extensions & EXT_SMART))) {
- print_const("'");
- } 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_const(""");
- } 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_const("''");
- } else {
- print_localized(QUOTE_RIGHT_DOUBLE);
- }
-
- break;
-
- case SLASH:
- print_char('/');
- break;
-
- case STAR:
- print_char('*');
- break;
-
- case STRONG_START:
- print_const("");
- break;
-
- case STRONG_STOP:
- print_const(" ");
- break;
-
- case SUBSCRIPT:
- if (t->mate) {
- (t->start < t->mate->start) ? (print_const("")) : (print_const(" "));
- } else if (t->len != 1) {
- print_const("");
- mmd_export_token_odf(out, source, t->child, scratch);
- print_const(" ");
- } else {
- print_const("~");
- }
-
- break;
-
- case SUPERSCRIPT:
- if (t->mate) {
- (t->start < t->mate->start) ? (print_const("")) : (print_const(" "));
- } else if (t->len != 1) {
- print_const("");
- mmd_export_token_odf(out, source, t->child, scratch);
- print_const(" ");
- } else {
- print_const("^");
- }
-
- break;
-
- case TABLE_CELL:
- print_const("next && t->next->type == TABLE_DIVIDER) {
- if (t->next->len > 1) {
- printf(" table:number-columns-spanned=\"%d\"", t->next->len);
- }
- }
-
- if (scratch->in_table_header) {
- print_const(">\n\ntable_alignment[scratch->table_cell_count]) {
- case 'l':
- case 'L':
- default:
- print_const(" text:style-name=\"MMD-Table\"");
- break;
-
- case 'r':
- case 'R':
- print_const(" text:style-name=\"MMD-Table-Right\"");
- break;
-
- case 'c':
- case 'C':
- print_const(" text:style-name=\"MMD-Table-Center\"");
- break;
- }
- }
-
- print_const(">");
- mmd_export_token_tree_odf(out, source, t->child, scratch);
-
- print_const(" \n \n");
-
- if (t->next) {
- scratch->table_cell_count += t->next->len;
- } else {
- scratch->table_cell_count++;
- }
-
- break;
-
- case TABLE_DIVIDER:
- break;
-
- case TABLE_ROW:
- print_const("\n");
- scratch->table_cell_count = 0;
- mmd_export_token_tree_odf(out, source, t->child, scratch);
- print_const(" \n");
- break;
-
- case TEXT_EMPTY:
- break;
-
- case TEXT_LINEBREAK:
- if (t->next) {
- print_const(" \n");
- scratch->padded = 0;
- }
-
- break;
-
- case TEXT_NL:
- if (t->next) {
- print_char('\n');
- }
-
- break;
-
- case RAW_FILTER_LEFT:
- case TEXT_BACKSLASH:
- case TEXT_BRACE_LEFT:
- case TEXT_BRACE_RIGHT:
- case TEXT_HASH:
- case TEXT_NUMBER_POSS_LIST:
- case TEXT_PERCENT:
- case TEXT_PERIOD:
- case TEXT_PLAIN:
- case TOC:
- case UL:
- print_token(t);
- break;
-
- default:
- fprintf(stderr, "Unknown token type: %d\n", t->type);
- token_describe(t, source);
- break;
- }
-}
-
-
-void mmd_export_token_tree_odf(DString * out, const char * source, token * t, scratch_pad * scratch) {
-
- // Prevent stack overflow with "dangerous" input causing extreme recursion
- if (scratch->recurse_depth == kMaxExportRecursiveDepth) {
- return;
- }
-
- scratch->recurse_depth++;
-
- while (t != NULL) {
- if (scratch->skip_token) {
- scratch->skip_token--;
- } else {
- mmd_export_token_odf(out, source, t, scratch);
- }
-
- t = t->next;
- }
-
- scratch->recurse_depth--;
-}
-
-
-void mmd_export_token_odf_raw(DString * out, const char * source, token * t, scratch_pad * scratch) {
- if (t == NULL) {
- return;
- }
-
- switch (t->type) {
- case AMPERSAND:
- print_const("&");
- break;
-
- case AMPERSAND_LONG:
- print_const("&");
- break;
-
- case ANGLE_RIGHT:
- print_const(">");
- break;
-
- case ANGLE_LEFT:
- print_const("<");
- break;
-
- case ESCAPED_CHARACTER:
- print_const("\\");
- mmd_print_char_odf(out, source[t->start + 1]);
- break;
-
- case HTML_ENTITY:
- print_const("&");
- d_string_append_c_array(out, &(source[t->start + 1]), t->len - 1);
- break;
-
- case INDENT_TAB:
- print_const(" ");
- break;
-
- case QUOTE_DOUBLE:
- print_const(""");
- break;
-
- case CODE_FENCE:
- if (t->next) {
- t->next->type = TEXT_EMPTY;
- }
-
- case TEXT_EMPTY:
- break;
-
- case TEXT_NL:
- print_const(" ");
- break;
-
- default:
- if (t->child) {
- mmd_export_token_tree_odf_raw(out, source, t->child, scratch);
- } else {
- print_token(t);
- }
-
- break;
- }
-}
-
-
-void mmd_export_token_tree_odf_raw(DString * out, const char * source, token * t, scratch_pad * scratch) {
- while (t != NULL) {
- if (scratch->skip_token) {
- scratch->skip_token--;
- } else {
- mmd_export_token_odf_raw(out, source, t, scratch);
- }
-
- t = t->next;
- }
-}
-
-
-void mmd_start_complete_odf(DString * out, const char * source, scratch_pad * scratch) {
- print_const("\n" \
- "\n");
-
- /* Font Declarations */
- print_const("\n" \
- " \n" \
- " \n");
-
- /* Append basic style information */
- print_const("\n" \
- "\n" \
- " \n" \
- " \n" \
- "\n" \
- " \n" \
- " \n" \
- " \n" \
- "\n" \
- " \n" \
- " \n" \
- "\n" \
- " \n" \
- " \n" \
- " \n" \
- "\n" \
- " \n" \
- " \n" \
- "\n" \
- " \n" \
- " \n" \
- " \n" \
- "\n" \
- " \n" \
- " \n" \
- " \n" \
- "" \
- " " \
- " \n" \
- "\n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n");
-
- /* Automatic style information */
- print_const("" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- "\n" \
- " \n" \
- " \n" \
- "\n" \
- " \n" \
- " \n" \
- "\n" \
- " \n" \
- " \n" \
- "\n" \
- "\n" \
- " \n" \
- "\n" \
- " \n" \
- " \n" \
- "\n" \
- "\n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- "\n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " Bibliography \n" \
- " \n" \
- " \n");
-
- // Iterate over metadata keys
- meta * m;
-
- if (scratch->meta_hash) {
- print_const("\n");
- }
-
- for (m = scratch->meta_hash; m != NULL; m = m->hh.next) {
- if (strcmp(m->key, "baseheaderlevel") == 0) {
- } else if (strcmp(m->key, "bibliostyle") == 0) {
- } else if (strcmp(m->key, "bibtex") == 0) {
- } else if (strcmp(m->key, "css") == 0) {
- } else if (strcmp(m->key, "htmlfooter") == 0) {
- } else if (strcmp(m->key, "htmlheader") == 0) {
- } else if (strcmp(m->key, "htmlheaderlevel") == 0) {
- } else if (strcmp(m->key, "language") == 0) {
- } else if (strcmp(m->key, "latexbegin") == 0) {
- } else if (strcmp(m->key, "latexconfig") == 0) {
- } else if (strcmp(m->key, "latexfooter") == 0) {
- } else if (strcmp(m->key, "latexheaderlevel") == 0) {
- } else if (strcmp(m->key, "latexinput") == 0) {
- } else if (strcmp(m->key, "latexleader") == 0) {
- } else if (strcmp(m->key, "latexmode") == 0) {
- } else if (strcmp(m->key, "mmdfooter") == 0) {
- } else if (strcmp(m->key, "mmdheader") == 0) {
- } else if (strcmp(m->key, "quoteslanguage") == 0) {
- } else if (strcmp(m->key, "title") == 0) {
- print_const("\t");
- mmd_print_string_odf(out, m->value);
- print_const(" \n");
- } else if (strcmp(m->key, "transcludebase") == 0) {
- } else if (strcmp(m->key, "xhtmlheader") == 0) {
- print(m->value);
- print_char('\n');
- } else if (strcmp(m->key, "xhtmlheaderlevel") == 0) {
- } else {
- print_const("\tkey);
- print_const("\">");
- mmd_print_string_odf(out, m->value);
- print_const(" \n");
- }
- }
-
- if (scratch->meta_hash) {
- print_const(" \n");
- }
-
- print_const("\n\n");
-}
-
-
-void mmd_end_complete_odf(DString * out, const char * source, scratch_pad * scratch) {
- pad(out, 1, scratch);
- print_const(" \n \n ");
-}
-
diff --git a/Sources/libMultiMarkdown/fodt.h b/Sources/libMultiMarkdown/fodt.h
deleted file mode 100644
index 80d43b2a..00000000
--- a/Sources/libMultiMarkdown/fodt.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
-
- MultiMarkdown -- Lightweight markup processor to produce HTML, odf, and more.
-
- @file fodt.h
-
- @brief Convert token tree to Flat OpenDocument (ODF/FODT) 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 FODT_MULTIMARKDOWN_H
-#define FODT_MULTIMARKDOWN_H
-
-
-#include "d_string.h"
-#include "token.h"
-#include "writer.h"
-
-void mmd_export_token_odf(DString * out, const char * source, token * t, scratch_pad * scratch);
-void mmd_export_token_tree_odf(DString * out, const char * source, token * t, scratch_pad * scratch);
-
-void mmd_export_token_odf_raw(DString * out, const char * source, token * t, scratch_pad * scratch);
-void mmd_export_token_tree_odf_raw(DString * out, const char * source, token * t, scratch_pad * scratch);
-
-void mmd_export_citation_list_odf(DString * out, const char * source, scratch_pad * scratch);
-void mmd_export_footnote_list_odf(DString * out, const char * source, scratch_pad * scratch);
-
-void mmd_start_complete_odf(DString * out, const char * source, scratch_pad * scratch);
-void mmd_end_complete_odf(DString * out, const char * source, scratch_pad * scratch);
-
-void mmd_export_citation_list_odf(DString * out, const char * source, scratch_pad * scratch);
-
-
-#endif
diff --git a/Sources/libMultiMarkdown/html.c b/Sources/libMultiMarkdown/html.c
index 69873693..edbee6d8 100644
--- a/Sources/libMultiMarkdown/html.c
+++ b/Sources/libMultiMarkdown/html.c
@@ -209,6 +209,7 @@ void mmd_print_localized_char_html(DString * out, unsigned short type, scratch_p
break;
case FRENCH:
+ case SPANISH:
print_const("«");
break;
@@ -233,6 +234,7 @@ void mmd_print_localized_char_html(DString * out, unsigned short type, scratch_p
break;
case FRENCH:
+ case SPANISH:
print_const("»");
break;
@@ -257,11 +259,6 @@ static char * strip_dimension_units(char *original) {
result[i] = tolower(result[i]);
}
- if (strstr(&result[strlen(result) - 2], "px")) {
- // Leave 'px' alone
- return result;
- }
-
// Trim anything other than digits
for (i = 0; result[i]; i++) {
if (result[i] < '0' || result[i] > '9') {
@@ -371,6 +368,12 @@ void mmd_export_image_html(DString * out, const char * source, token * text, lin
if (strcmp(a->key, "width") == 0) {
width = strip_dimension_units(a->value);
+ if (strlen(width) + 2 == strlen(a->value)) {
+ if (strcmp(&(a->value[strlen(width)]), "px") == 0) {
+ a->value[strlen(width)] = '\0';
+ }
+ }
+
if (strcmp(a->value, width) == 0) {
print_const(" ");
print(a->key);
@@ -386,6 +389,12 @@ void mmd_export_image_html(DString * out, const char * source, token * text, lin
} else if (strcmp(a->key, "height") == 0) {
height = strip_dimension_units(a->value);
+ if (strlen(height) + 2 == strlen(a->value)) {
+ if (strcmp(&(a->value[strlen(height)]), "px") == 0) {
+ a->value[strlen(height)] = '\0';
+ }
+ }
+
if (strcmp(a->value, height) == 0) {
print_const(" ");
print(a->key);
@@ -2044,6 +2053,8 @@ void mmd_export_token_html_raw(DString * out, const char * source, token * t, sc
return;
}
+ char * temp;
+
switch (t->type) {
case BACKTICK:
print_token(t);
@@ -2065,6 +2076,26 @@ void mmd_export_token_html_raw(DString * out, const char * source, token * t, sc
print_const("<");
break;
+ case CRITIC_COM_OPEN:
+ print_const("{>>");
+ break;
+
+ case CRITIC_COM_CLOSE:
+ print_const("<<}");
+ break;
+
+ case CRITIC_SUB_DIV:
+ print_const("~>");
+ break;
+
+ case CRITIC_SUB_DIV_A:
+ print_const("~");
+ break;
+
+ case CRITIC_SUB_DIV_B:
+ print_const(">");
+ break;
+
case ESCAPED_CHARACTER:
print_const("\\");
mmd_print_char_html(out, source[t->start + 1], false);
@@ -2075,6 +2106,27 @@ void mmd_export_token_html_raw(DString * out, const char * source, token * t, sc
d_string_append_c_array(out, &(source[t->start + 1]), t->len - 1);
break;
+ case MARKER_LIST_BULLET:
+ case MARKER_LIST_ENUMERATOR:
+ print_token(t);
+
+ temp = NULL;
+
+ if (t->next) {
+ temp = (char *) &source[t->next->start];
+ }
+
+ source = (char *) &source[t->start + t->len];
+
+ while (char_is_whitespace(*source) &&
+ ((temp == NULL) ||
+ (source < temp))) {
+ print_char(*source);
+ source++;
+ }
+
+ break;
+
case MATH_BRACKET_OPEN:
print_const("\\\\[");
break;
diff --git a/Sources/libMultiMarkdown/include/d_string.h b/Sources/libMultiMarkdown/include/d_string.h
index ae9664d9..44c0d132 100644
--- a/Sources/libMultiMarkdown/include/d_string.h
+++ b/Sources/libMultiMarkdown/include/d_string.h
@@ -17,7 +17,7 @@
/*
Copyright © 2011 Daniel Jalkut.
- Modifications by Fletcher T. Penney, Copyright © 2011-2017 Fletcher T. Penney.
+ Modifications by Fletcher T. Penney, Copyright © 2011-2018 Fletcher T. Penney.
Modifications by Dan Lowe, Copyright © 2011 Dan Lowe.
@@ -160,7 +160,7 @@ void d_string_insert_printf(
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
+ size_t len //!< How many characters(bytes) to remove
);
/// Copy a portion of dynamic string
diff --git a/Sources/libMultiMarkdown/include/libMultiMarkdown.h b/Sources/libMultiMarkdown/include/libMultiMarkdown.h
index c2159bad..36ef0204 100644
--- a/Sources/libMultiMarkdown/include/libMultiMarkdown.h
+++ b/Sources/libMultiMarkdown/include/libMultiMarkdown.h
@@ -306,10 +306,18 @@ void mmd_append_mmd_footer(DString * source);
void mmd_critic_markup_accept(DString * d);
+/// Accept all CriticMarkup changes in the specified range
+void mmd_critic_markup_accept_range(DString * d, size_t start, size_t len);
+
+
/// Reject all CriticMarkup changes in the source string
void mmd_critic_markup_reject(DString * d);
+/// Reject all CriticMarkup changes in the specified range
+void mmd_critic_markup_reject_range(DString * d, size_t start, size_t len);
+
+
/// Token types for parse tree
enum token_types {
DOC_START_TOKEN = 0, //!< DOC_START_TOKEN must be type 0
@@ -512,6 +520,7 @@ enum smart_quotes_language {
FRENCH,
GERMAN,
GERMANGUILL,
+ SPANISH,
SWEDISH,
};
diff --git a/Sources/libMultiMarkdown/latex.c b/Sources/libMultiMarkdown/latex.c
index 81af5e0d..3667e139 100644
--- a/Sources/libMultiMarkdown/latex.c
+++ b/Sources/libMultiMarkdown/latex.c
@@ -214,6 +214,7 @@ void mmd_print_localized_char_latex(DString * out, unsigned short type, scratch_
break;
case FRENCH:
+ case SPANISH:
print_const("«");
break;
@@ -238,6 +239,7 @@ void mmd_print_localized_char_latex(DString * out, unsigned short type, scratch_
break;
case FRENCH:
+ case SPANISH:
print_const("»");
break;
@@ -1983,6 +1985,8 @@ void mmd_export_token_latex_raw(DString * out, const char * source, token * t, s
return;
}
+ char * temp;
+
switch (t->type) {
case ESCAPED_CHARACTER:
print_const("\\");
@@ -1994,6 +1998,27 @@ void mmd_export_token_latex_raw(DString * out, const char * source, token * t, s
print_token(t);
break;
+ case MARKER_LIST_BULLET:
+ case MARKER_LIST_ENUMERATOR:
+ print_token(t);
+
+ temp = NULL;
+
+ if (t->next) {
+ temp = (char *) &source[t->next->start];
+ }
+
+ source = (char *) &source[t->start + t->len];
+
+ while (char_is_whitespace(*source) &&
+ ((temp == NULL) ||
+ (source < temp))) {
+ print_char(*source);
+ source++;
+ }
+
+ break;
+
case SUBSCRIPT:
if (t->child) {
print_const("\\ensuremath{\\sim}");
@@ -2138,6 +2163,17 @@ void mmd_export_token_latex_tt(DString * out, const char * source, token * t, sc
mmd_print_char_latex(out, source[t->start + 1]);
break;
+ case HASH1:
+ case HASH2:
+ case HASH3:
+ case HASH4:
+ case HASH5:
+ case HASH6:
+ case TEXT_HASH:
+ print_const("\\");
+ print_token(t);
+ break;
+
case HTML_ENTITY:
if (source[t->start + 1] == '#') {
print_const("\\&\\#");
@@ -2154,6 +2190,14 @@ void mmd_export_token_latex_tt(DString * out, const char * source, token * t, sc
t->next->type = TEXT_EMPTY;
}
+ case MATH_DOLLAR_SINGLE:
+ print_const("\\$");
+ break;
+
+ case MATH_DOLLAR_DOUBLE:
+ print_const("\\$\\$");
+ break;
+
case MATH_BRACKET_OPEN:
case MATH_BRACKET_CLOSE:
case MATH_PAREN_OPEN:
diff --git a/Sources/libMultiMarkdown/mmd.c b/Sources/libMultiMarkdown/mmd.c
index 13152542..ece12f13 100644
--- a/Sources/libMultiMarkdown/mmd.c
+++ b/Sources/libMultiMarkdown/mmd.c
@@ -237,7 +237,7 @@ void mmd_engine_set_language(mmd_engine * e, short language) {
break;
case LC_ES:
- e->quotes_lang = ENGLISH;
+ e->quotes_lang = SPANISH;
break;
case LC_FR:
@@ -1281,6 +1281,9 @@ void mmd_assign_ambidextrous_tokens_in_block(mmd_engine * e, token * block, size
case BLOCK_SETEXT_1:
case BLOCK_SETEXT_2:
case BLOCK_TABLE:
+ case BLOCK_TABLE_SECTION:
+ case TABLE_ROW:
+ case TABLE_CELL:
case BLOCK_TERM:
case LINE_LIST_BULLETED:
case LINE_LIST_ENUMERATED:
@@ -1573,7 +1576,7 @@ void mmd_assign_ambidextrous_tokens_in_block(mmd_engine * e, token * block, size
offset = t->start + t->len;
- if (char_is_whitespace_or_line_ending_or_punctuation(str[offset])) {
+ if (char_is_whitespace_or_line_ending(str[offset])) {
t->can_open = 0;
}
@@ -2398,7 +2401,7 @@ char * mmd_engine_metavalue_for_key(mmd_engine * e, const char * key) {
if (e == NULL || key == NULL) {
return NULL;
}
-
+
if (e->metadata_stack->size == 0) {
// Ensure we have checked for metadata
if (!mmd_engine_has_metadata(e, NULL)) {
diff --git a/Sources/libMultiMarkdown/opendocument-content.c b/Sources/libMultiMarkdown/opendocument-content.c
index 27ecbf01..9a2dfe6a 100644
--- a/Sources/libMultiMarkdown/opendocument-content.c
+++ b/Sources/libMultiMarkdown/opendocument-content.c
@@ -246,6 +246,7 @@ void mmd_print_localized_char_opendocument(DString * out, unsigned short type, s
break;
case FRENCH:
+ case SPANISH:
print_const("«");
break;
@@ -270,6 +271,7 @@ void mmd_print_localized_char_opendocument(DString * out, unsigned short type, s
break;
case FRENCH:
+ case SPANISH:
print_const("»");
break;
@@ -289,6 +291,8 @@ void mmd_export_token_opendocument_raw(DString * out, const char * source, token
return;
}
+ char * temp;
+
switch (t->type) {
case AMPERSAND:
print_const("&");
@@ -324,6 +328,27 @@ void mmd_export_token_opendocument_raw(DString * out, const char * source, token
print_const(""");
break;
+ case MARKER_LIST_BULLET:
+ case MARKER_LIST_ENUMERATOR:
+ print_token(t);
+
+ temp = NULL;
+
+ if (t->next) {
+ temp = (char *) &source[t->next->start];
+ }
+
+ source = (char *) &source[t->start + t->len];
+
+ while (char_is_whitespace(*source) &&
+ ((temp == NULL) ||
+ (source < temp))) {
+ print_char(*source);
+ source++;
+ }
+
+ break;
+
case MATH_BRACKET_OPEN:
case MATH_BRACKET_CLOSE:
case MATH_PAREN_OPEN:
diff --git a/Sources/libMultiMarkdown/opendocument.c b/Sources/libMultiMarkdown/opendocument.c
index 0aca6ffb..1edeb459 100644
--- a/Sources/libMultiMarkdown/opendocument.c
+++ b/Sources/libMultiMarkdown/opendocument.c
@@ -105,6 +105,7 @@
#include
#endif
+#include "file.h"
#include "miniz.h"
#include "opendocument.h"
#include "opendocument-content.h"
diff --git a/Sources/libMultiMarkdown/token.c b/Sources/libMultiMarkdown/token.c
index b71dc1ee..9b79ccd3 100644
--- a/Sources/libMultiMarkdown/token.c
+++ b/Sources/libMultiMarkdown/token.c
@@ -369,6 +369,18 @@ token * token_prune_graft(token * first, token * last, unsigned short container_
next->prev = first;
}
+ // Fix tail (prior tail is now a child)
+ if (first->next == NULL) {
+ token * walker = first;
+
+ while (walker->prev) {
+ walker = walker->prev;
+ }
+
+ first->tail = first;
+ walker->tail = first;
+ }
+
return first;
}
diff --git a/Sources/libMultiMarkdown/uuid.c b/Sources/libMultiMarkdown/uuid.c
index 2c91c9f2..6941e387 100644
--- a/Sources/libMultiMarkdown/uuid.c
+++ b/Sources/libMultiMarkdown/uuid.c
@@ -149,6 +149,6 @@ void custom_seed_rand(void) {
// This is not a "cryptographically secure" random seed,
// but good enough for an EPUB id....
unsigned long seed = mix(clock(), time(NULL), clock());
- srand(seed);
+ srand((unsigned int)seed);
}
diff --git a/Sources/libMultiMarkdown/writer.c b/Sources/libMultiMarkdown/writer.c
index f1e90aad..eb6abe85 100644
--- a/Sources/libMultiMarkdown/writer.c
+++ b/Sources/libMultiMarkdown/writer.c
@@ -598,10 +598,10 @@ attr * parse_attributes(char * source) {
a->next = attr_new(key, value);
a = a->next;
} else {
-#ifndef __clang_analyzer__
+ #ifndef __clang_analyzer__
a = attr_new(key, value);
attributes = a;
-#endif
+ #endif
}
free(value); // We stored a modified copy
@@ -1620,7 +1620,7 @@ void process_metadata_stack(mmd_engine * e, scratch_pad * scratch) {
scratch->quotes_lang = GERMAN;
} else if (strcmp(temp_char, "es") == 0) {
scratch->language = LC_ES;
- scratch->quotes_lang = ENGLISH;
+ scratch->quotes_lang = SPANISH;
} else if (strcmp(temp_char, "fr") == 0) {
scratch->language = LC_FR;
scratch->quotes_lang = FRENCH;
@@ -1662,6 +1662,9 @@ void process_metadata_stack(mmd_engine * e, scratch_pad * scratch) {
scratch->quotes_lang = GERMAN;
} else if (strcmp(temp_char, "germanguillemets") == 0) {
scratch->quotes_lang = GERMANGUILL;
+ } else if ((strcmp(temp_char, "spanish") == 0) ||
+ (strcmp(temp_char, "es") == 0)) {
+ scratch->quotes_lang = SPANISH;
} else if ((strcmp(temp_char, "swedish") == 0) ||
(strcmp(temp_char, "sv") == 0)) {
scratch->quotes_lang = SWEDISH;
@@ -1769,7 +1772,7 @@ void automatic_search(mmd_engine * e, token * t, trie * ac) {
void identify_global_search_terms(mmd_engine * e, scratch_pad * scratch) {
// Only search if we have a target
- int count = e->abbreviation_stack->size + e->glossary_stack->size;
+ size_t count = e->abbreviation_stack->size + e->glossary_stack->size;
if (count == 0) {
return;
diff --git a/Sources/multimarkdown/main.c b/Sources/multimarkdown/main.c
index f30c2afb..d0578bd0 100644
--- a/Sources/multimarkdown/main.c
+++ b/Sources/multimarkdown/main.c
@@ -129,42 +129,6 @@ char * filename_with_extension(const char * original, const char * new_extension
}
-// Windows does not know realpath(), so we need a "windows port"
-// Fix by @f8ttyc8t ()
-#if (defined(_WIN32) || defined(__WIN32__))
-// Let compiler know where to find GetFullPathName()
-#include
-
-char *realpath(const char *path, char *resolved_path) {
- DWORD retval = 0;
- DWORD dwBufSize = 0; // Just in case MAX_PATH differs from PATH_MAX
- TCHAR *buffer = NULL;
-
- if (resolved_path == NULL) {
- // realpath allocates appropiate bytes if resolved_path is null. This is to mimic realpath behavior
- dwBufSize = PATH_MAX; // Use windows PATH_MAX constant, because we are in Windows context now.
- buffer = (char*)malloc(dwBufSize);
-
- if (buffer == NULL) {
- return NULL; // some really weird is going on...
- }
- } else {
- dwBufSize = MAX_PATH; // buffer has been allocated using MAX_PATH earlier
- buffer = resolved_path;
- }
-
- retval = GetFullPathName(path, dwBufSize, buffer, NULL);
-
- if (retval == 0) {
- return NULL;
- printf("Failed to GetFullPathName()\n");
- }
-
- return buffer;
-}
-#endif
-
-
int main(int argc, char** argv) {
int exitcode = EXIT_SUCCESS;
char * binname = "multimarkdown";
diff --git a/swift/cocoaconv.rb b/swift/cocoaconv.rb
new file mode 100755
index 00000000..472616ce
--- /dev/null
+++ b/swift/cocoaconv.rb
@@ -0,0 +1,253 @@
+#!/usr/bin/env ruby
+
+require 'optparse'
+
+CURRENT_PATH = File.expand_path(File.dirname(__FILE__))
+FALLBACK_PATH = File.join(CURRENT_PATH, "..", "build-xcode", "Debug", "include", "libMultiMarkdown", "libMultiMarkdown.h")
+
+options = {:mode => :nsenum}
+OptionParser.new do |parser|
+ parser.banner = "Usage: #{$0} [options] path/to/libMultiMarkdown.h"
+
+ parser.separator ""
+ parser.separator "Without an input path, the script uses this default relative project location:"
+ parser.separator "../build-xcode/Debug/include/libMultiMarkdown/libMultiMarkdown.h"
+ parser.separator ""
+
+ parser.on("-h", "--help", "Prints this help") do
+ puts parser
+ exit
+ end
+
+ parser.on("-m", "--mode [MODE]", [:swift, :nsenum],
+ "Select generator:",
+ " nsenum Generates Objective-C NS_ENUM wrappers. (Default)",
+ " swift Generates Swift enum descriptions.") do |mode|
+ options[:mode] = mode
+ end
+
+ parser.on("-o", "--output [PATH]", String,
+ "Write output to file instead of STDOUT. (Optional)") do |path|
+ options[:outpath] = path
+ end
+end.parse!
+
+
+################################################################################
+## Types to perform the conversion
+################################################################################
+
+
+module CustomStringConvertible
+ def extension
+ indentation = " "
+ cases = case_descriptions
+ .map { |line| indentation + line }
+ .join("\n")
+
+ return %Q{
+extension #{type_name}: CustomStringConvertible {
+ public var description: String {
+ switch self {
+#{cases}
+ }
+ }
+}}
+ end
+
+ private
+
+ def case_descriptions
+ cases.map { |c| CustomStringConvertible.description_for(self.type_name, c) }
+ end
+
+ def indented_case_descriptions(indent)
+ case_descriptions
+ .map { |line| indent + line }
+ .join("\n")
+ end
+
+ def self.description_for(type_name, enum_case)
+ case_name = case_only(enum_case)
+
+ # Drop redundant enum base prefixes:
+ # ".formatLatex" => ".latex"
+ # ".extCritic" => ".critic"
+ swift_case_name = case_name.camelize(drop_prefix: case_name.start_with?("EXT_", "FORMAT_"),
+ lowercase_first: true)
+ %Q{case .#{swift_case_name}: return "#{type_name}.#{swift_case_name}"}
+ end
+
+ def self.case_only(line)
+ line[/\w+/]
+ end
+end
+
+class String
+ def camelize(drop_prefix: false, lowercase_first: false)
+ self
+ .split('_')
+ .drop(drop_prefix ? 1 : 0)
+ .map.with_index { |part, i|
+ if lowercase_first && i == 0
+ part.downcase
+ else
+ part.capitalize
+ end }
+ .join
+ end
+end
+
+module NSEnum
+ def self.type_name(type)
+ type_name = type.camelize
+ # Remove plural "S"
+ if type_name == "TokenTypes"
+ "TokenType"
+ elsif type_name == "ParserExtensions"
+ "ParserExtension"
+ else
+ type_name
+ end
+ end
+
+ def type_name
+ NSEnum.type_name(type)
+ end
+
+ def ns_enum
+ base_type_name = NSEnum.type_name(type)
+ swift_type_name = base_type_name
+ objc_type_name = "MMD6#{base_type_name}"
+
+ ns_enum_cases = cases
+ .map { |line| NSEnum.case(objc_type_name, line) }
+ .join("\n")
+
+ return %Q{
+typedef NS_ENUM(NSUInteger, #{objc_type_name}) {
+#{ns_enum_cases}
+} NS_SWIFT_NAME(#{swift_type_name});}
+ end
+
+ def self.case(type_name, line)
+ if /(?\s*)(?\w+)(?.*)/ =~ line
+ # Drop redundant enum base prefixes:
+ # "MMD6OutputFormatFormatLatex" => "MMD6OutputFormatLatex"
+ # "MMD6ParserExtensionExtCritic" => "MMD6ParserExtensionCritic"
+ drop_prefix = casename.start_with?("EXT_", "FORMAT_")
+ camelized_case_name = casename.camelize(drop_prefix: drop_prefix)
+ return %Q{#{indent}#{type_name}#{camelized_case_name} = #{casename},}
+ end
+
+ return line
+ end
+end
+
+class Enum
+ include CustomStringConvertible
+ include NSEnum
+
+ attr_accessor :type, :cases
+
+ def initialize(type)
+ @type = type
+ @cases = []
+ end
+
+ def <<(line)
+ return if !Enum.is_enum_case(line)
+ cases << line
+ end
+
+ def self.is_enum_case(line)
+ return false if line.strip.empty?
+ return false if line.include?("}")
+ return false if line.include?("{")
+ return true
+ end
+end
+
+class Enums
+ attr_reader :enums
+
+ def initialize(stream)
+ lines = stream.readlines
+ @enums = parse_enums(lines)
+ end
+
+ def ns_enums
+ @enums.map(&:ns_enum)
+ end
+
+ def swift_descriptions
+ @enums.map(&:extension)
+ end
+
+ private
+
+ def parse_enums(lines)
+ enums = []
+ enumbuffer = nil
+ lines.each do |line|
+ type = line[/^\s*enum (\w+)\s*\{/, 1]
+ if !type.nil?
+ enumbuffer = Enum.new(type)
+ elsif !enumbuffer.nil?
+ if line.start_with?("}")
+ enums << enumbuffer
+ enumbuffer = nil
+ else
+ enumbuffer << line
+ end
+ else
+ # nop; discard line
+ end
+ end
+ return enums
+ end
+end
+
+def file_stream_from_argv
+ path = ARGV.shift
+ return nil if path.nil?
+ File.open(path, "r")
+end
+
+def fallback_stream
+ return nil unless File.exists?(FALLBACK_PATH)
+ File.open(FALLBACK_PATH, "r")
+end
+
+
+################################################################################
+## Script execution itself
+################################################################################
+
+
+input = file_stream_from_argv || fallback_stream
+if input.nil?
+ puts "Failed to read `#{FALLBACK_PATH}`"
+ exit -1
+end
+enums = Enums.new(input)
+input.close
+
+
+result = if options[:mode] == :nsenum
+ enums.ns_enums.join("\n")
+ elsif options[:mode] == :swift
+ enums.swift_descriptions.join("\n")
+ else
+ puts "Illegal mode: #{options[:mode]}"
+ exit -1
+ end
+
+
+output = if options[:outpath].nil?
+ $stdout
+ else
+ File.open(options[:outpath], "w")
+ end
+output.puts result
+output.close
diff --git a/test/make-tests.sh b/test/make-tests.sh
index 90aa014d..87e2f20d 100644
--- a/test/make-tests.sh
+++ b/test/make-tests.sh
@@ -7,8 +7,9 @@
# Date: 01/08/2003
#
# Modified by Fletcher T. Penney for proper error codes
+# Modified by Fletcher T. Penney to handle spaces in path names
-if test $# -eq 0 ; then FILES=*.c ; else FILES=$* ; fi
+if test $# -eq 0 ; then FILES=("*.c") ; else FILES=("$@") ; fi
echo '
@@ -20,7 +21,7 @@ echo '
'
-cat $FILES | grep '^void Test' |
+cat "${FILES[@]}" | grep '^void Test' |
sed -e 's/(.*$//' \
-e 's/$/(CuTest*);/' \
-e 's/^/extern /'
@@ -35,7 +36,7 @@ void RunAllTests(void)
int failCount = 0;
'
-cat $FILES | grep '^void Test' |
+cat "${FILES[@]}" | grep '^void Test' |
sed -e 's/^void //' \
-e 's/(.*$//' \
-e 's/^/ SUITE_ADD_TEST(suite, /' \
diff --git a/tests/MMD6Tests/Amps and Angles.fodt b/tests/MMD6Tests/Amps and Angles.fodt
index f2139442..2be8293f 100644
--- a/tests/MMD6Tests/Amps and Angles.fodt
+++ b/tests/MMD6Tests/Amps and Angles.fodt
@@ -307,6 +307,10 @@ office:mimetype="application/vnd.oasis.opendocument.text">
© ©
© ©
+
+15
+
+& and & and < and > in code span.
diff --git a/tests/MMD6Tests/Amps and Angles.html b/tests/MMD6Tests/Amps and Angles.html
index 10887c8d..2ed2ee83 100644
--- a/tests/MMD6Tests/Amps and Angles.html
+++ b/tests/MMD6Tests/Amps and Angles.html
@@ -37,6 +37,10 @@
© ©
+15
+
+& and & and < and > in code span.
+