Compare commits

...

1 Commits

Author SHA1 Message Date
Rob Phillips 86232b6556 Remove cmark, add pod version 2017-08-30 17:32:30 -07:00
41 changed files with 17 additions and 42518 deletions
+5 -6
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Down"
spec.summary = "Blazing fast Markdown rendering in Swift, built upon cmark."
spec.version = "0.3.5"
spec.summary = "Blazing fast Markdown rendering in Swift, built upon cmark 0.28.0"
spec.version = "0.4.0"
spec.homepage = "https://github.com/iwasrobbed/Down"
spec.license = { :type => "MIT", :file => "LICENSE" }
spec.authors = { "Rob Phillips" => "rob@desideratalabs.co" }
spec.authors = { "Rob Phillips" => "rob@robphillips.me" }
spec.source = { :git => "https://github.com/iwasrobbed/Down.git", :tag => "v" + spec.version.to_s }
spec.source_files = "Source/{cmark,Enums & Options,Extensions,Renderers}/**", "Source/*"
spec.source_files = "Source/{Enums & Options,Extensions,Renderers}/**", "Source/*"
spec.ios.source_files = "Source/Views/**"
spec.osx.source_files = "Source/Views/**"
spec.public_header_files = "Source/*.h"
@@ -15,8 +15,7 @@ Pod::Spec.new do |spec|
spec.osx.deployment_target = "10.11"
spec.requires_arc = true
spec.module_name = "Down"
spec.preserve_path = 'Source/cmark/module.modulemap'
spec.pod_target_xcconfig = { 'SWIFT_INCLUDE_PATHS' => '$(SRCROOT)/Down/Source/cmark/**' }
spec.ios.resource = 'Resources/DownView.bundle'
spec.osx.resource = 'Resources/DownView.bundle'
spec.dependency 'libcmark', '~> 0.28.0'
end
-158
View File
@@ -8,43 +8,6 @@
/* Begin PBXBuildFile section */
8A569F481E6B3ED2008BE2AC /* DownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43AE5D91CFFD0D0006E1522 /* DownView.swift */; };
8A569F491E6B3ED9008BE2AC /* blocks.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201EF71CFA5D63008EEC6E /* blocks.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F4A1E6B3ED9008BE2AC /* buffer.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201EF81CFA5D63008EEC6E /* buffer.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F4B1E6B3ED9008BE2AC /* buffer.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201EF91CFA5D63008EEC6E /* buffer.h */; };
8A569F4C1E6B3ED9008BE2AC /* chunk.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201EFB1CFA5D63008EEC6E /* chunk.h */; };
8A569F4D1E6B3ED9008BE2AC /* cmark.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201EFC1CFA5D63008EEC6E /* cmark.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F4E1E6B3ED9008BE2AC /* cmark.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201EFD1CFA5D63008EEC6E /* cmark.h */; };
8A569F4F1E6B3ED9008BE2AC /* cmark_ctype.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201EFE1CFA5D63008EEC6E /* cmark_ctype.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F501E6B3ED9008BE2AC /* cmark_ctype.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201EFF1CFA5D63008EEC6E /* cmark_ctype.h */; };
8A569F511E6B3ED9008BE2AC /* cmark_export.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F001CFA5D63008EEC6E /* cmark_export.h */; };
8A569F521E6B3ED9008BE2AC /* cmark_version.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F011CFA5D63008EEC6E /* cmark_version.h */; };
8A569F531E6B3ED9008BE2AC /* commonmark.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F021CFA5D63008EEC6E /* commonmark.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F541E6B3ED9008BE2AC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F031CFA5D63008EEC6E /* config.h */; };
8A569F551E6B3ED9008BE2AC /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F041CFA5D63008EEC6E /* debug.h */; };
8A569F561E6B3ED9008BE2AC /* houdini.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F061CFA5D63008EEC6E /* houdini.h */; };
8A569F571E6B3ED9008BE2AC /* houdini_href_e.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F071CFA5D63008EEC6E /* houdini_href_e.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F581E6B3ED9008BE2AC /* houdini_html_e.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F081CFA5D63008EEC6E /* houdini_html_e.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F591E6B3ED9008BE2AC /* houdini_html_u.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F091CFA5D63008EEC6E /* houdini_html_u.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F5A1E6B3ED9008BE2AC /* html.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F0A1CFA5D63008EEC6E /* html.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F5B1E6B3ED9008BE2AC /* html_unescape.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F0B1CFA5D63008EEC6E /* html_unescape.h */; };
8A569F5C1E6B3ED9008BE2AC /* inlines.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F0C1CFA5D63008EEC6E /* inlines.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F5D1E6B3ED9008BE2AC /* inlines.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F0D1CFA5D63008EEC6E /* inlines.h */; };
8A569F5E1E6B3ED9008BE2AC /* iterator.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F0E1CFA5D63008EEC6E /* iterator.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F5F1E6B3ED9008BE2AC /* iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F0F1CFA5D63008EEC6E /* iterator.h */; };
8A569F601E6B3ED9008BE2AC /* latex.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F101CFA5D63008EEC6E /* latex.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F611E6B3ED9008BE2AC /* man.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F111CFA5D63008EEC6E /* man.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F621E6B3ED9008BE2AC /* node.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F131CFA5D63008EEC6E /* node.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F631E6B3ED9008BE2AC /* node.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F141CFA5D63008EEC6E /* node.h */; };
8A569F641E6B3ED9008BE2AC /* parser.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F151CFA5D63008EEC6E /* parser.h */; };
8A569F651E6B3ED9008BE2AC /* references.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F161CFA5D63008EEC6E /* references.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F661E6B3ED9008BE2AC /* references.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F171CFA5D63008EEC6E /* references.h */; };
8A569F671E6B3ED9008BE2AC /* render.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F181CFA5D63008EEC6E /* render.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F681E6B3ED9008BE2AC /* render.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F191CFA5D63008EEC6E /* render.h */; };
8A569F691E6B3ED9008BE2AC /* scanners.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F1A1CFA5D63008EEC6E /* scanners.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F6A1E6B3ED9008BE2AC /* scanners.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F1B1CFA5D63008EEC6E /* scanners.h */; };
8A569F6B1E6B3ED9008BE2AC /* utf8.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F1C1CFA5D63008EEC6E /* utf8.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F6C1E6B3ED9008BE2AC /* utf8.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F1D1CFA5D63008EEC6E /* utf8.h */; };
8A569F6D1E6B3ED9008BE2AC /* xml.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F1E1CFA5D63008EEC6E /* xml.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F6E1E6B3EDE008BE2AC /* DownASTRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D486E9951CFDD4860059FD7C /* DownASTRenderable.swift */; };
8A569F6F1E6B3EDE008BE2AC /* DownAttributedStringRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4CF88971CFFAC2C00F07FD1 /* DownAttributedStringRenderable.swift */; };
8A569F701E6B3EDE008BE2AC /* DownCommonMarkRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4DC91131CFDED4B0091CE09 /* DownCommonMarkRenderable.swift */; };
@@ -105,44 +68,6 @@
D41689B51CFFE6BB00E5802B /* DownView.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = DownView.bundle; sourceTree = "<group>"; };
D4201EC51CFA59A5008EEC6E /* BindingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BindingTests.swift; sourceTree = "<group>"; };
D4201EF01CFA59F2008EEC6E /* Down.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Down.swift; sourceTree = "<group>"; };
D4201EF71CFA5D63008EEC6E /* blocks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocks.c; sourceTree = "<group>"; };
D4201EF81CFA5D63008EEC6E /* buffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = buffer.c; sourceTree = "<group>"; };
D4201EF91CFA5D63008EEC6E /* buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = buffer.h; sourceTree = "<group>"; };
D4201EFB1CFA5D63008EEC6E /* chunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chunk.h; sourceTree = "<group>"; };
D4201EFC1CFA5D63008EEC6E /* cmark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmark.c; sourceTree = "<group>"; };
D4201EFD1CFA5D63008EEC6E /* cmark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cmark.h; sourceTree = "<group>"; };
D4201EFE1CFA5D63008EEC6E /* cmark_ctype.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmark_ctype.c; sourceTree = "<group>"; };
D4201EFF1CFA5D63008EEC6E /* cmark_ctype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cmark_ctype.h; sourceTree = "<group>"; };
D4201F001CFA5D63008EEC6E /* cmark_export.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cmark_export.h; sourceTree = "<group>"; };
D4201F011CFA5D63008EEC6E /* cmark_version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cmark_version.h; sourceTree = "<group>"; };
D4201F021CFA5D63008EEC6E /* commonmark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = commonmark.c; sourceTree = "<group>"; };
D4201F031CFA5D63008EEC6E /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
D4201F041CFA5D63008EEC6E /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = "<group>"; };
D4201F061CFA5D63008EEC6E /* houdini.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = houdini.h; sourceTree = "<group>"; };
D4201F071CFA5D63008EEC6E /* houdini_href_e.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = houdini_href_e.c; sourceTree = "<group>"; };
D4201F081CFA5D63008EEC6E /* houdini_html_e.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = houdini_html_e.c; sourceTree = "<group>"; };
D4201F091CFA5D63008EEC6E /* houdini_html_u.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = houdini_html_u.c; sourceTree = "<group>"; };
D4201F0A1CFA5D63008EEC6E /* html.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = html.c; sourceTree = "<group>"; };
D4201F0B1CFA5D63008EEC6E /* html_unescape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = html_unescape.h; sourceTree = "<group>"; };
D4201F0C1CFA5D63008EEC6E /* inlines.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inlines.c; sourceTree = "<group>"; };
D4201F0D1CFA5D63008EEC6E /* inlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inlines.h; sourceTree = "<group>"; };
D4201F0E1CFA5D63008EEC6E /* iterator.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iterator.c; sourceTree = "<group>"; };
D4201F0F1CFA5D63008EEC6E /* iterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iterator.h; sourceTree = "<group>"; };
D4201F101CFA5D63008EEC6E /* latex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = latex.c; sourceTree = "<group>"; };
D4201F111CFA5D63008EEC6E /* man.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = man.c; sourceTree = "<group>"; };
D4201F131CFA5D63008EEC6E /* node.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = node.c; sourceTree = "<group>"; };
D4201F141CFA5D63008EEC6E /* node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = node.h; sourceTree = "<group>"; };
D4201F151CFA5D63008EEC6E /* parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parser.h; sourceTree = "<group>"; };
D4201F161CFA5D63008EEC6E /* references.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = references.c; sourceTree = "<group>"; };
D4201F171CFA5D63008EEC6E /* references.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = references.h; sourceTree = "<group>"; };
D4201F181CFA5D63008EEC6E /* render.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render.c; sourceTree = "<group>"; };
D4201F191CFA5D63008EEC6E /* render.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render.h; sourceTree = "<group>"; };
D4201F1A1CFA5D63008EEC6E /* scanners.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scanners.c; sourceTree = "<group>"; };
D4201F1B1CFA5D63008EEC6E /* scanners.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scanners.h; sourceTree = "<group>"; };
D4201F1C1CFA5D63008EEC6E /* utf8.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utf8.c; sourceTree = "<group>"; };
D4201F1D1CFA5D63008EEC6E /* utf8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utf8.h; sourceTree = "<group>"; };
D4201F1E1CFA5D63008EEC6E /* xml.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xml.c; sourceTree = "<group>"; };
D42869501CFF501200FACB4C /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
D438696B1D00D27700E95A1F /* StringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = "<group>"; };
D43AE5C91CFFAE4D006E1522 /* NSAttributedString+HTML.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+HTML.swift"; sourceTree = "<group>"; };
D43AE5D91CFFD0D0006E1522 /* DownView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownView.swift; sourceTree = "<group>"; };
@@ -232,7 +157,6 @@
D43AE5C81CFFAE39006E1522 /* Extensions */,
D44875E21CFA6B120037A624 /* Renderers */,
D43AE5CB1CFFD068006E1522 /* Views */,
D4201EF61CFA5D63008EEC6E /* cmark */,
);
path = Source;
sourceTree = "<group>";
@@ -249,51 +173,6 @@
path = Tests;
sourceTree = "<group>";
};
D4201EF61CFA5D63008EEC6E /* cmark */ = {
isa = PBXGroup;
children = (
D4201EF71CFA5D63008EEC6E /* blocks.c */,
D4201EF81CFA5D63008EEC6E /* buffer.c */,
D4201EF91CFA5D63008EEC6E /* buffer.h */,
D4201EFB1CFA5D63008EEC6E /* chunk.h */,
D4201EFC1CFA5D63008EEC6E /* cmark.c */,
D4201EFD1CFA5D63008EEC6E /* cmark.h */,
D4201EFE1CFA5D63008EEC6E /* cmark_ctype.c */,
D4201EFF1CFA5D63008EEC6E /* cmark_ctype.h */,
D4201F001CFA5D63008EEC6E /* cmark_export.h */,
D4201F011CFA5D63008EEC6E /* cmark_version.h */,
D4201F021CFA5D63008EEC6E /* commonmark.c */,
D4201F031CFA5D63008EEC6E /* config.h */,
D4201F041CFA5D63008EEC6E /* debug.h */,
D4201F061CFA5D63008EEC6E /* houdini.h */,
D4201F071CFA5D63008EEC6E /* houdini_href_e.c */,
D4201F081CFA5D63008EEC6E /* houdini_html_e.c */,
D4201F091CFA5D63008EEC6E /* houdini_html_u.c */,
D4201F0A1CFA5D63008EEC6E /* html.c */,
D4201F0B1CFA5D63008EEC6E /* html_unescape.h */,
D4201F0C1CFA5D63008EEC6E /* inlines.c */,
D4201F0D1CFA5D63008EEC6E /* inlines.h */,
D4201F0E1CFA5D63008EEC6E /* iterator.c */,
D4201F0F1CFA5D63008EEC6E /* iterator.h */,
D4201F101CFA5D63008EEC6E /* latex.c */,
D4201F111CFA5D63008EEC6E /* man.c */,
D42869501CFF501200FACB4C /* module.modulemap */,
D4201F131CFA5D63008EEC6E /* node.c */,
D4201F141CFA5D63008EEC6E /* node.h */,
D4201F151CFA5D63008EEC6E /* parser.h */,
D4201F161CFA5D63008EEC6E /* references.c */,
D4201F171CFA5D63008EEC6E /* references.h */,
D4201F181CFA5D63008EEC6E /* render.c */,
D4201F191CFA5D63008EEC6E /* render.h */,
D4201F1A1CFA5D63008EEC6E /* scanners.c */,
D4201F1B1CFA5D63008EEC6E /* scanners.h */,
D4201F1C1CFA5D63008EEC6E /* utf8.c */,
D4201F1D1CFA5D63008EEC6E /* utf8.h */,
D4201F1E1CFA5D63008EEC6E /* xml.c */,
);
path = cmark;
sourceTree = "<group>";
};
D43AE5C81CFFAE39006E1522 /* Extensions */ = {
isa = PBXGroup;
children = (
@@ -342,24 +221,6 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
8A569F551E6B3ED9008BE2AC /* debug.h in Headers */,
8A569F4C1E6B3ED9008BE2AC /* chunk.h in Headers */,
8A569F631E6B3ED9008BE2AC /* node.h in Headers */,
8A569F521E6B3ED9008BE2AC /* cmark_version.h in Headers */,
8A569F661E6B3ED9008BE2AC /* references.h in Headers */,
8A569F6A1E6B3ED9008BE2AC /* scanners.h in Headers */,
8A569F4B1E6B3ED9008BE2AC /* buffer.h in Headers */,
8A569F5D1E6B3ED9008BE2AC /* inlines.h in Headers */,
8A569F681E6B3ED9008BE2AC /* render.h in Headers */,
8A569F561E6B3ED9008BE2AC /* houdini.h in Headers */,
8A569F6C1E6B3ED9008BE2AC /* utf8.h in Headers */,
8A569F641E6B3ED9008BE2AC /* parser.h in Headers */,
8A569F5F1E6B3ED9008BE2AC /* iterator.h in Headers */,
8A569F541E6B3ED9008BE2AC /* config.h in Headers */,
8A569F511E6B3ED9008BE2AC /* cmark_export.h in Headers */,
8A569F4E1E6B3ED9008BE2AC /* cmark.h in Headers */,
8A569F501E6B3ED9008BE2AC /* cmark_ctype.h in Headers */,
8A569F5B1E6B3ED9008BE2AC /* html_unescape.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -464,39 +325,20 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8A569F611E6B3ED9008BE2AC /* man.c in Sources */,
8A569F761E6B3EE3008BE2AC /* NSAttributedString+HTML.swift in Sources */,
8A569F5A1E6B3ED9008BE2AC /* html.c in Sources */,
8A569F5E1E6B3ED9008BE2AC /* iterator.c in Sources */,
8A569F481E6B3ED2008BE2AC /* DownView.swift in Sources */,
8A569F591E6B3ED9008BE2AC /* houdini_html_u.c in Sources */,
8A569F621E6B3ED9008BE2AC /* node.c in Sources */,
8A569F6F1E6B3EDE008BE2AC /* DownAttributedStringRenderable.swift in Sources */,
8A569F721E6B3EDE008BE2AC /* DownHTMLRenderable.swift in Sources */,
8A569F581E6B3ED9008BE2AC /* houdini_html_e.c in Sources */,
8A569F531E6B3ED9008BE2AC /* commonmark.c in Sources */,
8A569F4A1E6B3ED9008BE2AC /* buffer.c in Sources */,
8A569F771E6B3EE3008BE2AC /* String+ToHTML.swift in Sources */,
8A569F751E6B3EDE008BE2AC /* DownRenderable.swift in Sources */,
8A569F741E6B3EDE008BE2AC /* DownXMLRenderable.swift in Sources */,
8A569F6B1E6B3ED9008BE2AC /* utf8.c in Sources */,
8A569F791E6B3EE7008BE2AC /* DownOptions.swift in Sources */,
8A569F601E6B3ED9008BE2AC /* latex.c in Sources */,
8A569F711E6B3EDE008BE2AC /* DownGroffRenderable.swift in Sources */,
8A569F691E6B3ED9008BE2AC /* scanners.c in Sources */,
8A569F701E6B3EDE008BE2AC /* DownCommonMarkRenderable.swift in Sources */,
8A569F7A1E6B3EEA008BE2AC /* Down.swift in Sources */,
8A569F731E6B3EDE008BE2AC /* DownLaTeXRenderable.swift in Sources */,
8A569F781E6B3EE7008BE2AC /* DownErrors.swift in Sources */,
8A569F5C1E6B3ED9008BE2AC /* inlines.c in Sources */,
8A569F571E6B3ED9008BE2AC /* houdini_href_e.c in Sources */,
8A569F4D1E6B3ED9008BE2AC /* cmark.c in Sources */,
8A569F6D1E6B3ED9008BE2AC /* xml.c in Sources */,
8A569F6E1E6B3EDE008BE2AC /* DownASTRenderable.swift in Sources */,
8A569F491E6B3ED9008BE2AC /* blocks.c in Sources */,
8A569F4F1E6B3ED9008BE2AC /* cmark_ctype.c in Sources */,
8A569F671E6B3ED9008BE2AC /* render.c in Sources */,
8A569F651E6B3ED9008BE2AC /* references.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+12 -8
View File
@@ -10,11 +10,17 @@
Blazing fast Markdown rendering in Swift, built upon [cmark](https://github.com/jgm/cmark).
Is your app using it? [Let me know!](mailto:rob@desideratalabs.co)
Is your app using it? [Let me know!](mailto:rob@robphillips.me)
### Installation
Quickly install using [CocoaPods](https://cocoapods.org):
First, you'll need to install [cmake](https://cmake.org/download/) which builds the underlying static library.
Once installed, add a symlink to use cmake from the command line:
>sudo "/Applications/CMake.app/Contents/bin/cmake-gui" --install
Then you can easily install using [CocoaPods](https://cocoapods.org):
```ruby
pod 'Down'
@@ -26,13 +32,11 @@ Or [Carthage](https://github.com/Carthage/Carthage):
github "iwasrobbed/Down"
```
Or manually install:
You'll need to build the static library using:
1. Clone this repository
2. Build the Down project
3. Add the resulting framework file to your project
4. ?
5. Profit
```shell
echo `pwd`\nsed -i '' 's/include <\\(cmark.*\\)>/include \"\\1\"/' src/cmark.h\nmkdir -p build; cd build && cmake -G Xcode ..
```
### Robust Performance
File diff suppressed because it is too large Load Diff
-312
View File
@@ -1,312 +0,0 @@
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "config.h"
#include "cmark_ctype.h"
#include "buffer.h"
/* Used as default value for cmark_strbuf->ptr so that people can always
* assume ptr is non-NULL and zero terminated even for new cmark_strbufs.
*/
unsigned char cmark_strbuf__initbuf[1];
#ifndef MIN
#define MIN(x, y) ((x < y) ? x : y)
#endif
void cmark_strbuf_init(cmark_strbuf *buf, bufsize_t initial_size) {
buf->asize = 0;
buf->size = 0;
buf->ptr = cmark_strbuf__initbuf;
if (initial_size > 0)
cmark_strbuf_grow(buf, initial_size);
}
void cmark_strbuf_overflow_err() {
fprintf(stderr, "String buffer overflow");
abort();
}
static CMARK_INLINE void S_strbuf_grow_by(cmark_strbuf *buf, size_t add) {
size_t target_size = (size_t)buf->size + add;
if (target_size < add /* Integer overflow. */
|| target_size > BUFSIZE_MAX /* Truncation overflow. */
) {
cmark_strbuf_overflow_err();
return; /* unreachable */
}
if ((bufsize_t)target_size >= buf->asize)
cmark_strbuf_grow(buf, (bufsize_t)target_size);
}
void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) {
unsigned char *new_ptr;
if (target_size < buf->asize)
return;
if (buf->asize == 0) {
new_ptr = NULL;
} else {
new_ptr = buf->ptr;
}
/* Oversize the buffer by 50% to guarantee amortized linear time
* complexity on append operations. */
size_t new_size = (size_t)target_size + (size_t)target_size / 2;
/* Account for terminating null byte. */
new_size += 1;
/* round allocation up to multiple of 8 */
new_size = (new_size + 7) & ~7;
if (new_size < (size_t)target_size /* Integer overflow. */
|| new_size > BUFSIZE_MAX /* Truncation overflow. */
) {
if (target_size >= BUFSIZE_MAX) {
/* No space for terminating null byte. */
cmark_strbuf_overflow_err();
return; /* unreachable */
}
/* Oversize by the maximum possible amount. */
new_size = BUFSIZE_MAX;
}
new_ptr = (unsigned char *)realloc(new_ptr, new_size);
if (!new_ptr) {
perror("realloc in cmark_strbuf_grow");
abort();
}
buf->asize = (bufsize_t)new_size;
buf->ptr = new_ptr;
}
bufsize_t cmark_strbuf_len(const cmark_strbuf *buf) { return buf->size; }
void cmark_strbuf_free(cmark_strbuf *buf) {
if (!buf)
return;
if (buf->ptr != cmark_strbuf__initbuf)
free(buf->ptr);
cmark_strbuf_init(buf, 0);
}
void cmark_strbuf_clear(cmark_strbuf *buf) {
buf->size = 0;
if (buf->asize > 0)
buf->ptr[0] = '\0';
}
void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data,
bufsize_t len) {
if (len <= 0 || data == NULL) {
cmark_strbuf_clear(buf);
} else {
if (data != buf->ptr) {
if (len >= buf->asize)
cmark_strbuf_grow(buf, len);
memmove(buf->ptr, data, len);
}
buf->size = len;
buf->ptr[buf->size] = '\0';
}
}
void cmark_strbuf_sets(cmark_strbuf *buf, const char *string) {
cmark_strbuf_set(buf, (const unsigned char *)string,
string ? cmark_strbuf_safe_strlen(string) : 0);
}
void cmark_strbuf_putc(cmark_strbuf *buf, int c) {
S_strbuf_grow_by(buf, 1);
buf->ptr[buf->size++] = (unsigned char)(c & 0xFF);
buf->ptr[buf->size] = '\0';
}
void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
bufsize_t len) {
if (len <= 0)
return;
S_strbuf_grow_by(buf, len);
memmove(buf->ptr + buf->size, data, len);
buf->size += len;
buf->ptr[buf->size] = '\0';
}
void cmark_strbuf_puts(cmark_strbuf *buf, const char *string) {
cmark_strbuf_put(buf, (const unsigned char *)string,
cmark_strbuf_safe_strlen(string));
}
void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize,
const cmark_strbuf *buf) {
bufsize_t copylen;
assert(buf);
if (!data || datasize <= 0)
return;
data[0] = '\0';
if (buf->size == 0 || buf->asize <= 0)
return;
copylen = buf->size;
if (copylen > datasize - 1)
copylen = datasize - 1;
memmove(data, buf->ptr, copylen);
data[copylen] = '\0';
}
void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b) {
cmark_strbuf t = *buf_a;
*buf_a = *buf_b;
*buf_b = t;
}
unsigned char *cmark_strbuf_detach(cmark_strbuf *buf) {
unsigned char *data = buf->ptr;
if (buf->asize == 0) {
/* return an empty string */
return (unsigned char *)calloc(1, 1);
}
cmark_strbuf_init(buf, 0);
return data;
}
int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b) {
int result = memcmp(a->ptr, b->ptr, MIN(a->size, b->size));
return (result != 0) ? result
: (a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0;
}
bufsize_t cmark_strbuf_strchr(const cmark_strbuf *buf, int c, bufsize_t pos) {
if (pos >= buf->size)
return -1;
if (pos < 0)
pos = 0;
const unsigned char *p =
(unsigned char *)memchr(buf->ptr + pos, c, buf->size - pos);
if (!p)
return -1;
return (bufsize_t)(p - (const unsigned char *)buf->ptr);
}
bufsize_t cmark_strbuf_strrchr(const cmark_strbuf *buf, int c, bufsize_t pos) {
if (pos < 0 || buf->size == 0)
return -1;
if (pos >= buf->size)
pos = buf->size - 1;
bufsize_t i;
for (i = pos; i >= 0; i--) {
if (buf->ptr[i] == (unsigned char)c)
return i;
}
return -1;
}
void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len) {
if (len < 0)
len = 0;
if (len < buf->size) {
buf->size = len;
buf->ptr[buf->size] = '\0';
}
}
void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n) {
if (n > 0) {
if (n > buf->size)
n = buf->size;
buf->size = buf->size - n;
if (buf->size)
memmove(buf->ptr, buf->ptr + n, buf->size);
buf->ptr[buf->size] = '\0';
}
}
void cmark_strbuf_rtrim(cmark_strbuf *buf) {
if (!buf->size)
return;
while (buf->size > 0) {
if (!cmark_isspace(buf->ptr[buf->size - 1]))
break;
buf->size--;
}
buf->ptr[buf->size] = '\0';
}
void cmark_strbuf_trim(cmark_strbuf *buf) {
bufsize_t i = 0;
if (!buf->size)
return;
while (i < buf->size && cmark_isspace(buf->ptr[i]))
i++;
cmark_strbuf_drop(buf, i);
cmark_strbuf_rtrim(buf);
}
// Destructively modify string, collapsing consecutive
// space and newline characters into a single space.
void cmark_strbuf_normalize_whitespace(cmark_strbuf *s) {
bool last_char_was_space = false;
bufsize_t r, w;
for (r = 0, w = 0; r < s->size; ++r) {
if (cmark_isspace(s->ptr[r])) {
if (!last_char_was_space) {
s->ptr[w++] = ' ';
last_char_was_space = true;
}
} else {
s->ptr[w++] = s->ptr[r];
last_char_was_space = false;
}
}
cmark_strbuf_truncate(s, w);
}
// Destructively unescape a string: remove backslashes before punctuation chars.
extern void cmark_strbuf_unescape(cmark_strbuf *buf) {
bufsize_t r, w;
for (r = 0, w = 0; r < buf->size; ++r) {
if (buf->ptr[r] == '\\' && cmark_ispunct(buf->ptr[r + 1]))
r++;
buf->ptr[w++] = buf->ptr[r];
}
cmark_strbuf_truncate(buf, w);
}
-93
View File
@@ -1,93 +0,0 @@
#ifndef CMARK_BUFFER_H
#define CMARK_BUFFER_H
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <limits.h>
#include "config.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef int bufsize_t;
typedef struct {
unsigned char *ptr;
bufsize_t asize, size;
} cmark_strbuf;
extern unsigned char cmark_strbuf__initbuf[];
#define GH_BUF_INIT \
{ cmark_strbuf__initbuf, 0, 0 }
#define BUFSIZE_MAX INT_MAX
/**
* Initialize a cmark_strbuf structure.
*
* For the cases where GH_BUF_INIT cannot be used to do static
* initialization.
*/
void cmark_strbuf_init(cmark_strbuf *buf, bufsize_t initial_size);
/**
* Grow the buffer to hold at least `target_size` bytes.
*/
void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size);
void cmark_strbuf_free(cmark_strbuf *buf);
void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b);
bufsize_t cmark_strbuf_len(const cmark_strbuf *buf);
int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b);
unsigned char *cmark_strbuf_detach(cmark_strbuf *buf);
void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize,
const cmark_strbuf *buf);
static CMARK_INLINE const char *cmark_strbuf_cstr(const cmark_strbuf *buf) {
return (char *)buf->ptr;
}
#define cmark_strbuf_at(buf, n) ((buf)->ptr[n])
void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data,
bufsize_t len);
void cmark_strbuf_sets(cmark_strbuf *buf, const char *string);
void cmark_strbuf_putc(cmark_strbuf *buf, int c);
void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
bufsize_t len);
void cmark_strbuf_puts(cmark_strbuf *buf, const char *string);
void cmark_strbuf_clear(cmark_strbuf *buf);
bufsize_t cmark_strbuf_strchr(const cmark_strbuf *buf, int c, bufsize_t pos);
bufsize_t cmark_strbuf_strrchr(const cmark_strbuf *buf, int c, bufsize_t pos);
void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n);
void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len);
void cmark_strbuf_rtrim(cmark_strbuf *buf);
void cmark_strbuf_trim(cmark_strbuf *buf);
void cmark_strbuf_normalize_whitespace(cmark_strbuf *s);
void cmark_strbuf_unescape(cmark_strbuf *s);
/* Print error and abort. */
void cmark_strbuf_overflow_err(void);
static CMARK_INLINE bufsize_t cmark_strbuf_check_bufsize(size_t size) {
if (size > BUFSIZE_MAX) {
cmark_strbuf_overflow_err();
}
return (bufsize_t)size;
}
static CMARK_INLINE bufsize_t cmark_strbuf_safe_strlen(const char *str) {
return cmark_strbuf_check_bufsize(strlen(str));
}
#ifdef __cplusplus
}
#endif
#endif
-115
View File
@@ -1,115 +0,0 @@
#ifndef CMARK_CHUNK_H
#define CMARK_CHUNK_H
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "cmark_ctype.h"
#include "buffer.h"
#define CMARK_CHUNK_EMPTY \
{ NULL, 0, 0 }
typedef struct {
unsigned char *data;
bufsize_t len;
bufsize_t alloc; // also implies a NULL-terminated string
} cmark_chunk;
static CMARK_INLINE void cmark_chunk_free(cmark_chunk *c) {
if (c->alloc)
free(c->data);
c->data = NULL;
c->alloc = 0;
c->len = 0;
}
static CMARK_INLINE void cmark_chunk_ltrim(cmark_chunk *c) {
assert(!c->alloc);
while (c->len && cmark_isspace(c->data[0])) {
c->data++;
c->len--;
}
}
static CMARK_INLINE void cmark_chunk_rtrim(cmark_chunk *c) {
while (c->len > 0) {
if (!cmark_isspace(c->data[c->len - 1]))
break;
c->len--;
}
}
static CMARK_INLINE void cmark_chunk_trim(cmark_chunk *c) {
cmark_chunk_ltrim(c);
cmark_chunk_rtrim(c);
}
static CMARK_INLINE bufsize_t cmark_chunk_strchr(cmark_chunk *ch, int c,
bufsize_t offset) {
const unsigned char *p =
(unsigned char *)memchr(ch->data + offset, c, ch->len - offset);
return p ? (bufsize_t)(p - ch->data) : ch->len;
}
static CMARK_INLINE const char *cmark_chunk_to_cstr(cmark_chunk *c) {
unsigned char *str;
if (c->alloc) {
return (char *)c->data;
}
str = (unsigned char *)malloc(c->len + 1);
if (str != NULL) {
if (c->len > 0) {
memcpy(str, c->data, c->len);
}
str[c->len] = 0;
}
c->data = str;
c->alloc = 1;
return (char *)str;
}
static CMARK_INLINE void cmark_chunk_set_cstr(cmark_chunk *c, const char *str) {
if (c->alloc) {
free(c->data);
}
if (str == NULL) {
c->len = 0;
c->data = NULL;
c->alloc = 0;
} else {
c->len = cmark_strbuf_safe_strlen(str);
c->data = (unsigned char *)malloc(c->len + 1);
c->alloc = 1;
memcpy(c->data, str, c->len + 1);
}
}
static CMARK_INLINE cmark_chunk cmark_chunk_literal(const char *data) {
bufsize_t len = data ? cmark_strbuf_safe_strlen(data) : 0;
cmark_chunk c = {(unsigned char *)data, len, 0};
return c;
}
static CMARK_INLINE cmark_chunk cmark_chunk_dup(const cmark_chunk *ch,
bufsize_t pos, bufsize_t len) {
cmark_chunk c = {ch->data + pos, len, 0};
return c;
}
static CMARK_INLINE cmark_chunk cmark_chunk_buf_detach(cmark_strbuf *buf) {
cmark_chunk c;
c.len = buf->size;
c.data = cmark_strbuf_detach(buf);
c.alloc = 1;
return c;
}
#endif
-23
View File
@@ -1,23 +0,0 @@
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include "node.h"
#include "houdini.h"
#include "cmark.h"
#include "buffer.h"
int cmark_version() { return CMARK_VERSION; }
const char *cmark_version_string() { return CMARK_VERSION_STRING; }
char *cmark_markdown_to_html(const char *text, size_t len, int options) {
cmark_node *doc;
char *result;
doc = cmark_parse_document(text, len, options);
result = cmark_render_html(doc, options);
cmark_node_free(doc);
return result;
}
-599
View File
@@ -1,599 +0,0 @@
#ifndef CMARK_H
#define CMARK_H
#include <stdio.h>
#include <cmark_export.h>
#include <cmark_version.h>
#ifdef __cplusplus
extern "C" {
#endif
/** # NAME
*
* **cmark** - CommonMark parsing, manipulating, and rendering
*/
/** # DESCRIPTION
*
* ## Simple Interface
*/
/** Convert 'text' (assumed to be a UTF-8 encoded string with length
* 'len') from CommonMark Markdown to HTML, returning a null-terminated,
* UTF-8-encoded string.
*/
CMARK_EXPORT
char *cmark_markdown_to_html(const char *text, size_t len, int options);
/** ## Node Structure
*/
typedef enum {
/* Error status */
CMARK_NODE_NONE,
/* Block */
CMARK_NODE_DOCUMENT,
CMARK_NODE_BLOCK_QUOTE,
CMARK_NODE_LIST,
CMARK_NODE_ITEM,
CMARK_NODE_CODE_BLOCK,
CMARK_NODE_HTML_BLOCK,
CMARK_NODE_CUSTOM_BLOCK,
CMARK_NODE_PARAGRAPH,
CMARK_NODE_HEADING,
CMARK_NODE_THEMATIC_BREAK,
CMARK_NODE_FIRST_BLOCK = CMARK_NODE_DOCUMENT,
CMARK_NODE_LAST_BLOCK = CMARK_NODE_THEMATIC_BREAK,
/* Inline */
CMARK_NODE_TEXT,
CMARK_NODE_SOFTBREAK,
CMARK_NODE_LINEBREAK,
CMARK_NODE_CODE,
CMARK_NODE_HTML_INLINE,
CMARK_NODE_CUSTOM_INLINE,
CMARK_NODE_EMPH,
CMARK_NODE_STRONG,
CMARK_NODE_LINK,
CMARK_NODE_IMAGE,
CMARK_NODE_FIRST_INLINE = CMARK_NODE_TEXT,
CMARK_NODE_LAST_INLINE = CMARK_NODE_IMAGE,
} cmark_node_type;
/* For backwards compatibility: */
#define CMARK_NODE_HEADER CMARK_NODE_HEADING
#define CMARK_NODE_HRULE CMARK_NODE_THEMATIC_BREAK
#define CMARK_NODE_HTML CMARK_NODE_HTML_BLOCK
#define CMARK_NODE_INLINE_HTML CMARK_NODE_HTML_INLINE
typedef enum {
CMARK_NO_LIST,
CMARK_BULLET_LIST,
CMARK_ORDERED_LIST
} cmark_list_type;
typedef enum {
CMARK_NO_DELIM,
CMARK_PERIOD_DELIM,
CMARK_PAREN_DELIM
} cmark_delim_type;
typedef struct cmark_node cmark_node;
typedef struct cmark_parser cmark_parser;
typedef struct cmark_iter cmark_iter;
/**
* ## Creating and Destroying Nodes
*/
/** Creates a new node of type 'type'. Note that the node may have
* other required properties, which it is the caller's responsibility
* to assign.
*/
CMARK_EXPORT cmark_node *cmark_node_new(cmark_node_type type);
/** Frees the memory allocated for a node and any children.
*/
CMARK_EXPORT void cmark_node_free(cmark_node *node);
/**
* ## Tree Traversal
*/
/** Returns the next node in the sequence after 'node', or NULL if
* there is none.
*/
CMARK_EXPORT cmark_node *cmark_node_next(cmark_node *node);
/** Returns the previous node in the sequence after 'node', or NULL if
* there is none.
*/
CMARK_EXPORT cmark_node *cmark_node_previous(cmark_node *node);
/** Returns the parent of 'node', or NULL if there is none.
*/
CMARK_EXPORT cmark_node *cmark_node_parent(cmark_node *node);
/** Returns the first child of 'node', or NULL if 'node' has no children.
*/
CMARK_EXPORT cmark_node *cmark_node_first_child(cmark_node *node);
/** Returns the last child of 'node', or NULL if 'node' has no children.
*/
CMARK_EXPORT cmark_node *cmark_node_last_child(cmark_node *node);
/**
* ## Iterator
*
* An iterator will walk through a tree of nodes, starting from a root
* node, returning one node at a time, together with information about
* whether the node is being entered or exited. The iterator will
* first descend to a child node, if there is one. When there is no
* child, the iterator will go to the next sibling. When there is no
* next sibling, the iterator will return to the parent (but with
* a 'cmark_event_type' of `CMARK_EVENT_EXIT`). The iterator will
* return `CMARK_EVENT_DONE` when it reaches the root node again.
* One natural application is an HTML renderer, where an `ENTER` event
* outputs an open tag and an `EXIT` event outputs a close tag.
* An iterator might also be used to transform an AST in some systematic
* way, for example, turning all level-3 headings into regular paragraphs.
*
* void
* usage_example(cmark_node *root) {
* cmark_event_type ev_type;
* cmark_iter *iter = cmark_iter_new(root);
*
* while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
* cmark_node *cur = cmark_iter_get_node(iter);
* // Do something with `cur` and `ev_type`
* }
*
* cmark_iter_free(iter);
* }
*
* Iterators will never return `EXIT` events for leaf nodes, which are nodes
* of type:
*
* * CMARK_NODE_HTML_BLOCK
* * CMARK_NODE_THEMATIC_BREAK
* * CMARK_NODE_CODE_BLOCK
* * CMARK_NODE_TEXT
* * CMARK_NODE_SOFTBREAK
* * CMARK_NODE_LINEBREAK
* * CMARK_NODE_CODE
* * CMARK_NODE_HTML_INLINE
*
* Nodes must only be modified after an `EXIT` event, or an `ENTER` event for
* leaf nodes.
*/
typedef enum {
CMARK_EVENT_NONE,
CMARK_EVENT_DONE,
CMARK_EVENT_ENTER,
CMARK_EVENT_EXIT
} cmark_event_type;
/** Creates a new iterator starting at 'root'. The current node and event
* type are undefined until `cmark_iter_next` is called for the first time.
*/
CMARK_EXPORT
cmark_iter *cmark_iter_new(cmark_node *root);
/** Frees the memory allocated for an iterator.
*/
CMARK_EXPORT
void cmark_iter_free(cmark_iter *iter);
/** Advances to the next node and returns the event type (`CMARK_EVENT_ENTER`,
* `CMARK_EVENT_EXIT` or `CMARK_EVENT_DONE`).
*/
CMARK_EXPORT
cmark_event_type cmark_iter_next(cmark_iter *iter);
/** Returns the current node.
*/
CMARK_EXPORT
cmark_node *cmark_iter_get_node(cmark_iter *iter);
/** Returns the current event type.
*/
CMARK_EXPORT
cmark_event_type cmark_iter_get_event_type(cmark_iter *iter);
/** Returns the root node.
*/
CMARK_EXPORT
cmark_node *cmark_iter_get_root(cmark_iter *iter);
/** Resets the iterator so that the current node is 'current' and
* the event type is 'event_type'. The new current node must be a
* descendant of the root node or the root node itself.
*/
CMARK_EXPORT
void cmark_iter_reset(cmark_iter *iter, cmark_node *current,
cmark_event_type event_type);
/**
* ## Accessors
*/
/** Returns the user data of 'node'.
*/
CMARK_EXPORT void *cmark_node_get_user_data(cmark_node *node);
/** Sets arbitrary user data for 'node'. Returns 1 on success,
* 0 on failure.
*/
CMARK_EXPORT int cmark_node_set_user_data(cmark_node *node, void *user_data);
/** Returns the type of 'node', or `CMARK_NODE_NONE` on error.
*/
CMARK_EXPORT cmark_node_type cmark_node_get_type(cmark_node *node);
/** Like 'cmark_node_get_type', but returns a string representation
of the type, or `"<unknown>"`.
*/
CMARK_EXPORT
const char *cmark_node_get_type_string(cmark_node *node);
/** Returns the string contents of 'node', or an empty
string if none is set.
*/
CMARK_EXPORT const char *cmark_node_get_literal(cmark_node *node);
/** Sets the string contents of 'node'. Returns 1 on success,
* 0 on failure.
*/
CMARK_EXPORT int cmark_node_set_literal(cmark_node *node, const char *content);
/** Returns the heading level of 'node', or 0 if 'node' is not a heading.
*/
CMARK_EXPORT int cmark_node_get_heading_level(cmark_node *node);
/* For backwards compatibility */
#define cmark_node_get_header_level cmark_node_get_heading_level
#define cmark_node_set_header_level cmark_node_set_heading_level
/** Sets the heading level of 'node', returning 1 on success and 0 on error.
*/
CMARK_EXPORT int cmark_node_set_heading_level(cmark_node *node, int level);
/** Returns the list type of 'node', or `CMARK_NO_LIST` if 'node'
* is not a list.
*/
CMARK_EXPORT cmark_list_type cmark_node_get_list_type(cmark_node *node);
/** Sets the list type of 'node', returning 1 on success and 0 on error.
*/
CMARK_EXPORT int cmark_node_set_list_type(cmark_node *node,
cmark_list_type type);
/** Returns the list delimiter type of 'node', or `CMARK_NO_DELIM` if 'node'
* is not a list.
*/
CMARK_EXPORT cmark_delim_type cmark_node_get_list_delim(cmark_node *node);
/** Sets the list delimiter type of 'node', returning 1 on success and 0
* on error.
*/
CMARK_EXPORT int cmark_node_set_list_delim(cmark_node *node,
cmark_delim_type delim);
/** Returns starting number of 'node', if it is an ordered list, otherwise 0.
*/
CMARK_EXPORT int cmark_node_get_list_start(cmark_node *node);
/** Sets starting number of 'node', if it is an ordered list. Returns 1
* on success, 0 on failure.
*/
CMARK_EXPORT int cmark_node_set_list_start(cmark_node *node, int start);
/** Returns 1 if 'node' is a tight list, 0 otherwise.
*/
CMARK_EXPORT int cmark_node_get_list_tight(cmark_node *node);
/** Sets the "tightness" of a list. Returns 1 on success, 0 on failure.
*/
CMARK_EXPORT int cmark_node_set_list_tight(cmark_node *node, int tight);
/** Returns the info string from a fenced code block.
*/
CMARK_EXPORT const char *cmark_node_get_fence_info(cmark_node *node);
/** Sets the info string in a fenced code block, returning 1 on
* success and 0 on failure.
*/
CMARK_EXPORT int cmark_node_set_fence_info(cmark_node *node, const char *info);
/** Returns the URL of a link or image 'node', or an empty string
if no URL is set.
*/
CMARK_EXPORT const char *cmark_node_get_url(cmark_node *node);
/** Sets the URL of a link or image 'node'. Returns 1 on success,
* 0 on failure.
*/
CMARK_EXPORT int cmark_node_set_url(cmark_node *node, const char *url);
/** Returns the title of a link or image 'node', or an empty
string if no title is set.
*/
CMARK_EXPORT const char *cmark_node_get_title(cmark_node *node);
/** Sets the title of a link or image 'node'. Returns 1 on success,
* 0 on failure.
*/
CMARK_EXPORT int cmark_node_set_title(cmark_node *node, const char *title);
/** Returns the literal "on enter" text for a custom 'node', or
an empty string if no on_enter is set.
*/
CMARK_EXPORT const char *cmark_node_get_on_enter(cmark_node *node);
/** Sets the literal text to render "on enter" for a custom 'node'.
Any children of the node will be rendered after this text.
Returns 1 on success 0 on failure.
*/
CMARK_EXPORT int cmark_node_set_on_enter(cmark_node *node,
const char *on_enter);
/** Returns the literal "on exit" text for a custom 'node', or
an empty string if no on_exit is set.
*/
CMARK_EXPORT const char *cmark_node_get_on_exit(cmark_node *node);
/** Sets the literal text to render "on exit" for a custom 'node'.
Any children of the node will be rendered before this text.
Returns 1 on success 0 on failure.
*/
CMARK_EXPORT int cmark_node_set_on_exit(cmark_node *node, const char *on_exit);
/** Returns the line on which 'node' begins.
*/
CMARK_EXPORT int cmark_node_get_start_line(cmark_node *node);
/** Returns the column at which 'node' begins.
*/
CMARK_EXPORT int cmark_node_get_start_column(cmark_node *node);
/** Returns the line on which 'node' ends.
*/
CMARK_EXPORT int cmark_node_get_end_line(cmark_node *node);
/** Returns the column at which 'node' ends.
*/
CMARK_EXPORT int cmark_node_get_end_column(cmark_node *node);
/**
* ## Tree Manipulation
*/
/** Unlinks a 'node', removing it from the tree, but not freeing its
* memory. (Use 'cmark_node_free' for that.)
*/
CMARK_EXPORT void cmark_node_unlink(cmark_node *node);
/** Inserts 'sibling' before 'node'. Returns 1 on success, 0 on failure.
*/
CMARK_EXPORT int cmark_node_insert_before(cmark_node *node,
cmark_node *sibling);
/** Inserts 'sibling' after 'node'. Returns 1 on success, 0 on failure.
*/
CMARK_EXPORT int cmark_node_insert_after(cmark_node *node, cmark_node *sibling);
/** Replaces 'oldnode' with 'newnode' and unlinks 'oldnode' (but does
* not free its memory).
* Returns 1 on success, 0 on failure.
*/
CMARK_EXPORT int cmark_node_replace(cmark_node *oldnode, cmark_node *newnode);
/** Adds 'child' to the beginning of the children of 'node'.
* Returns 1 on success, 0 on failure.
*/
CMARK_EXPORT int cmark_node_prepend_child(cmark_node *node, cmark_node *child);
/** Adds 'child' to the end of the children of 'node'.
* Returns 1 on success, 0 on failure.
*/
CMARK_EXPORT int cmark_node_append_child(cmark_node *node, cmark_node *child);
/** Consolidates adjacent text nodes.
*/
CMARK_EXPORT void cmark_consolidate_text_nodes(cmark_node *root);
/**
* ## Parsing
*
* Simple interface:
*
* cmark_node *document = cmark_parse_document("Hello *world*", 13,
* CMARK_OPT_DEFAULT);
*
* Streaming interface:
*
* cmark_parser *parser = cmark_parser_new(CMARK_OPT_DEFAULT);
* FILE *fp = fopen("myfile.md", "rb");
* while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
* cmark_parser_feed(parser, buffer, bytes);
* if (bytes < sizeof(buffer)) {
* break;
* }
* }
* document = cmark_parser_finish(parser);
* cmark_parser_free(parser);
*/
/** Creates a new parser object.
*/
CMARK_EXPORT
cmark_parser *cmark_parser_new(int options);
/** Frees memory allocated for a parser object.
*/
CMARK_EXPORT
void cmark_parser_free(cmark_parser *parser);
/** Feeds a string of length 'len' to 'parser'.
*/
CMARK_EXPORT
void cmark_parser_feed(cmark_parser *parser, const char *buffer, size_t len);
/** Finish parsing and return a pointer to a tree of nodes.
*/
CMARK_EXPORT
cmark_node *cmark_parser_finish(cmark_parser *parser);
/** Parse a CommonMark document in 'buffer' of length 'len'.
* Returns a pointer to a tree of nodes.
*/
CMARK_EXPORT
cmark_node *cmark_parse_document(const char *buffer, size_t len, int options);
/** Parse a CommonMark document in file 'f', returning a pointer to
* a tree of nodes.
*/
CMARK_EXPORT
cmark_node *cmark_parse_file(FILE *f, int options);
/**
* ## Rendering
*/
/** Render a 'node' tree as XML.
*/
CMARK_EXPORT
char *cmark_render_xml(cmark_node *root, int options);
/** Render a 'node' tree as an HTML fragment. It is up to the user
* to add an appropriate header and footer.
*/
CMARK_EXPORT
char *cmark_render_html(cmark_node *root, int options);
/** Render a 'node' tree as a groff man page, without the header.
*/
CMARK_EXPORT
char *cmark_render_man(cmark_node *root, int options, int width);
/** Render a 'node' tree as a commonmark document.
*/
CMARK_EXPORT
char *cmark_render_commonmark(cmark_node *root, int options, int width);
/** Render a 'node' tree as a LaTeX document.
*/
CMARK_EXPORT
char *cmark_render_latex(cmark_node *root, int options, int width);
/**
* ## Options
*/
/** Default options.
*/
#define CMARK_OPT_DEFAULT 0
/**
* ### Options affecting rendering
*/
/** Include a `data-sourcepos` attribute on all block elements.
*/
#define CMARK_OPT_SOURCEPOS (1 << 1)
/** Render `softbreak` elements as hard line breaks.
*/
#define CMARK_OPT_HARDBREAKS (1 << 2)
/** Suppress raw HTML and unsafe links (`javascript:`, `vbscript:`,
* `file:`, and `data:`, except for `image/png`, `image/gif`,
* `image/jpeg`, or `image/webp` mime types). Raw HTML is replaced
* by a placeholder HTML comment. Unsafe links are replaced by
* empty strings.
*/
#define CMARK_OPT_SAFE (1 << 3)
/**
* ### Options affecting parsing
*/
/** Normalize tree by consolidating adjacent text nodes.
*/
#define CMARK_OPT_NORMALIZE (1 << 8)
/** Validate UTF-8 in the input before parsing, replacing illegal
* sequences with the replacement character U+FFFD.
*/
#define CMARK_OPT_VALIDATE_UTF8 (1 << 9)
/** Convert straight quotes to curly, --- to em dashes, -- to en dashes.
*/
#define CMARK_OPT_SMART (1 << 10)
/**
* ## Version information
*/
/** The library version as integer for runtime checks. Also available as
* macro CMARK_VERSION for compile time checks.
*
* * Bits 16-23 contain the major version.
* * Bits 8-15 contain the minor version.
* * Bits 0-7 contain the patchlevel.
*
* In hexadecimal format, the number 0x010203 represents version 1.2.3.
*/
CMARK_EXPORT
int cmark_version();
/** The library version string for runtime checks. Also available as
* macro CMARK_VERSION_STRING for compile time checks.
*/
CMARK_EXPORT
const char *cmark_version_string();
/** # AUTHORS
*
* John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
*/
#ifndef CMARK_NO_SHORT_NAMES
#define NODE_DOCUMENT CMARK_NODE_DOCUMENT
#define NODE_BLOCK_QUOTE CMARK_NODE_BLOCK_QUOTE
#define NODE_LIST CMARK_NODE_LIST
#define NODE_ITEM CMARK_NODE_ITEM
#define NODE_CODE_BLOCK CMARK_NODE_CODE_BLOCK
#define NODE_HTML_BLOCK CMARK_NODE_HTML_BLOCK
#define NODE_CUSTOM_BLOCK CMARK_NODE_CUSTOM_BLOCK
#define NODE_PARAGRAPH CMARK_NODE_PARAGRAPH
#define NODE_HEADING CMARK_NODE_HEADING
#define NODE_HEADER CMARK_NODE_HEADER
#define NODE_THEMATIC_BREAK CMARK_NODE_THEMATIC_BREAK
#define NODE_HRULE CMARK_NODE_HRULE
#define NODE_TEXT CMARK_NODE_TEXT
#define NODE_SOFTBREAK CMARK_NODE_SOFTBREAK
#define NODE_LINEBREAK CMARK_NODE_LINEBREAK
#define NODE_CODE CMARK_NODE_CODE
#define NODE_HTML_INLINE CMARK_NODE_HTML_INLINE
#define NODE_CUSTOM_INLINE CMARK_NODE_CUSTOM_INLINE
#define NODE_EMPH CMARK_NODE_EMPH
#define NODE_STRONG CMARK_NODE_STRONG
#define NODE_LINK CMARK_NODE_LINK
#define NODE_IMAGE CMARK_NODE_IMAGE
#define BULLET_LIST CMARK_BULLET_LIST
#define ORDERED_LIST CMARK_ORDERED_LIST
#define PERIOD_DELIM CMARK_PERIOD_DELIM
#define PAREN_DELIM CMARK_PAREN_DELIM
#endif
#ifdef __cplusplus
}
#endif
#endif
-42
View File
@@ -1,42 +0,0 @@
#include <stdint.h>
#include "cmark_ctype.h"
/** 1 = space, 2 = punct, 3 = digit, 4 = alpha, 0 = other
*/
static const uint8_t cmark_ctype_class[256] = {
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
/* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
/* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 2 */ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* 3 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2,
/* 4 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
/* 5 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2,
/* 6 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
/* 7 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0,
/* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/**
* Returns 1 if c is a "whitespace" character as defined by the spec.
*/
int cmark_isspace(char c) { return cmark_ctype_class[(uint8_t)c] == 1; }
/**
* Returns 1 if c is an ascii punctuation character.
*/
int cmark_ispunct(char c) { return cmark_ctype_class[(uint8_t)c] == 2; }
int cmark_isalnum(char c) {
uint8_t result;
result = cmark_ctype_class[(uint8_t)c];
return (result == 3 || result == 4);
}
int cmark_isdigit(char c) { return cmark_ctype_class[(uint8_t)c] == 3; }
-24
View File
@@ -1,24 +0,0 @@
#ifndef CMARK_CMARK_CTYPE_H
#define CMARK_CMARK_CTYPE_H
#ifdef __cplusplus
extern "C" {
#endif
/** Locale-independent versions of functions from ctype.h.
* We want cmark to behave the same no matter what the system locale.
*/
int cmark_isspace(char c);
int cmark_ispunct(char c);
int cmark_isalnum(char c);
int cmark_isdigit(char c);
#ifdef __cplusplus
}
#endif
#endif
-41
View File
@@ -1,41 +0,0 @@
#ifndef CMARK_EXPORT_H
#define CMARK_EXPORT_H
#ifdef CMARK_STATIC_DEFINE
# define CMARK_EXPORT
# define CMARK_NO_EXPORT
#else
# ifndef CMARK_EXPORT
# ifdef libcmark_EXPORTS
/* We are building this library */
# define CMARK_EXPORT __attribute__((visibility("default")))
# else
/* We are using this library */
# define CMARK_EXPORT __attribute__((visibility("default")))
# endif
# endif
# ifndef CMARK_NO_EXPORT
# define CMARK_NO_EXPORT __attribute__((visibility("hidden")))
# endif
#endif
#ifndef CMARK_DEPRECATED
# define CMARK_DEPRECATED __attribute__ ((__deprecated__))
#endif
#ifndef CMARK_DEPRECATED_EXPORT
# define CMARK_DEPRECATED_EXPORT CMARK_EXPORT CMARK_DEPRECATED
#endif
#ifndef CMARK_DEPRECATED_NO_EXPORT
# define CMARK_DEPRECATED_NO_EXPORT CMARK_NO_EXPORT CMARK_DEPRECATED
#endif
#define DEFINE_NO_DEPRECATED 0
#if DEFINE_NO_DEPRECATED
# define CMARK_NO_DEPRECATED
#endif
#endif
-7
View File
@@ -1,7 +0,0 @@
#ifndef CMARK_VERSION_H
#define CMARK_VERSION_H
#define CMARK_VERSION ((0 << 16) | (25 << 8) | 2)
#define CMARK_VERSION_STRING "0.25.2"
#endif
-461
View File
@@ -1,461 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include "config.h"
#include "cmark.h"
#include "node.h"
#include "buffer.h"
#include "utf8.h"
#include "scanners.h"
#include "render.h"
#define safe_strlen(s) cmark_strbuf_safe_strlen(s)
#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
#define LIT(s) renderer->out(renderer, s, false, LITERAL)
#define CR() renderer->cr(renderer)
#define BLANKLINE() renderer->blankline(renderer)
#define ENCODED_SIZE 20
#define LISTMARKER_SIZE 20
// Functions to convert cmark_nodes to commonmark strings.
static CMARK_INLINE void outc(cmark_renderer *renderer, cmark_escaping escape,
int32_t c, unsigned char nextc) {
bool needs_escaping = false;
bool follows_digit =
renderer->buffer->size > 0 &&
cmark_isdigit(renderer->buffer->ptr[renderer->buffer->size - 1]);
char encoded[ENCODED_SIZE];
needs_escaping =
escape != LITERAL &&
((escape == NORMAL &&
(c == '*' || c == '_' || c == '[' || c == ']' || c == '#' || c == '<' ||
c == '>' || c == '\\' || c == '`' || c == '!' ||
(c == '&' && isalpha(nextc)) || (c == '!' && nextc == '[') ||
(renderer->begin_content && (c == '-' || c == '+' || c == '=') &&
// begin_content doesn't get set to false til we've passed digits
// at the beginning of line, so...
!follows_digit) ||
(renderer->begin_content && (c == '.' || c == ')') && follows_digit &&
(nextc == 0 || cmark_isspace(nextc))))) ||
(escape == URL && (c == '`' || c == '<' || c == '>' || isspace(c) ||
c == '\\' || c == ')' || c == '(')) ||
(escape == TITLE &&
(c == '`' || c == '<' || c == '>' || c == '"' || c == '\\')));
if (needs_escaping) {
if (isspace(c)) {
// use percent encoding for spaces
snprintf(encoded, ENCODED_SIZE, "%%%2x", c);
cmark_strbuf_puts(renderer->buffer, encoded);
renderer->column += 3;
} else {
cmark_render_ascii(renderer, "\\");
cmark_render_code_point(renderer, c);
}
} else {
cmark_render_code_point(renderer, c);
}
}
static int longest_backtick_sequence(const char *code) {
int longest = 0;
int current = 0;
size_t i = 0;
size_t code_len = safe_strlen(code);
while (i <= code_len) {
if (code[i] == '`') {
current++;
} else {
if (current > longest) {
longest = current;
}
current = 0;
}
i++;
}
return longest;
}
static int shortest_unused_backtick_sequence(const char *code) {
int32_t used = 1;
int current = 0;
size_t i = 0;
size_t code_len = safe_strlen(code);
while (i <= code_len) {
if (code[i] == '`') {
current++;
} else {
if (current) {
used |= (1 << current);
}
current = 0;
}
i++;
}
// return number of first bit that is 0:
i = 0;
while (used & 1) {
used = used >> 1;
i++;
}
return (int)i;
}
static bool is_autolink(cmark_node *node) {
cmark_chunk *title;
cmark_chunk *url;
cmark_node *link_text;
char *realurl;
int realurllen;
if (node->type != CMARK_NODE_LINK) {
return false;
}
url = &node->as.link.url;
if (url->len == 0 || scan_scheme(url, 0) == 0) {
return false;
}
title = &node->as.link.title;
// if it has a title, we can't treat it as an autolink:
if (title->len > 0) {
return false;
}
link_text = node->first_child;
if (link_text == NULL) {
return false;
}
cmark_consolidate_text_nodes(link_text);
realurl = (char *)url->data;
realurllen = url->len;
if (strncmp(realurl, "mailto:", 7) == 0) {
realurl += 7;
realurllen -= 7;
}
return (realurllen == link_text->as.literal.len &&
strncmp(realurl, (char *)link_text->as.literal.data,
link_text->as.literal.len) == 0);
}
// if node is a block node, returns node.
// otherwise returns first block-level node that is an ancestor of node.
// if there is no block-level ancestor, returns NULL.
static cmark_node *get_containing_block(cmark_node *node) {
while (node) {
if (node->type >= CMARK_NODE_FIRST_BLOCK &&
node->type <= CMARK_NODE_LAST_BLOCK) {
return node;
} else {
node = node->parent;
}
}
return NULL;
}
static int S_render_node(cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
cmark_node *tmp;
int list_number;
cmark_delim_type list_delim;
int numticks;
int i;
bool entering = (ev_type == CMARK_EVENT_ENTER);
const char *info, *code, *title;
size_t info_len, code_len;
char listmarker[LISTMARKER_SIZE];
char *emph_delim;
bufsize_t marker_width;
// Don't adjust tight list status til we've started the list.
// Otherwise we loose the blank line between a paragraph and
// a following list.
if (!(node->type == CMARK_NODE_ITEM && node->prev == NULL && entering)) {
tmp = get_containing_block(node);
renderer->in_tight_list_item =
tmp && // tmp might be NULL if there is no containing block
((tmp->type == CMARK_NODE_ITEM &&
cmark_node_get_list_tight(tmp->parent)) ||
(tmp && tmp->parent && tmp->parent->type == CMARK_NODE_ITEM &&
cmark_node_get_list_tight(tmp->parent->parent)));
}
switch (node->type) {
case CMARK_NODE_DOCUMENT:
break;
case CMARK_NODE_BLOCK_QUOTE:
if (entering) {
LIT("> ");
renderer->begin_content = true;
cmark_strbuf_puts(renderer->prefix, "> ");
} else {
cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 2);
BLANKLINE();
}
break;
case CMARK_NODE_LIST:
if (!entering && node->next && (node->next->type == CMARK_NODE_CODE_BLOCK ||
node->next->type == CMARK_NODE_LIST)) {
// this ensures that a following code block or list will be
// inteprereted correctly.
CR();
LIT("<!-- end list -->");
BLANKLINE();
}
break;
case CMARK_NODE_ITEM:
if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
marker_width = 4;
} else {
list_number = cmark_node_get_list_start(node->parent);
list_delim = cmark_node_get_list_delim(node->parent);
tmp = node;
while (tmp->prev) {
tmp = tmp->prev;
list_number += 1;
}
// we ensure a width of at least 4 so
// we get nice transition from single digits
// to double
snprintf(listmarker, LISTMARKER_SIZE, "%d%s%s", list_number,
list_delim == CMARK_PAREN_DELIM ? ")" : ".",
list_number < 10 ? " " : " ");
marker_width = safe_strlen(listmarker);
}
if (entering) {
if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
LIT(" - ");
renderer->begin_content = true;
} else {
LIT(listmarker);
renderer->begin_content = true;
}
for (i = marker_width; i--;) {
cmark_strbuf_putc(renderer->prefix, ' ');
}
} else {
cmark_strbuf_truncate(renderer->prefix,
renderer->prefix->size - marker_width);
CR();
}
break;
case CMARK_NODE_HEADING:
if (entering) {
for (i = cmark_node_get_heading_level(node); i > 0; i--) {
LIT("#");
}
LIT(" ");
renderer->begin_content = true;
renderer->no_wrap = true;
} else {
renderer->no_wrap = false;
BLANKLINE();
}
break;
case CMARK_NODE_CODE_BLOCK:
BLANKLINE();
info = cmark_node_get_fence_info(node);
info_len = safe_strlen(info);
code = cmark_node_get_literal(node);
code_len = safe_strlen(code);
// use indented form if no info, and code doesn't
// begin or end with a blank line, and code isn't
// first thing in a list item
if (info_len == 0 &&
(code_len > 2 && !isspace((unsigned char)code[0]) &&
!(isspace((unsigned char)code[code_len - 1]) && isspace((unsigned char)code[code_len - 2]))) &&
!(node->prev == NULL && node->parent &&
node->parent->type == CMARK_NODE_ITEM)) {
LIT(" ");
cmark_strbuf_puts(renderer->prefix, " ");
OUT(cmark_node_get_literal(node), false, LITERAL);
cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 4);
} else {
numticks = longest_backtick_sequence(code) + 1;
if (numticks < 3) {
numticks = 3;
}
for (i = 0; i < numticks; i++) {
LIT("`");
}
LIT(" ");
OUT(info, false, LITERAL);
CR();
OUT(cmark_node_get_literal(node), false, LITERAL);
CR();
for (i = 0; i < numticks; i++) {
LIT("`");
}
}
BLANKLINE();
break;
case CMARK_NODE_HTML_BLOCK:
BLANKLINE();
OUT(cmark_node_get_literal(node), false, LITERAL);
BLANKLINE();
break;
case CMARK_NODE_CUSTOM_BLOCK:
BLANKLINE();
OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node),
false, LITERAL);
BLANKLINE();
break;
case CMARK_NODE_THEMATIC_BREAK:
BLANKLINE();
LIT("-----");
BLANKLINE();
break;
case CMARK_NODE_PARAGRAPH:
if (!entering) {
BLANKLINE();
}
break;
case CMARK_NODE_TEXT:
OUT(cmark_node_get_literal(node), true, NORMAL);
break;
case CMARK_NODE_LINEBREAK:
if (!(CMARK_OPT_HARDBREAKS & options)) {
LIT(" ");
}
CR();
break;
case CMARK_NODE_SOFTBREAK:
if (renderer->width == 0 && !(CMARK_OPT_HARDBREAKS & options)) {
CR();
} else {
OUT(" ", true, LITERAL);
}
break;
case CMARK_NODE_CODE:
code = cmark_node_get_literal(node);
code_len = safe_strlen(code);
numticks = shortest_unused_backtick_sequence(code);
for (i = 0; i < numticks; i++) {
LIT("`");
}
if (code_len == 0 || code[0] == '`') {
LIT(" ");
}
OUT(cmark_node_get_literal(node), true, LITERAL);
if (code_len == 0 || code[code_len - 1] == '`') {
LIT(" ");
}
for (i = 0; i < numticks; i++) {
LIT("`");
}
break;
case CMARK_NODE_HTML_INLINE:
OUT(cmark_node_get_literal(node), false, LITERAL);
break;
case CMARK_NODE_CUSTOM_INLINE:
OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node),
false, LITERAL);
break;
case CMARK_NODE_STRONG:
if (entering) {
LIT("**");
} else {
LIT("**");
}
break;
case CMARK_NODE_EMPH:
// If we have EMPH(EMPH(x)), we need to use *_x_*
// because **x** is STRONG(x):
if (node->parent && node->parent->type == CMARK_NODE_EMPH &&
node->next == NULL && node->prev == NULL) {
emph_delim = "_";
} else {
emph_delim = "*";
}
if (entering) {
LIT(emph_delim);
} else {
LIT(emph_delim);
}
break;
case CMARK_NODE_LINK:
if (is_autolink(node)) {
if (entering) {
LIT("<");
if (strncmp(cmark_node_get_url(node), "mailto:", 7) == 0) {
LIT((const char *)cmark_node_get_url(node) + 7);
} else {
LIT((const char *)cmark_node_get_url(node));
}
LIT(">");
// return signal to skip contents of node...
return 0;
}
} else {
if (entering) {
LIT("[");
} else {
LIT("](");
OUT(cmark_node_get_url(node), false, URL);
title = cmark_node_get_title(node);
if (safe_strlen(title) > 0) {
LIT(" \"");
OUT(title, false, TITLE);
LIT("\"");
}
LIT(")");
}
}
break;
case CMARK_NODE_IMAGE:
if (entering) {
LIT("![");
} else {
LIT("](");
OUT(cmark_node_get_url(node), false, URL);
title = cmark_node_get_title(node);
if (safe_strlen(title) > 0) {
OUT(" \"", true, LITERAL);
OUT(title, false, TITLE);
LIT("\"");
}
LIT(")");
}
break;
default:
assert(false);
break;
}
return 1;
}
char *cmark_render_commonmark(cmark_node *root, int options, int width) {
if (options & CMARK_OPT_HARDBREAKS) {
// disable breaking on width, since it has
// a different meaning with OPT_HARDBREAKS
width = 0;
}
return cmark_render(root, options, width, outc, S_render_node);
}
-76
View File
@@ -1,76 +0,0 @@
#ifndef CMARK_CONFIG_H
#define CMARK_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#define HAVE_STDBOOL_H
#ifdef HAVE_STDBOOL_H
#include <stdbool.h>
#elif !defined(__cplusplus)
typedef char bool;
#endif
#define HAVE___BUILTIN_EXPECT
#define HAVE___ATTRIBUTE__
#ifdef HAVE___ATTRIBUTE__
#define CMARK_ATTRIBUTE(list) __attribute__ (list)
#else
#define CMARK_ATTRIBUTE(list)
#endif
#ifndef CMARK_INLINE
#if defined(_MSC_VER) && !defined(__cplusplus)
#define CMARK_INLINE __inline
#else
#define CMARK_INLINE inline
#endif
#endif
/* snprintf and vsnprintf fallbacks for MSVC before 2015,
due to Valentin Milea http://stackoverflow.com/questions/2915672/
*/
#if defined(_MSC_VER) && _MSC_VER < 1900
#include <stdio.h>
#include <stdarg.h>
#define snprintf c99_snprintf
#define vsnprintf c99_vsnprintf
CMARK_INLINE int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap)
{
int count = -1;
if (size != 0)
count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
if (count == -1)
count = _vscprintf(format, ap);
return count;
}
CMARK_INLINE int c99_snprintf(char *outBuf, size_t size, const char *format, ...)
{
int count;
va_list ap;
va_start(ap, format);
count = c99_vsnprintf(outBuf, size, format, ap);
va_end(ap);
return count;
}
#endif
#ifdef __cplusplus
}
#endif
#endif
-36
View File
@@ -1,36 +0,0 @@
#ifndef CMARK_DEBUG_H
#define CMARK_DEBUG_H
#include <stdio.h>
#include <errno.h>
#include <string.h>
#ifdef NDEBUG
#define debug(M, ...)
#else
#define debug(M, ...) \
fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#endif
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
#define log_err(M, ...) \
fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, \
clean_errno(), ##__VA_ARGS__)
#define log_warn(M, ...) \
fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, \
clean_errno(), ##__VA_ARGS__)
#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, \
__LINE__, ##__VA_ARGS__)
#define check(A, M, ...) \
if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto error; }
#define sentinel(M, ...) \
{ log_err(M, ##__VA_ARGS__); errno=0; goto error; }
#define check_debug(A, M, ...) \
if(!(A)) { debug(M, ##__VA_ARGS__); errno=0; goto error; }
#endif
-51
View File
@@ -1,51 +0,0 @@
#ifndef CMARK_HOUDINI_H
#define CMARK_HOUDINI_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "config.h"
#include "buffer.h"
#ifdef HAVE___BUILTIN_EXPECT
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
#ifdef HOUDINI_USE_LOCALE
#define _isxdigit(c) isxdigit(c)
#define _isdigit(c) isdigit(c)
#else
/*
* Helper _isdigit methods -- do not trust the current locale
* */
#define _isxdigit(c) (strchr("0123456789ABCDEFabcdef", (c)) != NULL)
#define _isdigit(c) ((c) >= '0' && (c) <= '9')
#endif
#define HOUDINI_ESCAPED_SIZE(x) (((x)*12) / 10)
#define HOUDINI_UNESCAPED_SIZE(x) (x)
extern bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src,
bufsize_t size);
extern int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src,
bufsize_t size);
extern int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src,
bufsize_t size, int secure);
extern int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src,
bufsize_t size);
extern void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src,
bufsize_t size);
extern int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src,
bufsize_t size);
#ifdef __cplusplus
}
#endif
#endif
-100
View File
@@ -1,100 +0,0 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "houdini.h"
/*
* The following characters will not be escaped:
*
* -_.+!*'(),%#@?=;:/,+&$ alphanum
*
* Note that this character set is the addition of:
*
* - The characters which are safe to be in an URL
* - The characters which are *not* safe to be in
* an URL because they are RESERVED characters.
*
* We asume (lazily) that any RESERVED char that
* appears inside an URL is actually meant to
* have its native function (i.e. as an URL
* component/separator) and hence needs no escaping.
*
* There are two exceptions: the chacters & (amp)
* and ' (single quote) do not appear in the table.
* They are meant to appear in the URL as components,
* yet they require special HTML-entity escaping
* to generate valid HTML markup.
*
* All other characters will be escaped to %XX.
*
*/
static const char HREF_SAFE[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src, bufsize_t size) {
static const uint8_t hex_chars[] = "0123456789ABCDEF";
bufsize_t i = 0, org;
uint8_t hex_str[3];
hex_str[0] = '%';
while (i < size) {
org = i;
while (i < size && HREF_SAFE[src[i]] != 0)
i++;
if (likely(i > org))
cmark_strbuf_put(ob, src + org, i - org);
/* escaping */
if (i >= size)
break;
switch (src[i]) {
/* amp appears all the time in URLs, but needs
* HTML-entity escaping to be inside an href */
case '&':
cmark_strbuf_puts(ob, "&amp;");
break;
/* the single quote is a valid URL character
* according to the standard; it needs HTML
* entity escaping too */
case '\'':
cmark_strbuf_puts(ob, "&#x27;");
break;
/* the space can be escaped to %20 or a plus
* sign. we're going with the generic escape
* for now. the plus thing is more commonly seen
* when building GET strings */
#if 0
case ' ':
cmark_strbuf_putc(ob, '+');
break;
#endif
/* every other character goes with a %XX escaping */
default:
hex_str[1] = hex_chars[(src[i] >> 4) & 0xF];
hex_str[2] = hex_chars[src[i] & 0xF];
cmark_strbuf_put(ob, hex_str, 3);
}
i++;
}
return 1;
}
-66
View File
@@ -1,66 +0,0 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "houdini.h"
/**
* According to the OWASP rules:
*
* & --> &amp;
* < --> &lt;
* > --> &gt;
* " --> &quot;
* ' --> &#x27; &apos; is not recommended
* / --> &#x2F; forward slash is included as it helps end an HTML entity
*
*/
static const char HTML_ESCAPE_TABLE[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static const char *HTML_ESCAPES[] = {"", "&quot;", "&amp;", "&#39;",
"&#47;", "&lt;", "&gt;"};
int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src, bufsize_t size,
int secure) {
bufsize_t i = 0, org, esc = 0;
while (i < size) {
org = i;
while (i < size && (esc = HTML_ESCAPE_TABLE[src[i]]) == 0)
i++;
if (i > org)
cmark_strbuf_put(ob, src + org, i - org);
/* escaping */
if (unlikely(i >= size))
break;
/* The forward slash is only escaped in secure mode */
if ((src[i] == '/' || src[i] == '\'') && !secure) {
cmark_strbuf_putc(ob, src[i]);
} else {
cmark_strbuf_puts(ob, HTML_ESCAPES[esc]);
}
i++;
}
return 1;
}
int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src, bufsize_t size) {
return houdini_escape_html0(ob, src, size, 1);
}
-149
View File
@@ -1,149 +0,0 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "buffer.h"
#include "houdini.h"
#include "utf8.h"
#include "entities.inc"
/* Binary tree lookup code for entities added by JGM */
static const unsigned char *S_lookup(int i, int low, int hi,
const unsigned char *s, int len) {
int j;
int cmp =
strncmp((const char *)s, (const char *)cmark_entities[i].entity, len);
if (cmp == 0 && cmark_entities[i].entity[len] == 0) {
return (const unsigned char *)cmark_entities[i].bytes;
} else if (cmp < 0 && i > low) {
j = i - ((i - low) / 2);
if (j == i)
j -= 1;
return S_lookup(j, low, i - 1, s, len);
} else if (cmp > 0 && i < hi) {
j = i + ((hi - i) / 2);
if (j == i)
j += 1;
return S_lookup(j, i + 1, hi, s, len);
} else {
return NULL;
}
}
static const unsigned char *S_lookup_entity(const unsigned char *s, int len) {
return S_lookup(CMARK_NUM_ENTITIES / 2, 0, CMARK_NUM_ENTITIES - 1, s, len);
}
bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src,
bufsize_t size) {
bufsize_t i = 0;
if (size >= 3 && src[0] == '#') {
int codepoint = 0;
int num_digits = 0;
if (_isdigit(src[1])) {
for (i = 1; i < size && _isdigit(src[i]); ++i) {
codepoint = (codepoint * 10) + (src[i] - '0');
if (codepoint >= 0x110000) {
// Keep counting digits but
// avoid integer overflow.
codepoint = 0x110000;
}
}
num_digits = i - 1;
}
else if (src[1] == 'x' || src[1] == 'X') {
for (i = 2; i < size && _isxdigit(src[i]); ++i) {
codepoint = (codepoint * 16) + ((src[i] | 32) % 39 - 9);
if (codepoint >= 0x110000) {
// Keep counting digits but
// avoid integer overflow.
codepoint = 0x110000;
}
}
num_digits = i - 2;
}
if (num_digits >= 1 && num_digits <= 8 && i < size && src[i] == ';') {
if (codepoint == 0 || (codepoint >= 0xD800 && codepoint < 0xE000) ||
codepoint >= 0x110000) {
codepoint = 0xFFFD;
}
cmark_utf8proc_encode_char(codepoint, ob);
return i + 1;
}
}
else {
if (size > CMARK_ENTITY_MAX_LENGTH)
size = CMARK_ENTITY_MAX_LENGTH;
for (i = CMARK_ENTITY_MIN_LENGTH; i < size; ++i) {
if (src[i] == ' ')
break;
if (src[i] == ';') {
const unsigned char *entity = S_lookup_entity(src, i);
if (entity != NULL) {
cmark_strbuf_puts(ob, (const char *)entity);
return i + 1;
}
break;
}
}
}
return 0;
}
int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src,
bufsize_t size) {
bufsize_t i = 0, org, ent;
while (i < size) {
org = i;
while (i < size && src[i] != '&')
i++;
if (likely(i > org)) {
if (unlikely(org == 0)) {
if (i >= size)
return 0;
cmark_strbuf_grow(ob, HOUDINI_UNESCAPED_SIZE(size));
}
cmark_strbuf_put(ob, src + org, i - org);
}
/* escaping */
if (i >= size)
break;
i++;
ent = houdini_unescape_ent(ob, src + i, size - i);
i += ent;
/* not really an entity */
if (ent == 0)
cmark_strbuf_putc(ob, '&');
}
return 1;
}
void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src,
bufsize_t size) {
if (!houdini_unescape_html(ob, src, size))
cmark_strbuf_put(ob, src, size);
}
-339
View File
@@ -1,339 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "cmark_ctype.h"
#include "config.h"
#include "cmark.h"
#include "node.h"
#include "buffer.h"
#include "houdini.h"
#include "scanners.h"
#define BUFFER_SIZE 100
// Functions to convert cmark_nodes to HTML strings.
static void escape_html(cmark_strbuf *dest, const unsigned char *source,
bufsize_t length) {
houdini_escape_html0(dest, source, length, 0);
}
static CMARK_INLINE void cr(cmark_strbuf *html) {
if (html->size && html->ptr[html->size - 1] != '\n')
cmark_strbuf_putc(html, '\n');
}
struct render_state {
cmark_strbuf *html;
cmark_node *plain;
};
static void S_render_sourcepos(cmark_node *node, cmark_strbuf *html,
int options) {
char buffer[BUFFER_SIZE];
if (CMARK_OPT_SOURCEPOS & options) {
snprintf(buffer, BUFFER_SIZE, " data-sourcepos=\"%d:%d-%d:%d\"",
cmark_node_get_start_line(node), cmark_node_get_start_column(node),
cmark_node_get_end_line(node), cmark_node_get_end_column(node));
cmark_strbuf_puts(html, buffer);
}
}
static int S_render_node(cmark_node *node, cmark_event_type ev_type,
struct render_state *state, int options) {
cmark_node *parent;
cmark_node *grandparent;
cmark_strbuf *html = state->html;
char start_heading[] = "<h0";
char end_heading[] = "</h0";
bool tight;
char buffer[BUFFER_SIZE];
bool entering = (ev_type == CMARK_EVENT_ENTER);
if (state->plain == node) { // back at original node
state->plain = NULL;
}
if (state->plain != NULL) {
switch (node->type) {
case CMARK_NODE_TEXT:
case CMARK_NODE_CODE:
case CMARK_NODE_HTML_INLINE:
escape_html(html, node->as.literal.data, node->as.literal.len);
break;
case CMARK_NODE_LINEBREAK:
case CMARK_NODE_SOFTBREAK:
cmark_strbuf_putc(html, ' ');
break;
default:
break;
}
return 1;
}
switch (node->type) {
case CMARK_NODE_DOCUMENT:
break;
case CMARK_NODE_BLOCK_QUOTE:
if (entering) {
cr(html);
cmark_strbuf_puts(html, "<blockquote");
S_render_sourcepos(node, html, options);
cmark_strbuf_puts(html, ">\n");
} else {
cr(html);
cmark_strbuf_puts(html, "</blockquote>\n");
}
break;
case CMARK_NODE_LIST: {
cmark_list_type list_type = node->as.list.list_type;
int start = node->as.list.start;
if (entering) {
cr(html);
if (list_type == CMARK_BULLET_LIST) {
cmark_strbuf_puts(html, "<ul");
S_render_sourcepos(node, html, options);
cmark_strbuf_puts(html, ">\n");
} else if (start == 1) {
cmark_strbuf_puts(html, "<ol");
S_render_sourcepos(node, html, options);
cmark_strbuf_puts(html, ">\n");
} else {
snprintf(buffer, BUFFER_SIZE, "<ol start=\"%d\"", start);
cmark_strbuf_puts(html, buffer);
S_render_sourcepos(node, html, options);
cmark_strbuf_puts(html, ">\n");
}
} else {
cmark_strbuf_puts(html,
list_type == CMARK_BULLET_LIST ? "</ul>\n" : "</ol>\n");
}
break;
}
case CMARK_NODE_ITEM:
if (entering) {
cr(html);
cmark_strbuf_puts(html, "<li");
S_render_sourcepos(node, html, options);
cmark_strbuf_putc(html, '>');
} else {
cmark_strbuf_puts(html, "</li>\n");
}
break;
case CMARK_NODE_HEADING:
if (entering) {
cr(html);
start_heading[2] = (char)('0' + node->as.heading.level);
cmark_strbuf_puts(html, start_heading);
S_render_sourcepos(node, html, options);
cmark_strbuf_putc(html, '>');
} else {
end_heading[3] = (char)('0' + node->as.heading.level);
cmark_strbuf_puts(html, end_heading);
cmark_strbuf_puts(html, ">\n");
}
break;
case CMARK_NODE_CODE_BLOCK:
cr(html);
if (node->as.code.info.len == 0) {
cmark_strbuf_puts(html, "<pre");
S_render_sourcepos(node, html, options);
cmark_strbuf_puts(html, "><code>");
} else {
bufsize_t first_tag = 0;
while (first_tag < node->as.code.info.len &&
!cmark_isspace(node->as.code.info.data[first_tag])) {
first_tag += 1;
}
cmark_strbuf_puts(html, "<pre");
S_render_sourcepos(node, html, options);
cmark_strbuf_puts(html, "><code class=\"language-");
escape_html(html, node->as.code.info.data, first_tag);
cmark_strbuf_puts(html, "\">");
}
escape_html(html, node->as.code.literal.data, node->as.code.literal.len);
cmark_strbuf_puts(html, "</code></pre>\n");
break;
case CMARK_NODE_HTML_BLOCK:
cr(html);
if (options & CMARK_OPT_SAFE) {
cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
} else {
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
}
cr(html);
break;
case CMARK_NODE_CUSTOM_BLOCK:
cr(html);
if (entering) {
cmark_strbuf_put(html, node->as.custom.on_enter.data,
node->as.custom.on_enter.len);
} else {
cmark_strbuf_put(html, node->as.custom.on_exit.data,
node->as.custom.on_exit.len);
}
cr(html);
break;
case CMARK_NODE_THEMATIC_BREAK:
cr(html);
cmark_strbuf_puts(html, "<hr");
S_render_sourcepos(node, html, options);
cmark_strbuf_puts(html, " />\n");
break;
case CMARK_NODE_PARAGRAPH:
parent = cmark_node_parent(node);
grandparent = cmark_node_parent(parent);
if (grandparent != NULL && grandparent->type == CMARK_NODE_LIST) {
tight = grandparent->as.list.tight;
} else {
tight = false;
}
if (!tight) {
if (entering) {
cr(html);
cmark_strbuf_puts(html, "<p");
S_render_sourcepos(node, html, options);
cmark_strbuf_putc(html, '>');
} else {
cmark_strbuf_puts(html, "</p>\n");
}
}
break;
case CMARK_NODE_TEXT:
escape_html(html, node->as.literal.data, node->as.literal.len);
break;
case CMARK_NODE_LINEBREAK:
cmark_strbuf_puts(html, "<br />\n");
break;
case CMARK_NODE_SOFTBREAK:
if (options & CMARK_OPT_HARDBREAKS) {
cmark_strbuf_puts(html, "<br />\n");
} else {
cmark_strbuf_putc(html, '\n');
}
break;
case CMARK_NODE_CODE:
cmark_strbuf_puts(html, "<code>");
escape_html(html, node->as.literal.data, node->as.literal.len);
cmark_strbuf_puts(html, "</code>");
break;
case CMARK_NODE_HTML_INLINE:
if (options & CMARK_OPT_SAFE) {
cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
} else {
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
}
break;
case CMARK_NODE_CUSTOM_INLINE:
if (entering) {
cmark_strbuf_put(html, node->as.custom.on_enter.data,
node->as.custom.on_enter.len);
} else {
cmark_strbuf_put(html, node->as.custom.on_exit.data,
node->as.custom.on_exit.len);
}
break;
case CMARK_NODE_STRONG:
if (entering) {
cmark_strbuf_puts(html, "<strong>");
} else {
cmark_strbuf_puts(html, "</strong>");
}
break;
case CMARK_NODE_EMPH:
if (entering) {
cmark_strbuf_puts(html, "<em>");
} else {
cmark_strbuf_puts(html, "</em>");
}
break;
case CMARK_NODE_LINK:
if (entering) {
cmark_strbuf_puts(html, "<a href=\"");
if (!((options & CMARK_OPT_SAFE) &&
scan_dangerous_url(&node->as.link.url, 0))) {
houdini_escape_href(html, node->as.link.url.data,
node->as.link.url.len);
}
if (node->as.link.title.len) {
cmark_strbuf_puts(html, "\" title=\"");
escape_html(html, node->as.link.title.data, node->as.link.title.len);
}
cmark_strbuf_puts(html, "\">");
} else {
cmark_strbuf_puts(html, "</a>");
}
break;
case CMARK_NODE_IMAGE:
if (entering) {
cmark_strbuf_puts(html, "<img src=\"");
if (!((options & CMARK_OPT_SAFE) &&
scan_dangerous_url(&node->as.link.url, 0))) {
houdini_escape_href(html, node->as.link.url.data,
node->as.link.url.len);
}
cmark_strbuf_puts(html, "\" alt=\"");
state->plain = node;
} else {
if (node->as.link.title.len) {
cmark_strbuf_puts(html, "\" title=\"");
escape_html(html, node->as.link.title.data, node->as.link.title.len);
}
cmark_strbuf_puts(html, "\" />");
}
break;
default:
assert(false);
break;
}
// cmark_strbuf_putc(html, 'x');
return 1;
}
char *cmark_render_html(cmark_node *root, int options) {
char *result;
cmark_strbuf html = GH_BUF_INIT;
cmark_event_type ev_type;
cmark_node *cur;
struct render_state state = {&html, NULL};
cmark_iter *iter = cmark_iter_new(root);
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
cur = cmark_iter_get_node(iter);
S_render_node(cur, ev_type, &state, options);
}
result = (char *)cmark_strbuf_detach(&html);
cmark_iter_free(iter);
return result;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-23
View File
@@ -1,23 +0,0 @@
#ifndef CMARK_INLINES_H
#define CMARK_INLINES_H
#import "references.h"
#ifdef __cplusplus
extern "C" {
#endif
cmark_chunk cmark_clean_url(cmark_chunk *url);
cmark_chunk cmark_clean_title(cmark_chunk *title);
void cmark_parse_inlines(cmark_node *parent, cmark_reference_map *refmap,
int options);
bufsize_t cmark_parse_reference_inline(cmark_strbuf *input,
cmark_reference_map *refmap);
#ifdef __cplusplus
}
#endif
#endif
-121
View File
@@ -1,121 +0,0 @@
#include <assert.h>
#include <stdlib.h>
#include "config.h"
#include "node.h"
#include "cmark.h"
#include "iterator.h"
static const int S_leaf_mask =
(1 << CMARK_NODE_HTML_BLOCK) | (1 << CMARK_NODE_THEMATIC_BREAK) |
(1 << CMARK_NODE_CODE_BLOCK) | (1 << CMARK_NODE_TEXT) |
(1 << CMARK_NODE_SOFTBREAK) | (1 << CMARK_NODE_LINEBREAK) |
(1 << CMARK_NODE_CODE) | (1 << CMARK_NODE_HTML_INLINE);
cmark_iter *cmark_iter_new(cmark_node *root) {
if (root == NULL) {
return NULL;
}
cmark_iter *iter = (cmark_iter *)malloc(sizeof(cmark_iter));
if (iter == NULL) {
return NULL;
}
iter->root = root;
iter->cur.ev_type = CMARK_EVENT_NONE;
iter->cur.node = NULL;
iter->next.ev_type = CMARK_EVENT_ENTER;
iter->next.node = root;
return iter;
}
void cmark_iter_free(cmark_iter *iter) { free(iter); }
static bool S_is_leaf(cmark_node *node) {
return ((1 << node->type) & S_leaf_mask) != 0;
}
cmark_event_type cmark_iter_next(cmark_iter *iter) {
cmark_event_type ev_type = iter->next.ev_type;
cmark_node *node = iter->next.node;
iter->cur.ev_type = ev_type;
iter->cur.node = node;
if (ev_type == CMARK_EVENT_DONE) {
return ev_type;
}
/* roll forward to next item, setting both fields */
if (ev_type == CMARK_EVENT_ENTER && !S_is_leaf(node)) {
if (node->first_child == NULL) {
/* stay on this node but exit */
iter->next.ev_type = CMARK_EVENT_EXIT;
} else {
iter->next.ev_type = CMARK_EVENT_ENTER;
iter->next.node = node->first_child;
}
} else if (node == iter->root) {
/* don't move past root */
iter->next.ev_type = CMARK_EVENT_DONE;
iter->next.node = NULL;
} else if (node->next) {
iter->next.ev_type = CMARK_EVENT_ENTER;
iter->next.node = node->next;
} else if (node->parent) {
iter->next.ev_type = CMARK_EVENT_EXIT;
iter->next.node = node->parent;
} else {
assert(false);
iter->next.ev_type = CMARK_EVENT_DONE;
iter->next.node = NULL;
}
return ev_type;
}
void cmark_iter_reset(cmark_iter *iter, cmark_node *current,
cmark_event_type event_type) {
iter->next.ev_type = event_type;
iter->next.node = current;
cmark_iter_next(iter);
}
cmark_node *cmark_iter_get_node(cmark_iter *iter) { return iter->cur.node; }
cmark_event_type cmark_iter_get_event_type(cmark_iter *iter) {
return iter->cur.ev_type;
}
cmark_node *cmark_iter_get_root(cmark_iter *iter) { return iter->root; }
void cmark_consolidate_text_nodes(cmark_node *root) {
if (root == NULL) {
return;
}
cmark_iter *iter = cmark_iter_new(root);
cmark_strbuf buf = GH_BUF_INIT;
cmark_event_type ev_type;
cmark_node *cur, *tmp, *next;
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
cur = cmark_iter_get_node(iter);
if (ev_type == CMARK_EVENT_ENTER && cur->type == CMARK_NODE_TEXT &&
cur->next && cur->next->type == CMARK_NODE_TEXT) {
cmark_strbuf_clear(&buf);
cmark_strbuf_put(&buf, cur->as.literal.data, cur->as.literal.len);
tmp = cur->next;
while (tmp && tmp->type == CMARK_NODE_TEXT) {
cmark_iter_next(iter); // advance pointer
cmark_strbuf_put(&buf, tmp->as.literal.data, tmp->as.literal.len);
next = tmp->next;
cmark_node_free(tmp);
tmp = next;
}
cmark_chunk_free(&cur->as.literal);
cur->as.literal = cmark_chunk_buf_detach(&buf);
}
}
cmark_strbuf_free(&buf);
cmark_iter_free(iter);
}
-25
View File
@@ -1,25 +0,0 @@
#ifndef CMARK_ITERATOR_H
#define CMARK_ITERATOR_H
#ifdef __cplusplus
extern "C" {
#endif
#include "cmark.h"
typedef struct {
cmark_event_type ev_type;
cmark_node *node;
} cmark_iter_state;
struct cmark_iter {
cmark_node *root;
cmark_iter_state cur;
cmark_iter_state next;
};
#ifdef __cplusplus
}
#endif
#endif
-436
View File
@@ -1,436 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include "config.h"
#include "cmark.h"
#include "node.h"
#include "buffer.h"
#include "utf8.h"
#include "scanners.h"
#include "render.h"
#define safe_strlen(s) cmark_strbuf_safe_strlen(s)
#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
#define LIT(s) renderer->out(renderer, s, false, LITERAL)
#define CR() renderer->cr(renderer)
#define BLANKLINE() renderer->blankline(renderer)
#define LIST_NUMBER_STRING_SIZE 20
static CMARK_INLINE void outc(cmark_renderer *renderer, cmark_escaping escape,
int32_t c, unsigned char nextc) {
if (escape == LITERAL) {
cmark_render_code_point(renderer, c);
return;
}
switch (c) {
case 123: // '{'
case 125: // '}'
case 35: // '#'
case 37: // '%'
case 38: // '&'
cmark_render_ascii(renderer, "\\");
cmark_render_code_point(renderer, c);
break;
case 36: // '$'
case 95: // '_'
if (escape == NORMAL) {
cmark_render_ascii(renderer, "\\");
}
cmark_render_code_point(renderer, c);
break;
case 45: // '-'
if (nextc == 45) { // prevent ligature
cmark_render_ascii(renderer, "\\-");
} else {
cmark_render_ascii(renderer, "-");
}
break;
case 126: // '~'
if (escape == NORMAL) {
cmark_render_ascii(renderer, "\\textasciitilde{}");
} else {
cmark_render_code_point(renderer, c);
}
break;
case 94: // '^'
cmark_render_ascii(renderer, "\\^{}");
break;
case 92: // '\\'
if (escape == URL) {
// / acts as path sep even on windows:
cmark_render_ascii(renderer, "/");
} else {
cmark_render_ascii(renderer, "\\textbackslash{}");
}
break;
case 124: // '|'
cmark_render_ascii(renderer, "\\textbar{}");
break;
case 60: // '<'
cmark_render_ascii(renderer, "\\textless{}");
break;
case 62: // '>'
cmark_render_ascii(renderer, "\\textgreater{}");
break;
case 91: // '['
case 93: // ']'
cmark_render_ascii(renderer, "{");
cmark_render_code_point(renderer, c);
cmark_render_ascii(renderer, "}");
break;
case 34: // '"'
cmark_render_ascii(renderer, "\\textquotedbl{}");
// requires \usepackage[T1]{fontenc}
break;
case 39: // '\''
cmark_render_ascii(renderer, "\\textquotesingle{}");
// requires \usepackage{textcomp}
break;
case 160: // nbsp
cmark_render_ascii(renderer, "~");
break;
case 8230: // hellip
cmark_render_ascii(renderer, "\\ldots{}");
break;
case 8216: // lsquo
if (escape == NORMAL) {
cmark_render_ascii(renderer, "`");
} else {
cmark_render_code_point(renderer, c);
}
break;
case 8217: // rsquo
if (escape == NORMAL) {
cmark_render_ascii(renderer, "\'");
} else {
cmark_render_code_point(renderer, c);
}
break;
case 8220: // ldquo
if (escape == NORMAL) {
cmark_render_ascii(renderer, "``");
} else {
cmark_render_code_point(renderer, c);
}
break;
case 8221: // rdquo
if (escape == NORMAL) {
cmark_render_ascii(renderer, "''");
} else {
cmark_render_code_point(renderer, c);
}
break;
case 8212: // emdash
if (escape == NORMAL) {
cmark_render_ascii(renderer, "---");
} else {
cmark_render_code_point(renderer, c);
}
break;
case 8211: // endash
if (escape == NORMAL) {
cmark_render_ascii(renderer, "--");
} else {
cmark_render_code_point(renderer, c);
}
break;
default:
cmark_render_code_point(renderer, c);
}
}
typedef enum {
NO_LINK,
URL_AUTOLINK,
EMAIL_AUTOLINK,
NORMAL_LINK,
INTERNAL_LINK
} link_type;
static link_type get_link_type(cmark_node *node) {
size_t title_len, url_len;
cmark_node *link_text;
char *realurl;
int realurllen;
bool isemail = false;
if (node->type != CMARK_NODE_LINK) {
return NO_LINK;
}
const char *url = cmark_node_get_url(node);
cmark_chunk url_chunk = cmark_chunk_literal(url);
if (url && *url == '#') {
return INTERNAL_LINK;
}
url_len = safe_strlen(url);
if (url_len == 0 || scan_scheme(&url_chunk, 0) == 0) {
return NO_LINK;
}
const char *title = cmark_node_get_title(node);
title_len = safe_strlen(title);
// if it has a title, we can't treat it as an autolink:
if (title_len == 0) {
link_text = node->first_child;
cmark_consolidate_text_nodes(link_text);
realurl = (char *)url;
realurllen = url_len;
if (strncmp(realurl, "mailto:", 7) == 0) {
realurl += 7;
realurllen -= 7;
isemail = true;
}
if (realurllen == link_text->as.literal.len &&
strncmp(realurl, (char *)link_text->as.literal.data,
link_text->as.literal.len) == 0) {
if (isemail) {
return EMAIL_AUTOLINK;
} else {
return URL_AUTOLINK;
}
}
}
return NORMAL_LINK;
}
static int S_get_enumlevel(cmark_node *node) {
int enumlevel = 0;
cmark_node *tmp = node;
while (tmp) {
if (tmp->type == CMARK_NODE_LIST &&
cmark_node_get_list_type(node) == CMARK_ORDERED_LIST) {
enumlevel++;
}
tmp = tmp->parent;
}
return enumlevel;
}
static int S_render_node(cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
int list_number;
char list_number_string[LIST_NUMBER_STRING_SIZE];
bool entering = (ev_type == CMARK_EVENT_ENTER);
cmark_list_type list_type;
const char *roman_numerals[] = {"", "i", "ii", "iii", "iv", "v",
"vi", "vii", "viii", "ix", "x"};
// avoid warning about unused parameter:
(void)(options);
switch (node->type) {
case CMARK_NODE_DOCUMENT:
break;
case CMARK_NODE_BLOCK_QUOTE:
if (entering) {
LIT("\\begin{quote}");
CR();
} else {
LIT("\\end{quote}");
BLANKLINE();
}
break;
case CMARK_NODE_LIST:
list_type = cmark_node_get_list_type(node);
if (entering) {
LIT("\\begin{");
LIT(list_type == CMARK_ORDERED_LIST ? "enumerate" : "itemize");
LIT("}");
CR();
list_number = cmark_node_get_list_start(node);
if (list_number > 1) {
snprintf(list_number_string, LIST_NUMBER_STRING_SIZE, "%d",
list_number);
LIT("\\setcounter{enum");
LIT((char *)roman_numerals[S_get_enumlevel(node)]);
LIT("}{");
OUT(list_number_string, false, NORMAL);
LIT("}");
CR();
}
} else {
LIT("\\end{");
LIT(list_type == CMARK_ORDERED_LIST ? "enumerate" : "itemize");
LIT("}");
BLANKLINE();
}
break;
case CMARK_NODE_ITEM:
if (entering) {
LIT("\\item ");
} else {
CR();
}
break;
case CMARK_NODE_HEADING:
if (entering) {
switch (cmark_node_get_heading_level(node)) {
case 1:
LIT("\\section");
break;
case 2:
LIT("\\subsection");
break;
case 3:
LIT("\\subsubsection");
break;
case 4:
LIT("\\paragraph");
break;
case 5:
LIT("\\subparagraph");
break;
}
LIT("{");
} else {
LIT("}");
BLANKLINE();
}
break;
case CMARK_NODE_CODE_BLOCK:
CR();
LIT("\\begin{verbatim}");
CR();
OUT(cmark_node_get_literal(node), false, LITERAL);
CR();
LIT("\\end{verbatim}");
BLANKLINE();
break;
case CMARK_NODE_HTML_BLOCK:
break;
case CMARK_NODE_CUSTOM_BLOCK:
CR();
OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node),
false, LITERAL);
CR();
break;
case CMARK_NODE_THEMATIC_BREAK:
BLANKLINE();
LIT("\\begin{center}\\rule{0.5\\linewidth}{\\linethickness}\\end{center}");
BLANKLINE();
break;
case CMARK_NODE_PARAGRAPH:
if (!entering) {
BLANKLINE();
}
break;
case CMARK_NODE_TEXT:
OUT(cmark_node_get_literal(node), true, NORMAL);
break;
case CMARK_NODE_LINEBREAK:
LIT("\\\\");
CR();
break;
case CMARK_NODE_SOFTBREAK:
if (renderer->width == 0) {
CR();
} else {
OUT(" ", true, NORMAL);
}
break;
case CMARK_NODE_CODE:
LIT("\\texttt{");
OUT(cmark_node_get_literal(node), false, NORMAL);
LIT("}");
break;
case CMARK_NODE_HTML_INLINE:
break;
case CMARK_NODE_CUSTOM_INLINE:
OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node),
false, LITERAL);
break;
case CMARK_NODE_STRONG:
if (entering) {
LIT("\\textbf{");
} else {
LIT("}");
}
break;
case CMARK_NODE_EMPH:
if (entering) {
LIT("\\emph{");
} else {
LIT("}");
}
break;
case CMARK_NODE_LINK:
if (entering) {
const char *url = cmark_node_get_url(node);
// requires \usepackage{hyperref}
switch (get_link_type(node)) {
case URL_AUTOLINK:
LIT("\\url{");
OUT(url, false, URL);
break;
case EMAIL_AUTOLINK:
LIT("\\href{");
OUT(url, false, URL);
LIT("}\\nolinkurl{");
break;
case NORMAL_LINK:
LIT("\\href{");
OUT(url, false, URL);
LIT("}{");
break;
case INTERNAL_LINK:
LIT("\\protect\\hyperlink{");
OUT(url + 1, false, URL);
LIT("}{");
break;
case NO_LINK:
LIT("{"); // error?
}
} else {
LIT("}");
}
break;
case CMARK_NODE_IMAGE:
if (entering) {
LIT("\\protect\\includegraphics{");
// requires \include{graphicx}
OUT(cmark_node_get_url(node), false, URL);
LIT("}");
return 0;
}
break;
default:
assert(false);
break;
}
return 1;
}
char *cmark_render_latex(cmark_node *root, int options, int width) {
return cmark_render(root, options, width, outc, S_render_node);
}
-248
View File
@@ -1,248 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "config.h"
#include "cmark.h"
#include "node.h"
#include "buffer.h"
#include "utf8.h"
#include "render.h"
#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
#define LIT(s) renderer->out(renderer, s, false, LITERAL)
#define CR() renderer->cr(renderer)
#define BLANKLINE() renderer->blankline(renderer)
#define LIST_NUMBER_SIZE 20
// Functions to convert cmark_nodes to groff man strings.
static void S_outc(cmark_renderer *renderer, cmark_escaping escape, int32_t c,
unsigned char nextc) {
(void)(nextc);
if (escape == LITERAL) {
cmark_render_code_point(renderer, c);
return;
}
switch (c) {
case 46:
if (renderer->begin_line) {
cmark_render_ascii(renderer, "\\&.");
} else {
cmark_render_code_point(renderer, c);
}
break;
case 39:
if (renderer->begin_line) {
cmark_render_ascii(renderer, "\\&'");
} else {
cmark_render_code_point(renderer, c);
}
break;
case 45:
cmark_render_ascii(renderer, "\\-");
break;
case 92:
cmark_render_ascii(renderer, "\\e");
break;
case 8216: // left single quote
cmark_render_ascii(renderer, "\\[oq]");
break;
case 8217: // right single quote
cmark_render_ascii(renderer, "\\[cq]");
break;
case 8220: // left double quote
cmark_render_ascii(renderer, "\\[lq]");
break;
case 8221: // right double quote
cmark_render_ascii(renderer, "\\[rq]");
break;
case 8212: // em dash
cmark_render_ascii(renderer, "\\[em]");
break;
case 8211: // en dash
cmark_render_ascii(renderer, "\\[en]");
break;
default:
cmark_render_code_point(renderer, c);
}
}
static int S_render_node(cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
cmark_node *tmp;
int list_number;
bool entering = (ev_type == CMARK_EVENT_ENTER);
// avoid unused parameter error:
(void)(options);
switch (node->type) {
case CMARK_NODE_DOCUMENT:
break;
case CMARK_NODE_BLOCK_QUOTE:
if (entering) {
CR();
LIT(".RS");
CR();
} else {
CR();
LIT(".RE");
CR();
}
break;
case CMARK_NODE_LIST:
break;
case CMARK_NODE_ITEM:
if (entering) {
CR();
LIT(".IP ");
if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
LIT("\\[bu] 2");
} else {
list_number = cmark_node_get_list_start(node->parent);
tmp = node;
while (tmp->prev) {
tmp = tmp->prev;
list_number += 1;
}
char list_number_s[LIST_NUMBER_SIZE];
snprintf(list_number_s, LIST_NUMBER_SIZE, "\"%d.\" 4", list_number);
LIT(list_number_s);
}
CR();
} else {
CR();
}
break;
case CMARK_NODE_HEADING:
if (entering) {
CR();
LIT(cmark_node_get_heading_level(node) == 1 ? ".SH" : ".SS");
CR();
} else {
CR();
}
break;
case CMARK_NODE_CODE_BLOCK:
CR();
LIT(".IP\n.nf\n\\f[C]\n");
OUT(cmark_node_get_literal(node), false, NORMAL);
CR();
LIT("\\f[]\n.fi");
CR();
break;
case CMARK_NODE_HTML_BLOCK:
break;
case CMARK_NODE_CUSTOM_BLOCK:
CR();
OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node),
false, LITERAL);
CR();
break;
case CMARK_NODE_THEMATIC_BREAK:
CR();
LIT(".PP\n * * * * *");
CR();
break;
case CMARK_NODE_PARAGRAPH:
if (entering) {
// no blank line if first paragraph in list:
if (node->parent && node->parent->type == CMARK_NODE_ITEM &&
node->prev == NULL) {
// no blank line or .PP
} else {
CR();
LIT(".PP");
CR();
}
} else {
CR();
}
break;
case CMARK_NODE_TEXT:
OUT(cmark_node_get_literal(node), true, NORMAL);
break;
case CMARK_NODE_LINEBREAK:
LIT(".PD 0\n.P\n.PD");
CR();
break;
case CMARK_NODE_SOFTBREAK:
if (renderer->width == 0) {
CR();
} else {
OUT(" ", true, LITERAL);
}
break;
case CMARK_NODE_CODE:
LIT("\\f[C]");
OUT(cmark_node_get_literal(node), true, NORMAL);
LIT("\\f[]");
break;
case CMARK_NODE_HTML_INLINE:
break;
case CMARK_NODE_CUSTOM_INLINE:
OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node),
false, LITERAL);
break;
case CMARK_NODE_STRONG:
if (entering) {
LIT("\\f[B]");
} else {
LIT("\\f[]");
}
break;
case CMARK_NODE_EMPH:
if (entering) {
LIT("\\f[I]");
} else {
LIT("\\f[]");
}
break;
case CMARK_NODE_LINK:
if (!entering) {
LIT(" (");
OUT(cmark_node_get_url(node), true, URL);
LIT(")");
}
break;
case CMARK_NODE_IMAGE:
if (entering) {
LIT("[IMAGE: ");
} else {
LIT("]");
}
break;
default:
assert(false);
break;
}
return 1;
}
char *cmark_render_man(cmark_node *root, int options, int width) {
return cmark_render(root, options, width, S_outc, S_render_node);
}
-5
View File
@@ -1,5 +0,0 @@
module libcmark [system][extern_c] {
header "node.h"
header "cmark.h"
export *
}
-852
View File
@@ -1,852 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "node.h"
static void S_node_unlink(cmark_node *node);
static CMARK_INLINE bool S_is_block(cmark_node *node) {
if (node == NULL) {
return false;
}
return node->type >= CMARK_NODE_FIRST_BLOCK &&
node->type <= CMARK_NODE_LAST_BLOCK;
}
static CMARK_INLINE bool S_is_inline(cmark_node *node) {
if (node == NULL) {
return false;
}
return node->type >= CMARK_NODE_FIRST_INLINE &&
node->type <= CMARK_NODE_LAST_INLINE;
}
static bool S_can_contain(cmark_node *node, cmark_node *child) {
cmark_node *cur;
if (node == NULL || child == NULL) {
return false;
}
// Verify that child is not an ancestor of node or equal to node.
cur = node;
do {
if (cur == child) {
return false;
}
cur = cur->parent;
} while (cur != NULL);
if (child->type == CMARK_NODE_DOCUMENT) {
return false;
}
switch (node->type) {
case CMARK_NODE_DOCUMENT:
case CMARK_NODE_BLOCK_QUOTE:
case CMARK_NODE_ITEM:
return S_is_block(child) && child->type != CMARK_NODE_ITEM;
case CMARK_NODE_LIST:
return child->type == CMARK_NODE_ITEM;
case CMARK_NODE_CUSTOM_BLOCK:
return true;
case CMARK_NODE_PARAGRAPH:
case CMARK_NODE_HEADING:
case CMARK_NODE_EMPH:
case CMARK_NODE_STRONG:
case CMARK_NODE_LINK:
case CMARK_NODE_IMAGE:
case CMARK_NODE_CUSTOM_INLINE:
return S_is_inline(child);
default:
break;
}
return false;
}
cmark_node *cmark_node_new(cmark_node_type type) {
cmark_node *node = (cmark_node *)calloc(1, sizeof(*node));
node->type = type;
switch (node->type) {
case CMARK_NODE_HEADING:
node->as.heading.level = 1;
break;
case CMARK_NODE_LIST: {
cmark_list *list = &node->as.list;
list->list_type = CMARK_BULLET_LIST;
list->start = 1;
list->tight = false;
break;
}
default:
break;
}
return node;
}
// Free a cmark_node list and any children.
static void S_free_nodes(cmark_node *e) {
cmark_node *next;
while (e != NULL) {
if (S_is_block(e)) {
cmark_strbuf_free(&e->string_content);
}
switch (e->type) {
case CMARK_NODE_CODE_BLOCK:
cmark_chunk_free(&e->as.code.info);
cmark_chunk_free(&e->as.code.literal);
break;
case CMARK_NODE_TEXT:
case CMARK_NODE_HTML_INLINE:
case CMARK_NODE_CODE:
case CMARK_NODE_HTML_BLOCK:
cmark_chunk_free(&e->as.literal);
break;
case CMARK_NODE_LINK:
case CMARK_NODE_IMAGE:
cmark_chunk_free(&e->as.link.url);
cmark_chunk_free(&e->as.link.title);
break;
case CMARK_NODE_CUSTOM_BLOCK:
case CMARK_NODE_CUSTOM_INLINE:
cmark_chunk_free(&e->as.custom.on_enter);
cmark_chunk_free(&e->as.custom.on_exit);
break;
default:
break;
}
if (e->last_child) {
// Splice children into list
e->last_child->next = e->next;
e->next = e->first_child;
}
next = e->next;
free(e);
e = next;
}
}
void cmark_node_free(cmark_node *node) {
S_node_unlink(node);
node->next = NULL;
S_free_nodes(node);
}
cmark_node_type cmark_node_get_type(cmark_node *node) {
if (node == NULL) {
return CMARK_NODE_NONE;
} else {
return node->type;
}
}
const char *cmark_node_get_type_string(cmark_node *node) {
if (node == NULL) {
return "NONE";
}
switch (node->type) {
case CMARK_NODE_NONE:
return "none";
case CMARK_NODE_DOCUMENT:
return "document";
case CMARK_NODE_BLOCK_QUOTE:
return "block_quote";
case CMARK_NODE_LIST:
return "list";
case CMARK_NODE_ITEM:
return "item";
case CMARK_NODE_CODE_BLOCK:
return "code_block";
case CMARK_NODE_HTML_BLOCK:
return "html_block";
case CMARK_NODE_CUSTOM_BLOCK:
return "custom_block";
case CMARK_NODE_PARAGRAPH:
return "paragraph";
case CMARK_NODE_HEADING:
return "heading";
case CMARK_NODE_THEMATIC_BREAK:
return "thematic_break";
case CMARK_NODE_TEXT:
return "text";
case CMARK_NODE_SOFTBREAK:
return "softbreak";
case CMARK_NODE_LINEBREAK:
return "linebreak";
case CMARK_NODE_CODE:
return "code";
case CMARK_NODE_HTML_INLINE:
return "html_inline";
case CMARK_NODE_CUSTOM_INLINE:
return "custom_inline";
case CMARK_NODE_EMPH:
return "emph";
case CMARK_NODE_STRONG:
return "strong";
case CMARK_NODE_LINK:
return "link";
case CMARK_NODE_IMAGE:
return "image";
}
return "<unknown>";
}
cmark_node *cmark_node_next(cmark_node *node) {
if (node == NULL) {
return NULL;
} else {
return node->next;
}
}
cmark_node *cmark_node_previous(cmark_node *node) {
if (node == NULL) {
return NULL;
} else {
return node->prev;
}
}
cmark_node *cmark_node_parent(cmark_node *node) {
if (node == NULL) {
return NULL;
} else {
return node->parent;
}
}
cmark_node *cmark_node_first_child(cmark_node *node) {
if (node == NULL) {
return NULL;
} else {
return node->first_child;
}
}
cmark_node *cmark_node_last_child(cmark_node *node) {
if (node == NULL) {
return NULL;
} else {
return node->last_child;
}
}
void *cmark_node_get_user_data(cmark_node *node) {
if (node == NULL) {
return NULL;
} else {
return node->user_data;
}
}
int cmark_node_set_user_data(cmark_node *node, void *user_data) {
if (node == NULL) {
return 0;
}
node->user_data = user_data;
return 1;
}
const char *cmark_node_get_literal(cmark_node *node) {
if (node == NULL) {
return NULL;
}
switch (node->type) {
case CMARK_NODE_HTML_BLOCK:
case CMARK_NODE_TEXT:
case CMARK_NODE_HTML_INLINE:
case CMARK_NODE_CODE:
return cmark_chunk_to_cstr(&node->as.literal);
case CMARK_NODE_CODE_BLOCK:
return cmark_chunk_to_cstr(&node->as.code.literal);
default:
break;
}
return NULL;
}
int cmark_node_set_literal(cmark_node *node, const char *content) {
if (node == NULL) {
return 0;
}
switch (node->type) {
case CMARK_NODE_HTML_BLOCK:
case CMARK_NODE_TEXT:
case CMARK_NODE_HTML_INLINE:
case CMARK_NODE_CODE:
cmark_chunk_set_cstr(&node->as.literal, content);
return 1;
case CMARK_NODE_CODE_BLOCK:
cmark_chunk_set_cstr(&node->as.code.literal, content);
return 1;
default:
break;
}
return 0;
}
int cmark_node_get_heading_level(cmark_node *node) {
if (node == NULL) {
return 0;
}
switch (node->type) {
case CMARK_NODE_HEADING:
return node->as.heading.level;
default:
break;
}
return 0;
}
int cmark_node_set_heading_level(cmark_node *node, int level) {
if (node == NULL || level < 1 || level > 6) {
return 0;
}
switch (node->type) {
case CMARK_NODE_HEADING:
node->as.heading.level = level;
return 1;
default:
break;
}
return 0;
}
cmark_list_type cmark_node_get_list_type(cmark_node *node) {
if (node == NULL) {
return CMARK_NO_LIST;
}
if (node->type == CMARK_NODE_LIST) {
return node->as.list.list_type;
} else {
return CMARK_NO_LIST;
}
}
int cmark_node_set_list_type(cmark_node *node, cmark_list_type type) {
if (!(type == CMARK_BULLET_LIST || type == CMARK_ORDERED_LIST)) {
return 0;
}
if (node == NULL) {
return 0;
}
if (node->type == CMARK_NODE_LIST) {
node->as.list.list_type = type;
return 1;
} else {
return 0;
}
}
cmark_delim_type cmark_node_get_list_delim(cmark_node *node) {
if (node == NULL) {
return CMARK_NO_DELIM;
}
if (node->type == CMARK_NODE_LIST) {
return node->as.list.delimiter;
} else {
return CMARK_NO_DELIM;
}
}
int cmark_node_set_list_delim(cmark_node *node, cmark_delim_type delim) {
if (!(delim == CMARK_PERIOD_DELIM || delim == CMARK_PAREN_DELIM)) {
return 0;
}
if (node == NULL) {
return 0;
}
if (node->type == CMARK_NODE_LIST) {
node->as.list.delimiter = delim;
return 1;
} else {
return 0;
}
}
int cmark_node_get_list_start(cmark_node *node) {
if (node == NULL) {
return 0;
}
if (node->type == CMARK_NODE_LIST) {
return node->as.list.start;
} else {
return 0;
}
}
int cmark_node_set_list_start(cmark_node *node, int start) {
if (node == NULL || start < 0) {
return 0;
}
if (node->type == CMARK_NODE_LIST) {
node->as.list.start = start;
return 1;
} else {
return 0;
}
}
int cmark_node_get_list_tight(cmark_node *node) {
if (node == NULL) {
return 0;
}
if (node->type == CMARK_NODE_LIST) {
return node->as.list.tight;
} else {
return 0;
}
}
int cmark_node_set_list_tight(cmark_node *node, int tight) {
if (node == NULL) {
return 0;
}
if (node->type == CMARK_NODE_LIST) {
node->as.list.tight = tight == 1;
return 1;
} else {
return 0;
}
}
const char *cmark_node_get_fence_info(cmark_node *node) {
if (node == NULL) {
return NULL;
}
if (node->type == CMARK_NODE_CODE_BLOCK) {
return cmark_chunk_to_cstr(&node->as.code.info);
} else {
return NULL;
}
}
int cmark_node_set_fence_info(cmark_node *node, const char *info) {
if (node == NULL) {
return 0;
}
if (node->type == CMARK_NODE_CODE_BLOCK) {
cmark_chunk_set_cstr(&node->as.code.info, info);
return 1;
} else {
return 0;
}
}
const char *cmark_node_get_url(cmark_node *node) {
if (node == NULL) {
return NULL;
}
switch (node->type) {
case CMARK_NODE_LINK:
case CMARK_NODE_IMAGE:
return cmark_chunk_to_cstr(&node->as.link.url);
default:
break;
}
return NULL;
}
int cmark_node_set_url(cmark_node *node, const char *url) {
if (node == NULL) {
return 0;
}
switch (node->type) {
case CMARK_NODE_LINK:
case CMARK_NODE_IMAGE:
cmark_chunk_set_cstr(&node->as.link.url, url);
return 1;
default:
break;
}
return 0;
}
const char *cmark_node_get_title(cmark_node *node) {
if (node == NULL) {
return NULL;
}
switch (node->type) {
case CMARK_NODE_LINK:
case CMARK_NODE_IMAGE:
return cmark_chunk_to_cstr(&node->as.link.title);
default:
break;
}
return NULL;
}
int cmark_node_set_title(cmark_node *node, const char *title) {
if (node == NULL) {
return 0;
}
switch (node->type) {
case CMARK_NODE_LINK:
case CMARK_NODE_IMAGE:
cmark_chunk_set_cstr(&node->as.link.title, title);
return 1;
default:
break;
}
return 0;
}
const char *cmark_node_get_on_enter(cmark_node *node) {
if (node == NULL) {
return NULL;
}
switch (node->type) {
case CMARK_NODE_CUSTOM_INLINE:
case CMARK_NODE_CUSTOM_BLOCK:
return cmark_chunk_to_cstr(&node->as.custom.on_enter);
default:
break;
}
return NULL;
}
int cmark_node_set_on_enter(cmark_node *node, const char *on_enter) {
if (node == NULL) {
return 0;
}
switch (node->type) {
case CMARK_NODE_CUSTOM_INLINE:
case CMARK_NODE_CUSTOM_BLOCK:
cmark_chunk_set_cstr(&node->as.custom.on_enter, on_enter);
return 1;
default:
break;
}
return 0;
}
const char *cmark_node_get_on_exit(cmark_node *node) {
if (node == NULL) {
return NULL;
}
switch (node->type) {
case CMARK_NODE_CUSTOM_INLINE:
case CMARK_NODE_CUSTOM_BLOCK:
return cmark_chunk_to_cstr(&node->as.custom.on_exit);
default:
break;
}
return NULL;
}
int cmark_node_set_on_exit(cmark_node *node, const char *on_exit) {
if (node == NULL) {
return 0;
}
switch (node->type) {
case CMARK_NODE_CUSTOM_INLINE:
case CMARK_NODE_CUSTOM_BLOCK:
cmark_chunk_set_cstr(&node->as.custom.on_exit, on_exit);
return 1;
default:
break;
}
return 0;
}
int cmark_node_get_start_line(cmark_node *node) {
if (node == NULL) {
return 0;
}
return node->start_line;
}
int cmark_node_get_start_column(cmark_node *node) {
if (node == NULL) {
return 0;
}
return node->start_column;
}
int cmark_node_get_end_line(cmark_node *node) {
if (node == NULL) {
return 0;
}
return node->end_line;
}
int cmark_node_get_end_column(cmark_node *node) {
if (node == NULL) {
return 0;
}
return node->end_column;
}
// Unlink a node without adjusting its next, prev, and parent pointers.
static void S_node_unlink(cmark_node *node) {
if (node == NULL) {
return;
}
if (node->prev) {
node->prev->next = node->next;
}
if (node->next) {
node->next->prev = node->prev;
}
// Adjust first_child and last_child of parent.
cmark_node *parent = node->parent;
if (parent) {
if (parent->first_child == node) {
parent->first_child = node->next;
}
if (parent->last_child == node) {
parent->last_child = node->prev;
}
}
}
void cmark_node_unlink(cmark_node *node) {
S_node_unlink(node);
node->next = NULL;
node->prev = NULL;
node->parent = NULL;
}
int cmark_node_insert_before(cmark_node *node, cmark_node *sibling) {
if (node == NULL || sibling == NULL) {
return 0;
}
if (!node->parent || !S_can_contain(node->parent, sibling)) {
return 0;
}
S_node_unlink(sibling);
cmark_node *old_prev = node->prev;
// Insert 'sibling' between 'old_prev' and 'node'.
if (old_prev) {
old_prev->next = sibling;
}
sibling->prev = old_prev;
sibling->next = node;
node->prev = sibling;
// Set new parent.
cmark_node *parent = node->parent;
sibling->parent = parent;
// Adjust first_child of parent if inserted as first child.
if (parent && !old_prev) {
parent->first_child = sibling;
}
return 1;
}
int cmark_node_insert_after(cmark_node *node, cmark_node *sibling) {
if (node == NULL || sibling == NULL) {
return 0;
}
if (!node->parent || !S_can_contain(node->parent, sibling)) {
return 0;
}
S_node_unlink(sibling);
cmark_node *old_next = node->next;
// Insert 'sibling' between 'node' and 'old_next'.
if (old_next) {
old_next->prev = sibling;
}
sibling->next = old_next;
sibling->prev = node;
node->next = sibling;
// Set new parent.
cmark_node *parent = node->parent;
sibling->parent = parent;
// Adjust last_child of parent if inserted as last child.
if (parent && !old_next) {
parent->last_child = sibling;
}
return 1;
}
int cmark_node_replace(cmark_node *oldnode, cmark_node *newnode) {
if (!cmark_node_insert_before(oldnode, newnode)) {
return 0;
}
cmark_node_unlink(oldnode);
return 1;
}
int cmark_node_prepend_child(cmark_node *node, cmark_node *child) {
if (!S_can_contain(node, child)) {
return 0;
}
S_node_unlink(child);
cmark_node *old_first_child = node->first_child;
child->next = old_first_child;
child->prev = NULL;
child->parent = node;
node->first_child = child;
if (old_first_child) {
old_first_child->prev = child;
} else {
// Also set last_child if node previously had no children.
node->last_child = child;
}
return 1;
}
int cmark_node_append_child(cmark_node *node, cmark_node *child) {
if (!S_can_contain(node, child)) {
return 0;
}
S_node_unlink(child);
cmark_node *old_last_child = node->last_child;
child->next = NULL;
child->prev = old_last_child;
child->parent = node;
node->last_child = child;
if (old_last_child) {
old_last_child->next = child;
} else {
// Also set first_child if node previously had no children.
node->first_child = child;
}
return 1;
}
static void S_print_error(FILE *out, cmark_node *node, const char *elem) {
if (out == NULL) {
return;
}
fprintf(out, "Invalid '%s' in node type %s at %d:%d\n", elem,
cmark_node_get_type_string(node), node->start_line,
node->start_column);
}
int cmark_node_check(cmark_node *node, FILE *out) {
cmark_node *cur;
int errors = 0;
if (!node) {
return 0;
}
cur = node;
for (;;) {
if (cur->first_child) {
if (cur->first_child->prev != NULL) {
S_print_error(out, cur->first_child, "prev");
cur->first_child->prev = NULL;
++errors;
}
if (cur->first_child->parent != cur) {
S_print_error(out, cur->first_child, "parent");
cur->first_child->parent = cur;
++errors;
}
cur = cur->first_child;
continue;
}
next_sibling:
if (cur == node) {
break;
}
if (cur->next) {
if (cur->next->prev != cur) {
S_print_error(out, cur->next, "prev");
cur->next->prev = cur;
++errors;
}
if (cur->next->parent != cur->parent) {
S_print_error(out, cur->next, "parent");
cur->next->parent = cur->parent;
++errors;
}
cur = cur->next;
continue;
}
if (cur->parent->last_child != cur) {
S_print_error(out, cur->parent, "last_child");
cur->parent->last_child = cur;
++errors;
}
cur = cur->parent;
goto next_sibling;
}
return errors;
}
-88
View File
@@ -1,88 +0,0 @@
#ifndef CMARK_NODE_H
#define CMARK_NODE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdint.h>
#include "cmark.h"
#include "buffer.h"
#include "chunk.h"
typedef struct {
cmark_list_type list_type;
int marker_offset;
int padding;
int start;
cmark_delim_type delimiter;
unsigned char bullet_char;
bool tight;
} cmark_list;
typedef struct {
cmark_chunk info;
cmark_chunk literal;
int fence_length;
/* fence_offset must be 0-3, so we can use int8_t */
int8_t fence_offset;
unsigned char fence_char;
bool fenced;
} cmark_code;
typedef struct {
int level;
bool setext;
} cmark_heading;
typedef struct {
cmark_chunk url;
cmark_chunk title;
} cmark_link;
typedef struct {
cmark_chunk on_enter;
cmark_chunk on_exit;
} cmark_custom;
struct cmark_node {
struct cmark_node *next;
struct cmark_node *prev;
struct cmark_node *parent;
struct cmark_node *first_child;
struct cmark_node *last_child;
void *user_data;
int start_line;
int start_column;
int end_line;
int end_column;
cmark_node_type type;
bool open;
bool last_line_blank;
cmark_strbuf string_content;
union {
cmark_chunk literal;
cmark_list list;
cmark_code code;
cmark_heading heading;
cmark_link link;
cmark_custom custom;
int html_block_type;
} as;
};
CMARK_EXPORT int cmark_node_check(cmark_node *node, FILE *out);
#ifdef __cplusplus
}
#endif
#endif
-37
View File
@@ -1,37 +0,0 @@
#ifndef CMARK_AST_H
#define CMARK_AST_H
#include <stdio.h>
#include "node.h"
#include "buffer.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_LINK_LABEL_LENGTH 1000
struct cmark_parser {
struct cmark_reference_map *refmap;
struct cmark_node *root;
struct cmark_node *current;
int line_number;
bufsize_t offset;
bufsize_t column;
bufsize_t first_nonspace;
bufsize_t first_nonspace_column;
int indent;
bool blank;
bool partially_consumed_tab;
cmark_strbuf *curline;
bufsize_t last_line_length;
cmark_strbuf *linebuf;
int options;
bool last_buffer_ended_with_cr;
};
#ifdef __cplusplus
}
#endif
#endif
-144
View File
@@ -1,144 +0,0 @@
#include "cmark.h"
#include "utf8.h"
#include "parser.h"
#include "references.h"
#include "inlines.h"
#include "chunk.h"
static unsigned int refhash(const unsigned char *link_ref) {
unsigned int hash = 0;
while (*link_ref)
hash = (*link_ref++) + (hash << 6) + (hash << 16) - hash;
return hash;
}
static void reference_free(cmark_reference *ref) {
if (ref != NULL) {
free(ref->label);
cmark_chunk_free(&ref->url);
cmark_chunk_free(&ref->title);
free(ref);
}
}
// normalize reference: collapse internal whitespace to single space,
// remove leading/trailing whitespace, case fold
// Return NULL if the reference name is actually empty (i.e. composed
// solely from whitespace)
static unsigned char *normalize_reference(cmark_chunk *ref) {
cmark_strbuf normalized = GH_BUF_INIT;
unsigned char *result;
if (ref == NULL)
return NULL;
if (ref->len == 0)
return NULL;
cmark_utf8proc_case_fold(&normalized, ref->data, ref->len);
cmark_strbuf_trim(&normalized);
cmark_strbuf_normalize_whitespace(&normalized);
result = cmark_strbuf_detach(&normalized);
assert(result);
if (result[0] == '\0') {
free(result);
return NULL;
}
return result;
}
static void add_reference(cmark_reference_map *map, cmark_reference *ref) {
cmark_reference *t = ref->next = map->table[ref->hash % REFMAP_SIZE];
while (t) {
if (t->hash == ref->hash && !strcmp((char *)t->label, (char *)ref->label)) {
reference_free(ref);
return;
}
t = t->next;
}
map->table[ref->hash % REFMAP_SIZE] = ref;
}
void cmark_reference_create(cmark_reference_map *map, cmark_chunk *label,
cmark_chunk *url, cmark_chunk *title) {
cmark_reference *ref;
unsigned char *reflabel = normalize_reference(label);
/* empty reference name, or composed from only whitespace */
if (reflabel == NULL)
return;
ref = (cmark_reference *)calloc(1, sizeof(*ref));
if (ref != NULL) {
ref->label = reflabel;
ref->hash = refhash(ref->label);
ref->url = cmark_clean_url(url);
ref->title = cmark_clean_title(title);
ref->next = NULL;
add_reference(map, ref);
}
}
// Returns reference if refmap contains a reference with matching
// label, otherwise NULL.
cmark_reference *cmark_reference_lookup(cmark_reference_map *map,
cmark_chunk *label) {
cmark_reference *ref = NULL;
unsigned char *norm;
unsigned int hash;
if (label->len > MAX_LINK_LABEL_LENGTH)
return NULL;
if (map == NULL)
return NULL;
norm = normalize_reference(label);
if (norm == NULL)
return NULL;
hash = refhash(norm);
ref = map->table[hash % REFMAP_SIZE];
while (ref) {
if (ref->hash == hash && !strcmp((char *)ref->label, (char *)norm))
break;
ref = ref->next;
}
free(norm);
return ref;
}
void cmark_reference_map_free(cmark_reference_map *map) {
unsigned int i;
if (map == NULL)
return;
for (i = 0; i < REFMAP_SIZE; ++i) {
cmark_reference *ref = map->table[i];
cmark_reference *next;
while (ref) {
next = ref->next;
reference_free(ref);
ref = next;
}
}
free(map);
}
cmark_reference_map *cmark_reference_map_new(void) {
return (cmark_reference_map *)calloc(1, sizeof(cmark_reference_map));
}
-39
View File
@@ -1,39 +0,0 @@
#ifndef CMARK_REFERENCES_H
#define CMARK_REFERENCES_H
#include "chunk.h"
#ifdef __cplusplus
extern "C" {
#endif
#define REFMAP_SIZE 16
struct cmark_reference {
struct cmark_reference *next;
unsigned char *label;
cmark_chunk url;
cmark_chunk title;
unsigned int hash;
};
typedef struct cmark_reference cmark_reference;
struct cmark_reference_map {
cmark_reference *table[REFMAP_SIZE];
};
typedef struct cmark_reference_map cmark_reference_map;
cmark_reference_map *cmark_reference_map_new(void);
void cmark_reference_map_free(cmark_reference_map *map);
cmark_reference *cmark_reference_lookup(cmark_reference_map *map,
cmark_chunk *label);
extern void cmark_reference_create(cmark_reference_map *map, cmark_chunk *label,
cmark_chunk *url, cmark_chunk *title);
#ifdef __cplusplus
}
#endif
#endif
-182
View File
@@ -1,182 +0,0 @@
#include <stdlib.h>
#include "buffer.h"
#include "chunk.h"
#include "cmark.h"
#include "utf8.h"
#include "render.h"
static CMARK_INLINE void S_cr(cmark_renderer *renderer) {
if (renderer->need_cr < 1) {
renderer->need_cr = 1;
}
}
static CMARK_INLINE void S_blankline(cmark_renderer *renderer) {
if (renderer->need_cr < 2) {
renderer->need_cr = 2;
}
}
static void S_out(cmark_renderer *renderer, const char *source, bool wrap,
cmark_escaping escape) {
int length = cmark_strbuf_safe_strlen(source);
unsigned char nextc;
int32_t c;
int i = 0;
int last_nonspace;
int len;
cmark_chunk remainder = cmark_chunk_literal("");
int k = renderer->buffer->size - 1;
wrap = wrap && !renderer->no_wrap;
if (renderer->in_tight_list_item && renderer->need_cr > 1) {
renderer->need_cr = 1;
}
while (renderer->need_cr) {
if (k < 0 || renderer->buffer->ptr[k] == '\n') {
k -= 1;
} else {
cmark_strbuf_putc(renderer->buffer, '\n');
if (renderer->need_cr > 1) {
cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
renderer->prefix->size);
}
}
renderer->column = 0;
renderer->begin_line = true;
renderer->begin_content = true;
renderer->need_cr -= 1;
}
while (i < length) {
if (renderer->begin_line) {
cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
renderer->prefix->size);
// note: this assumes prefix is ascii:
renderer->column = renderer->prefix->size;
}
len = cmark_utf8proc_iterate((const uint8_t *)source + i, length - i, &c);
if (len == -1) { // error condition
return; // return without rendering rest of string
}
nextc = source[i + len];
if (c == 32 && wrap) {
if (!renderer->begin_line) {
last_nonspace = renderer->buffer->size;
cmark_strbuf_putc(renderer->buffer, ' ');
renderer->column += 1;
renderer->begin_line = false;
renderer->begin_content = false;
// skip following spaces
while (source[i + 1] == ' ') {
i++;
}
// We don't allow breaks that make a digit the first character
// because this causes problems with commonmark output.
if (!cmark_isdigit(source[i + 1])) {
renderer->last_breakable = last_nonspace;
}
}
} else if (c == 10) {
cmark_strbuf_putc(renderer->buffer, '\n');
renderer->column = 0;
renderer->begin_line = true;
renderer->begin_content = true;
renderer->last_breakable = 0;
} else if (escape == LITERAL) {
cmark_render_code_point(renderer, c);
renderer->begin_line = false;
// we don't set 'begin_content' to false til we've
// finished parsing a digit. Reason: in commonmark
// we need to escape a potential list marker after
// a digit:
renderer->begin_content =
renderer->begin_content && cmark_isdigit(c) == 1;
} else {
(renderer->outc)(renderer, escape, c, nextc);
renderer->begin_line = false;
renderer->begin_content =
renderer->begin_content && cmark_isdigit(c) == 1;
}
// If adding the character went beyond width, look for an
// earlier place where the line could be broken:
if (renderer->width > 0 && renderer->column > renderer->width &&
!renderer->begin_line && renderer->last_breakable > 0) {
// copy from last_breakable to remainder
cmark_chunk_set_cstr(&remainder, (char *)renderer->buffer->ptr +
renderer->last_breakable + 1);
// truncate at last_breakable
cmark_strbuf_truncate(renderer->buffer, renderer->last_breakable);
// add newline, prefix, and remainder
cmark_strbuf_putc(renderer->buffer, '\n');
cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
renderer->prefix->size);
cmark_strbuf_put(renderer->buffer, remainder.data, remainder.len);
renderer->column = renderer->prefix->size + remainder.len;
cmark_chunk_free(&remainder);
renderer->last_breakable = 0;
renderer->begin_line = false;
renderer->begin_content = false;
}
i += len;
}
}
// Assumes no newlines, assumes ascii content:
void cmark_render_ascii(cmark_renderer *renderer, const char *s) {
int origsize = renderer->buffer->size;
cmark_strbuf_puts(renderer->buffer, s);
renderer->column += renderer->buffer->size - origsize;
}
void cmark_render_code_point(cmark_renderer *renderer, uint32_t c) {
cmark_utf8proc_encode_char(c, renderer->buffer);
renderer->column += 1;
}
char *cmark_render(cmark_node *root, int options, int width,
void (*outc)(cmark_renderer *, cmark_escaping, int32_t,
unsigned char),
int (*render_node)(cmark_renderer *renderer,
cmark_node *node,
cmark_event_type ev_type, int options)) {
cmark_strbuf pref = GH_BUF_INIT;
cmark_strbuf buf = GH_BUF_INIT;
cmark_node *cur;
cmark_event_type ev_type;
char *result;
cmark_iter *iter = cmark_iter_new(root);
cmark_renderer renderer = {&buf, &pref, 0, width, 0,
0, true, true, false, false,
outc, S_cr, S_blankline, S_out};
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
cur = cmark_iter_get_node(iter);
if (!render_node(&renderer, cur, ev_type, options)) {
// a false value causes us to skip processing
// the node's contents. this is used for
// autolinks.
cmark_iter_reset(iter, cur, CMARK_EVENT_EXIT);
}
}
// ensure final newline
if (renderer.buffer->ptr[renderer.buffer->size - 1] != '\n') {
cmark_strbuf_putc(renderer.buffer, '\n');
}
result = (char *)cmark_strbuf_detach(renderer.buffer);
cmark_iter_free(iter);
cmark_strbuf_free(renderer.prefix);
cmark_strbuf_free(renderer.buffer);
return result;
}
-48
View File
@@ -1,48 +0,0 @@
#ifndef CMARK_RENDER_H
#define CMARK_RENDER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include "buffer.h"
#include "chunk.h"
typedef enum { LITERAL, NORMAL, TITLE, URL } cmark_escaping;
struct cmark_renderer {
cmark_strbuf *buffer;
cmark_strbuf *prefix;
int column;
int width;
int need_cr;
bufsize_t last_breakable;
bool begin_line;
bool begin_content;
bool no_wrap;
bool in_tight_list_item;
void (*outc)(struct cmark_renderer *, cmark_escaping, int32_t, unsigned char);
void (*cr)(struct cmark_renderer *);
void (*blankline)(struct cmark_renderer *);
void (*out)(struct cmark_renderer *, const char *, bool, cmark_escaping);
};
typedef struct cmark_renderer cmark_renderer;
void cmark_render_ascii(cmark_renderer *renderer, const char *s);
void cmark_render_code_point(cmark_renderer *renderer, uint32_t c);
char *cmark_render(cmark_node *root, int options, int width,
void (*outc)(cmark_renderer *, cmark_escaping, int32_t,
unsigned char),
int (*render_node)(cmark_renderer *renderer,
cmark_node *node,
cmark_event_type ev_type, int options));
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large Load Diff
-57
View File
@@ -1,57 +0,0 @@
#include "cmark.h"
#include "chunk.h"
#ifdef __cplusplus
extern "C" {
#endif
bufsize_t _scan_at(bufsize_t (*scanner)(const unsigned char *), cmark_chunk *c,
bufsize_t offset);
bufsize_t _scan_scheme(const unsigned char *p);
bufsize_t _scan_autolink_uri(const unsigned char *p);
bufsize_t _scan_autolink_email(const unsigned char *p);
bufsize_t _scan_html_tag(const unsigned char *p);
bufsize_t _scan_html_block_start(const unsigned char *p);
bufsize_t _scan_html_block_start_7(const unsigned char *p);
bufsize_t _scan_html_block_end_1(const unsigned char *p);
bufsize_t _scan_html_block_end_2(const unsigned char *p);
bufsize_t _scan_html_block_end_3(const unsigned char *p);
bufsize_t _scan_html_block_end_4(const unsigned char *p);
bufsize_t _scan_html_block_end_5(const unsigned char *p);
bufsize_t _scan_link_url(const unsigned char *p);
bufsize_t _scan_link_title(const unsigned char *p);
bufsize_t _scan_spacechars(const unsigned char *p);
bufsize_t _scan_atx_heading_start(const unsigned char *p);
bufsize_t _scan_setext_heading_line(const unsigned char *p);
bufsize_t _scan_thematic_break(const unsigned char *p);
bufsize_t _scan_open_code_fence(const unsigned char *p);
bufsize_t _scan_close_code_fence(const unsigned char *p);
bufsize_t _scan_entity(const unsigned char *p);
bufsize_t _scan_dangerous_url(const unsigned char *p);
#define scan_scheme(c, n) _scan_at(&_scan_scheme, c, n)
#define scan_autolink_uri(c, n) _scan_at(&_scan_autolink_uri, c, n)
#define scan_autolink_email(c, n) _scan_at(&_scan_autolink_email, c, n)
#define scan_html_tag(c, n) _scan_at(&_scan_html_tag, c, n)
#define scan_html_block_start(c, n) _scan_at(&_scan_html_block_start, c, n)
#define scan_html_block_start_7(c, n) _scan_at(&_scan_html_block_start_7, c, n)
#define scan_html_block_end_1(c, n) _scan_at(&_scan_html_block_end_1, c, n)
#define scan_html_block_end_2(c, n) _scan_at(&_scan_html_block_end_2, c, n)
#define scan_html_block_end_3(c, n) _scan_at(&_scan_html_block_end_3, c, n)
#define scan_html_block_end_4(c, n) _scan_at(&_scan_html_block_end_4, c, n)
#define scan_html_block_end_5(c, n) _scan_at(&_scan_html_block_end_5, c, n)
#define scan_link_url(c, n) _scan_at(&_scan_link_url, c, n)
#define scan_link_title(c, n) _scan_at(&_scan_link_title, c, n)
#define scan_spacechars(c, n) _scan_at(&_scan_spacechars, c, n)
#define scan_atx_heading_start(c, n) _scan_at(&_scan_atx_heading_start, c, n)
#define scan_setext_heading_line(c, n) \
_scan_at(&_scan_setext_heading_line, c, n)
#define scan_thematic_break(c, n) _scan_at(&_scan_thematic_break, c, n)
#define scan_open_code_fence(c, n) _scan_at(&_scan_open_code_fence, c, n)
#define scan_close_code_fence(c, n) _scan_at(&_scan_close_code_fence, c, n)
#define scan_entity(c, n) _scan_at(&_scan_entity, c, n)
#define scan_dangerous_url(c, n) _scan_at(&_scan_dangerous_url, c, n)
#ifdef __cplusplus
}
#endif
-317
View File
@@ -1,317 +0,0 @@
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include "cmark_ctype.h"
#include "utf8.h"
static const int8_t utf8proc_utf8class[256] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0};
static void encode_unknown(cmark_strbuf *buf) {
static const uint8_t repl[] = {239, 191, 189};
cmark_strbuf_put(buf, repl, 3);
}
static int utf8proc_charlen(const uint8_t *str, bufsize_t str_len) {
int length, i;
if (!str_len)
return 0;
length = utf8proc_utf8class[str[0]];
if (!length)
return -1;
if (str_len >= 0 && (bufsize_t)length > str_len)
return -str_len;
for (i = 1; i < length; i++) {
if ((str[i] & 0xC0) != 0x80)
return -i;
}
return length;
}
// Validate a single UTF-8 character according to RFC 3629.
static int utf8proc_valid(const uint8_t *str, bufsize_t str_len) {
int length = utf8proc_utf8class[str[0]];
if (!length)
return -1;
if ((bufsize_t)length > str_len)
return -str_len;
switch (length) {
case 2:
if ((str[1] & 0xC0) != 0x80)
return -1;
if (str[0] < 0xC2) {
// Overlong
return -length;
}
break;
case 3:
if ((str[1] & 0xC0) != 0x80)
return -1;
if ((str[2] & 0xC0) != 0x80)
return -2;
if (str[0] == 0xE0) {
if (str[1] < 0xA0) {
// Overlong
return -length;
}
} else if (str[0] == 0xED) {
if (str[1] >= 0xA0) {
// Surrogate
return -length;
}
}
break;
case 4:
if ((str[1] & 0xC0) != 0x80)
return -1;
if ((str[2] & 0xC0) != 0x80)
return -2;
if ((str[3] & 0xC0) != 0x80)
return -3;
if (str[0] == 0xF0) {
if (str[1] < 0x90) {
// Overlong
return -length;
}
} else if (str[0] >= 0xF4) {
if (str[0] > 0xF4 || str[1] >= 0x90) {
// Above 0x10FFFF
return -length;
}
}
break;
}
return length;
}
void cmark_utf8proc_check(cmark_strbuf *ob, const uint8_t *line,
bufsize_t size) {
bufsize_t i = 0;
while (i < size) {
bufsize_t org = i;
int charlen = 0;
while (i < size) {
if (line[i] < 0x80 && line[i] != 0) {
i++;
} else if (line[i] >= 0x80) {
charlen = utf8proc_valid(line + i, size - i);
if (charlen < 0) {
charlen = -charlen;
break;
}
i += charlen;
} else if (line[i] == 0) {
// ASCII NUL is technically valid but rejected
// for security reasons.
charlen = 1;
break;
}
}
if (i > org) {
cmark_strbuf_put(ob, line + org, i - org);
}
if (i >= size) {
break;
} else {
// Invalid UTF-8
encode_unknown(ob);
i += charlen;
}
}
}
int cmark_utf8proc_iterate(const uint8_t *str, bufsize_t str_len,
int32_t *dst) {
int length;
int32_t uc = -1;
*dst = -1;
length = utf8proc_charlen(str, str_len);
if (length < 0)
return -1;
switch (length) {
case 1:
uc = str[0];
break;
case 2:
uc = ((str[0] & 0x1F) << 6) + (str[1] & 0x3F);
if (uc < 0x80)
uc = -1;
break;
case 3:
uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) << 6) + (str[2] & 0x3F);
if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000))
uc = -1;
break;
case 4:
uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12) +
((str[2] & 0x3F) << 6) + (str[3] & 0x3F);
if (uc < 0x10000 || uc >= 0x110000)
uc = -1;
break;
}
if (uc < 0)
return -1;
*dst = uc;
return length;
}
void cmark_utf8proc_encode_char(int32_t uc, cmark_strbuf *buf) {
uint8_t dst[4];
bufsize_t len = 0;
assert(uc >= 0);
if (uc < 0x80) {
dst[0] = (uint8_t)(uc);
len = 1;
} else if (uc < 0x800) {
dst[0] = (uint8_t)(0xC0 + (uc >> 6));
dst[1] = 0x80 + (uc & 0x3F);
len = 2;
} else if (uc == 0xFFFF) {
dst[0] = 0xFF;
len = 1;
} else if (uc == 0xFFFE) {
dst[0] = 0xFE;
len = 1;
} else if (uc < 0x10000) {
dst[0] = (uint8_t)(0xE0 + (uc >> 12));
dst[1] = 0x80 + ((uc >> 6) & 0x3F);
dst[2] = 0x80 + (uc & 0x3F);
len = 3;
} else if (uc < 0x110000) {
dst[0] = (uint8_t)(0xF0 + (uc >> 18));
dst[1] = 0x80 + ((uc >> 12) & 0x3F);
dst[2] = 0x80 + ((uc >> 6) & 0x3F);
dst[3] = 0x80 + (uc & 0x3F);
len = 4;
} else {
encode_unknown(buf);
return;
}
cmark_strbuf_put(buf, dst, len);
}
void cmark_utf8proc_case_fold(cmark_strbuf *dest, const uint8_t *str,
bufsize_t len) {
int32_t c;
#define bufpush(x) cmark_utf8proc_encode_char(x, dest)
while (len > 0) {
bufsize_t char_len = cmark_utf8proc_iterate(str, len, &c);
if (char_len >= 0) {
#include "case_fold_switch.inc"
} else {
encode_unknown(dest);
char_len = -char_len;
}
str += char_len;
len -= char_len;
}
}
// matches anything in the Zs class, plus LF, CR, TAB, FF.
int cmark_utf8proc_is_space(int32_t uc) {
return (uc == 9 || uc == 10 || uc == 12 || uc == 13 || uc == 32 ||
uc == 160 || uc == 5760 || (uc >= 8192 && uc <= 8202) || uc == 8239 ||
uc == 8287 || uc == 12288);
}
// matches anything in the P[cdefios] classes.
int cmark_utf8proc_is_punctuation(int32_t uc) {
return (
(uc < 128 && cmark_ispunct((char)uc)) || uc == 161 || uc == 167 ||
uc == 171 || uc == 182 || uc == 183 || uc == 187 || uc == 191 ||
uc == 894 || uc == 903 || (uc >= 1370 && uc <= 1375) || uc == 1417 ||
uc == 1418 || uc == 1470 || uc == 1472 || uc == 1475 || uc == 1478 ||
uc == 1523 || uc == 1524 || uc == 1545 || uc == 1546 || uc == 1548 ||
uc == 1549 || uc == 1563 || uc == 1566 || uc == 1567 ||
(uc >= 1642 && uc <= 1645) || uc == 1748 || (uc >= 1792 && uc <= 1805) ||
(uc >= 2039 && uc <= 2041) || (uc >= 2096 && uc <= 2110) || uc == 2142 ||
uc == 2404 || uc == 2405 || uc == 2416 || uc == 2800 || uc == 3572 ||
uc == 3663 || uc == 3674 || uc == 3675 || (uc >= 3844 && uc <= 3858) ||
uc == 3860 || (uc >= 3898 && uc <= 3901) || uc == 3973 ||
(uc >= 4048 && uc <= 4052) || uc == 4057 || uc == 4058 ||
(uc >= 4170 && uc <= 4175) || uc == 4347 || (uc >= 4960 && uc <= 4968) ||
uc == 5120 || uc == 5741 || uc == 5742 || uc == 5787 || uc == 5788 ||
(uc >= 5867 && uc <= 5869) || uc == 5941 || uc == 5942 ||
(uc >= 6100 && uc <= 6102) || (uc >= 6104 && uc <= 6106) ||
(uc >= 6144 && uc <= 6154) || uc == 6468 || uc == 6469 || uc == 6686 ||
uc == 6687 || (uc >= 6816 && uc <= 6822) || (uc >= 6824 && uc <= 6829) ||
(uc >= 7002 && uc <= 7008) || (uc >= 7164 && uc <= 7167) ||
(uc >= 7227 && uc <= 7231) || uc == 7294 || uc == 7295 ||
(uc >= 7360 && uc <= 7367) || uc == 7379 || (uc >= 8208 && uc <= 8231) ||
(uc >= 8240 && uc <= 8259) || (uc >= 8261 && uc <= 8273) ||
(uc >= 8275 && uc <= 8286) || uc == 8317 || uc == 8318 || uc == 8333 ||
uc == 8334 || (uc >= 8968 && uc <= 8971) || uc == 9001 || uc == 9002 ||
(uc >= 10088 && uc <= 10101) || uc == 10181 || uc == 10182 ||
(uc >= 10214 && uc <= 10223) || (uc >= 10627 && uc <= 10648) ||
(uc >= 10712 && uc <= 10715) || uc == 10748 || uc == 10749 ||
(uc >= 11513 && uc <= 11516) || uc == 11518 || uc == 11519 ||
uc == 11632 || (uc >= 11776 && uc <= 11822) ||
(uc >= 11824 && uc <= 11842) || (uc >= 12289 && uc <= 12291) ||
(uc >= 12296 && uc <= 12305) || (uc >= 12308 && uc <= 12319) ||
uc == 12336 || uc == 12349 || uc == 12448 || uc == 12539 || uc == 42238 ||
uc == 42239 || (uc >= 42509 && uc <= 42511) || uc == 42611 ||
uc == 42622 || (uc >= 42738 && uc <= 42743) ||
(uc >= 43124 && uc <= 43127) || uc == 43214 || uc == 43215 ||
(uc >= 43256 && uc <= 43258) || uc == 43310 || uc == 43311 ||
uc == 43359 || (uc >= 43457 && uc <= 43469) || uc == 43486 ||
uc == 43487 || (uc >= 43612 && uc <= 43615) || uc == 43742 ||
uc == 43743 || uc == 43760 || uc == 43761 || uc == 44011 || uc == 64830 ||
uc == 64831 || (uc >= 65040 && uc <= 65049) ||
(uc >= 65072 && uc <= 65106) || (uc >= 65108 && uc <= 65121) ||
uc == 65123 || uc == 65128 || uc == 65130 || uc == 65131 ||
(uc >= 65281 && uc <= 65283) || (uc >= 65285 && uc <= 65290) ||
(uc >= 65292 && uc <= 65295) || uc == 65306 || uc == 65307 ||
uc == 65311 || uc == 65312 || (uc >= 65339 && uc <= 65341) ||
uc == 65343 || uc == 65371 || uc == 65373 ||
(uc >= 65375 && uc <= 65381) || (uc >= 65792 && uc <= 65794) ||
uc == 66463 || uc == 66512 || uc == 66927 || uc == 67671 || uc == 67871 ||
uc == 67903 || (uc >= 68176 && uc <= 68184) || uc == 68223 ||
(uc >= 68336 && uc <= 68342) || (uc >= 68409 && uc <= 68415) ||
(uc >= 68505 && uc <= 68508) || (uc >= 69703 && uc <= 69709) ||
uc == 69819 || uc == 69820 || (uc >= 69822 && uc <= 69825) ||
(uc >= 69952 && uc <= 69955) || uc == 70004 || uc == 70005 ||
(uc >= 70085 && uc <= 70088) || uc == 70093 ||
(uc >= 70200 && uc <= 70205) || uc == 70854 ||
(uc >= 71105 && uc <= 71113) || (uc >= 71233 && uc <= 71235) ||
(uc >= 74864 && uc <= 74868) || uc == 92782 || uc == 92783 ||
uc == 92917 || (uc >= 92983 && uc <= 92987) || uc == 92996 ||
uc == 113823);
}
-24
View File
@@ -1,24 +0,0 @@
#ifndef CMARK_UTF8_H
#define CMARK_UTF8_H
#include <stdint.h>
#include "buffer.h"
#ifdef __cplusplus
extern "C" {
#endif
void cmark_utf8proc_case_fold(cmark_strbuf *dest, const uint8_t *str,
bufsize_t len);
void cmark_utf8proc_encode_char(int32_t uc, cmark_strbuf *buf);
int cmark_utf8proc_iterate(const uint8_t *str, bufsize_t str_len, int32_t *dst);
void cmark_utf8proc_check(cmark_strbuf *dest, const uint8_t *line,
bufsize_t size);
int cmark_utf8proc_is_space(int32_t uc);
int cmark_utf8proc_is_punctuation(int32_t uc);
#ifdef __cplusplus
}
#endif
#endif
-170
View File
@@ -1,170 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "config.h"
#include "cmark.h"
#include "node.h"
#include "buffer.h"
#include "houdini.h"
#define BUFFER_SIZE 100
// Functions to convert cmark_nodes to XML strings.
static void escape_xml(cmark_strbuf *dest, const unsigned char *source,
bufsize_t length) {
houdini_escape_html0(dest, source, length, 0);
}
struct render_state {
cmark_strbuf *xml;
int indent;
};
static CMARK_INLINE void indent(struct render_state *state) {
int i;
for (i = 0; i < state->indent; i++) {
cmark_strbuf_putc(state->xml, ' ');
}
}
static int S_render_node(cmark_node *node, cmark_event_type ev_type,
struct render_state *state, int options) {
cmark_strbuf *xml = state->xml;
bool literal = false;
cmark_delim_type delim;
bool entering = (ev_type == CMARK_EVENT_ENTER);
char buffer[BUFFER_SIZE];
if (entering) {
indent(state);
cmark_strbuf_putc(xml, '<');
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
if (options & CMARK_OPT_SOURCEPOS && node->start_line != 0) {
snprintf(buffer, BUFFER_SIZE, " sourcepos=\"%d:%d-%d:%d\"",
node->start_line, node->start_column, node->end_line,
node->end_column);
cmark_strbuf_puts(xml, buffer);
}
literal = false;
switch (node->type) {
case CMARK_NODE_DOCUMENT:
cmark_strbuf_puts(xml, " xmlns=\"http://commonmark.org/xml/1.0\"");
break;
case CMARK_NODE_TEXT:
case CMARK_NODE_CODE:
case CMARK_NODE_HTML_BLOCK:
case CMARK_NODE_HTML_INLINE:
cmark_strbuf_puts(xml, ">");
escape_xml(xml, node->as.literal.data, node->as.literal.len);
cmark_strbuf_puts(xml, "</");
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
literal = true;
break;
case CMARK_NODE_LIST:
switch (cmark_node_get_list_type(node)) {
case CMARK_ORDERED_LIST:
cmark_strbuf_puts(xml, " type=\"ordered\"");
snprintf(buffer, BUFFER_SIZE, " start=\"%d\"",
cmark_node_get_list_start(node));
cmark_strbuf_puts(xml, buffer);
delim = cmark_node_get_list_delim(node);
if (delim == CMARK_PAREN_DELIM) {
cmark_strbuf_puts(xml, " delim=\"paren\"");
} else if (delim == CMARK_PERIOD_DELIM) {
cmark_strbuf_puts(xml, " delim=\"period\"");
}
break;
case CMARK_BULLET_LIST:
cmark_strbuf_puts(xml, " type=\"bullet\"");
break;
default:
break;
}
snprintf(buffer, BUFFER_SIZE, " tight=\"%s\"",
(cmark_node_get_list_tight(node) ? "true" : "false"));
cmark_strbuf_puts(xml, buffer);
break;
case CMARK_NODE_HEADING:
snprintf(buffer, BUFFER_SIZE, " level=\"%d\"", node->as.heading.level);
cmark_strbuf_puts(xml, buffer);
break;
case CMARK_NODE_CODE_BLOCK:
if (node->as.code.info.len > 0) {
cmark_strbuf_puts(xml, " info=\"");
escape_xml(xml, node->as.code.info.data, node->as.code.info.len);
cmark_strbuf_putc(xml, '"');
}
cmark_strbuf_puts(xml, ">");
escape_xml(xml, node->as.code.literal.data, node->as.code.literal.len);
cmark_strbuf_puts(xml, "</");
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
literal = true;
break;
case CMARK_NODE_CUSTOM_BLOCK:
case CMARK_NODE_CUSTOM_INLINE:
cmark_strbuf_puts(xml, " on_enter=\"");
escape_xml(xml, node->as.custom.on_enter.data,
node->as.custom.on_enter.len);
cmark_strbuf_putc(xml, '"');
cmark_strbuf_puts(xml, " on_exit=\"");
escape_xml(xml, node->as.custom.on_exit.data,
node->as.custom.on_exit.len);
cmark_strbuf_putc(xml, '"');
break;
case CMARK_NODE_LINK:
case CMARK_NODE_IMAGE:
cmark_strbuf_puts(xml, " destination=\"");
escape_xml(xml, node->as.link.url.data, node->as.link.url.len);
cmark_strbuf_putc(xml, '"');
cmark_strbuf_puts(xml, " title=\"");
escape_xml(xml, node->as.link.title.data, node->as.link.title.len);
cmark_strbuf_putc(xml, '"');
break;
default:
break;
}
if (node->first_child) {
state->indent += 2;
} else if (!literal) {
cmark_strbuf_puts(xml, " /");
}
cmark_strbuf_puts(xml, ">\n");
} else if (node->first_child) {
state->indent -= 2;
indent(state);
cmark_strbuf_puts(xml, "</");
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
cmark_strbuf_puts(xml, ">\n");
}
return 1;
}
char *cmark_render_xml(cmark_node *root, int options) {
char *result;
cmark_strbuf xml = GH_BUF_INIT;
cmark_event_type ev_type;
cmark_node *cur;
struct render_state state = {&xml, 0};
cmark_iter *iter = cmark_iter_new(root);
cmark_strbuf_puts(state.xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
cmark_strbuf_puts(state.xml,
"<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n");
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
cur = cmark_iter_get_node(iter);
S_render_node(cur, ev_type, &state, options);
}
result = (char *)cmark_strbuf_detach(&xml);
cmark_iter_free(iter);
return result;
}