Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the handle_backticks issue #426

Closed
wants to merge 229 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
229 commits
Select commit Hold shift + click to select a range
cec3765
More runs in benchmark; .gitignore update
Sep 26, 2016
f30d3c6
Arena allocator
Sep 27, 2016
c8960d7
Extensions API (https://github.com/jgm/cmark/pull/123)
MathieuDuponchelle Dec 1, 2016
3e3761a
Strip extensions API down and separate from core
Dec 1, 2016
0445d10
Table extension from c068469 reworked
Nov 29, 2016
c55225f
Strikethrough extension from c068469 reworked
Nov 29, 2016
920f728
Autolink extension
Nov 29, 2016
1eab596
Tagfilter extension
Nov 29, 2016
3e5f8a4
Reduce maximum amount of backticks
vmg Nov 28, 2016
c36f848
Get a clean build on MSVC (#5)
Dec 9, 2016
b9df6b3
table: trim cells, fix escaping, cleanup (#4)
Dec 13, 2016
3636dc9
Initialise openers bottom correctly
Jan 5, 2017
a49c13a
Fix for inline parser changes
Jan 23, 2017
b555d89
Abort if we fail to alloc chunk itself
Jan 26, 2017
16846c6
Add a no-crash test
Jan 27, 2017
f893cfa
Add opaque_free_func to extensions
Feb 6, 2017
9822599
Use opaque instead of user_data in table
Feb 6, 2017
061c1f6
Rework email autolink as postprocessor
Feb 2, 2017
9f85003
Compile shared library for extensions
Feb 6, 2017
b9a3ab8
Use extensions in spec test
Feb 6, 2017
7b0b501
Only escape pipes in commonmark output when necessary
Feb 6, 2017
d6ac760
Fix Windows build
Feb 7, 2017
fd110a5
Preserve number of tildes in failed strikethru
Feb 9, 2017
e548d42
autolink simplification
Feb 10, 2017
6923e1e
autolink_delim only works with ")", fix balance behaviour
Feb 10, 2017
a331579
spec update
Feb 9, 2017
8cb4978
Windows build fix (again)
Mar 6, 2017
90b6f7d
Support UTF-8 domains in autolinks
Mar 13, 2017
dcfddd7
Handle links in quotes correctly.
Mar 13, 2017
331b192
Reference links in tables (#10)
Mar 15, 2017
166942b
Handle UTF-8 BOM (#14)
Mar 20, 2017
5d08859
Add CMARK_OPT_GITHUB_PRE_LANG
Mar 22, 2017
81816f3
Use <pre><code>
Mar 22, 2017
0c167f8
Fix empty table cell behaviour (#17)
Mar 26, 2017
8fafc10
Limit arena
Mar 27, 2017
2714110
Add Dockerfile
Mar 28, 2017
c2712a4
Add -gfm suffix to artifacts
Mar 28, 2017
eaf3b8f
README updates
Mar 28, 2017
4c4df80
Correct manpages. Fixes #20.
Apr 3, 2017
21bbc4c
Simple tables (#21)
Apr 4, 2017
36b5588
Latest spec
Apr 4, 2017
5dfedc7
Skip disabled extensions
Apr 4, 2017
f2fa4a1
roundtrip_tests reports results
Apr 4, 2017
9dc52d8
Add GFM version number
May 1, 2017
c0f16ae
Plaintext renderer (#25)
May 8, 2017
47e724d
Remove normalize as an option per #190 (#194)
May 8, 2017
afd530f
Remove dead/misleading code
May 15, 2017
9f81059
Add table alignment getters (#29)
May 22, 2017
b0707b6
make install also installs extensions (#32)
May 29, 2017
fff48d5
0.27.1.gfm.1
May 29, 2017
d9526ab
Add CMARK_GFM_VERSION define.
May 29, 2017
1cd892e
Fix link order of cmark-gfm (#35)
nafest May 31, 2017
ec5dcf4
Add `cmark_syntax_extension_get_private()` (#36)
foonathan Jun 2, 2017
fa66ade
Unmark as static
Jun 16, 2017
a38cfc0
Don't scan past an EOL (#37)
Jun 21, 2017
cb91444
Regenerate scanner
Jun 21, 2017
4b3267d
Also exclude \n
Jun 21, 2017
a758a35
Update cmark-fuzz for cmark-gfm
Jun 29, 2017
71b0d00
Latest cmake in Docker
Jun 30, 2017
0fbab47
Fix a misaligned write
Jun 30, 2017
2af1c5c
0.27.1.gfm.2
Jun 30, 2017
ffa8c3e
Install ninja-build
Jun 30, 2017
3a3ac47
Avoid memcpy'ing NULL pointers (#38)
philipturnbull Jul 6, 2017
fca380c
Case-insensitive tagfilter. Fixes #42. (#43)
Jul 7, 2017
7d70d2c
Allocate memory from arena with correct alignment (#40)
philipturnbull Jul 11, 2017
494f10a
Use unsigned integer when shifting (#39)
philipturnbull Jul 11, 2017
970e029
0.27.1.gfm.3
kivikakk Jul 11, 2017
298d9d2
> 32 nested balanced parens in a link is bananas (#48)
Jul 12, 2017
175542b
0.27.1.gfm.4
kivikakk Jul 12, 2017
c93dc8b
Latest spec
kivikakk Jul 14, 2017
d219c0a
Fix typo (#52)
Alhadis Jul 17, 2017
e45ee8d
test: Add test case for pathological collisions
vmg Jul 14, 2017
384cc9d
references: Fix pathological quadatric behavior
vmg Jul 14, 2017
45ca300
Fix pathological test runner on Windows
kivikakk Jul 17, 2017
62166fe
Add casts for MSVC10
kivikakk Jul 17, 2017
66a0836
Merge branch 'vmg/collisions'
kivikakk Jul 17, 2017
2b158e1
Update to latest spec
kivikakk Aug 2, 2017
2731cb0
Add the idempotent core_extensions_ensure_registered
kivikakk Aug 7, 2017
b9459ef
Inline sourcepos (#53)
Aug 9, 2017
7cf993f
Remove unneeded TODO
kivikakk Aug 9, 2017
8595dda
0.28.0.gfm.5
kivikakk Aug 9, 2017
fd7d177
Sourcepos fixes (#54)
Aug 10, 2017
3a9081b
0.28.0.gfm.6
kivikakk Aug 10, 2017
8eb09f8
Skip strikethroughs when considering emphasis (#55)
Aug 17, 2017
2667be9
0.28.0.gfm.7
kivikakk Aug 17, 2017
fa84ac8
Autolink should not cause : to be skipped
kivikakk Aug 25, 2017
c939f0e
Merge remote-tracking branch 'upstream/master'
kivikakk Aug 25, 2017
28232aa
0.28.0.gfm.8
kivikakk Aug 25, 2017
820372d
Recursive chevrons are bananas (#49)
Sep 6, 2017
150239c
0.28.0.gfm.9
kivikakk Sep 6, 2017
63f17be
blocks: Fix quadratic behavior in `finalize`
vmg Sep 7, 2017
d946b7c
0.28.0.gfm.10
kivikakk Sep 8, 2017
3afbcad
No empty <tbody>
kivikakk Sep 11, 2017
e3f3a27
0.28.0.gfm.11
kivikakk Sep 11, 2017
07fe00f
Period in email must precede alnum (#58)
Oct 3, 2017
fff5fef
Merge branch 'upstream-master'
kivikakk Nov 5, 2017
1781c95
feature test macros in harness
kivikakk Nov 6, 2017
37804e6
Fix install EXPORT target
kivikakk Nov 6, 2017
8d71a16
Shift includes around for proper header install (#63)
Nov 6, 2017
9188bdf
add node.js wrapper (#46)
killagu Nov 9, 2017
59f7233
Footnotes (#64)
Nov 16, 2017
57b3567
FOOTNOTE_REFERENCE has text content
kivikakk Nov 16, 2017
6b101e3
Footnote fix per kivikakk/comrak#44
kivikakk Nov 26, 2017
0c6d1c4
ASCII clean source
kivikakk Dec 12, 2017
e97b324
Add -lcmark-gfmextensions to libcmark-gfm.pc.in
kivikakk Jan 7, 2018
e1fa457
Merge remote-tracking branch 'upstream/master'
kivikakk Jan 7, 2018
6df666d
Fix extensions with static only
kivikakk Jan 7, 2018
f0b8686
Build static on Windows again
kivikakk Jan 7, 2018
7ef1ebc
0.28.3.gfm.12
kivikakk Jan 7, 2018
9137851
Add CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE. Closes #71.
kivikakk Jan 25, 2018
7ddfb10
add CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES (#86)
gfx Feb 20, 2018
b6098ab
add tests for --table-prefer-style-attributes (#87)
gfx Feb 20, 2018
bf28ef6
Remove square brackets when rendering HTML for footnotes (#90)
pyrmont Mar 12, 2018
c7ac6ac
Merge remote-tracking branch 'upstream/master'
kivikakk Apr 13, 2018
b7a3b74
Handle deeply nested lists (#95)
philipturnbull Jun 20, 2018
7b4a497
Expose `cmark_node_type CMARK_NODE_TABLE` etc., make XCode happy with…
molikto Jun 20, 2018
907dcdf
Debian packaging (#97)
troglobit Jun 20, 2018
02bc37d
Removed meta from list of block tags.
jgm Jun 11, 2018
61f1f05
Fix spaces on regression test.
jgm Jun 11, 2018
38cc7a4
add regression test from comrak
kivikakk Jul 12, 2018
e9a231f
latest spec
kivikakk Jul 12, 2018
343c5d2
latest spec
kivikakk Jul 15, 2018
648b388
regressions.txt has non-specified strikethrough
kivikakk Jul 15, 2018
8aa0868
Add example of a Python wrapper which uses libcmark-gfmextensions. (#…
gstein Jul 19, 2018
4503875
Parse rest of info string as meta (#103)
mikekavouras Aug 8, 2018
4057e9f
0.28.3.gfm.13
kivikakk Aug 8, 2018
0accc94
add plaintext render func for strikethru
kivikakk Aug 9, 2018
1b1f90d
0.28.3.gfm.14
kivikakk Aug 10, 2018
17b339e
commonmark writer: escape tilde (~). (#106)
jgm Aug 19, 2018
1470c30
table extension: cosmetic fix for uniformity of output. (#105)
jgm Aug 19, 2018
9ceb8bd
commonmark writer/strikethrough: use two tildes for delimiters. (#104)
jgm Aug 19, 2018
3221400
Normalise header and define names (#109)
Aug 21, 2018
f649003
0.28.3.gfm.15
kivikakk Aug 21, 2018
ea2a07d
`~` should not be escaped in href (#110)
Sep 5, 2018
a9dbc9c
Footnotes in tables (#112)
Sep 10, 2018
446767d
0.28.3.gfm.16
kivikakk Sep 10, 2018
22d1149
Allow extension to provide "opaque" alloc function (#89)
nojb Sep 13, 2018
e4de28e
Merge remote-tracking branch 'upstream/master'
kivikakk Sep 16, 2018
258d2a4
XML attribute formatters (#116)
Sep 24, 2018
e7dc6ae
Add support for tables and strike-through text in the XSLT (#117)
maelle Sep 25, 2018
1512c9c
0.28.3.gfm.17
kivikakk Sep 25, 2018
4ec9b35
Be more strict on matching strikethrough (#120)
Oct 7, 2018
975a9d1
Remove /debian by suggestion in #122
kivikakk Oct 10, 2018
6e73dea
update travis-ci link
kivikakk Oct 15, 2018
a9ed0e2
fix image target
kivikakk Oct 15, 2018
f64691b
Default to safe operation (#123)
Oct 17, 2018
304bce0
0.28.3.gfm.18
kivikakk Oct 17, 2018
198669d
Prevent out-of-bound memory access. (#124)
Xadeck Oct 17, 2018
21f7420
Limit the recursion in autolink extension. (#125)
Xadeck Oct 17, 2018
bbb9dd1
Add plaintext rendering for footnotes. Otherwise, it crashes in debug…
Xadeck Oct 17, 2018
bc48e4f
0.28.3.gfm.19
kivikakk Oct 17, 2018
3c4da5b
Add GFM extensions to fuzzing harness (#127)
philipturnbull Oct 18, 2018
36e36cd
Fix a buffer overread in the CMark tables extension. (#128)
Sjlver Oct 22, 2018
d53d533
don't crash on test failure on macos
kivikakk Nov 12, 2018
44eafe0
use pledge(2) (#132)
Nov 19, 2018
42f5a52
check for OpenBSD 5.9+
kivikakk Nov 21, 2018
9bdf783
be more liberal in strikethru regression
kivikakk Nov 27, 2018
02b19e0
fix misplaced parenthesis
Nov 27, 2018
6d60bfa
add tasklist extension (#94)
Watson1978 Dec 2, 2018
b153c5a
add changelog entry
kivikakk Dec 2, 2018
301eefc
fix attribution
kivikakk Dec 2, 2018
3785191
0.28.3.gfm.20
kivikakk Jan 31, 2019
7c71bd1
Merge branch 'upstream-master'
kivikakk Feb 5, 2019
90048f9
Remove options mask from fuzzing harness (#129)
philipturnbull Feb 5, 2019
4b9523d
remove the class here
kivikakk Feb 12, 2019
9f7ca02
Adjustments to how the tasklist generation occurs (#136)
gjtorikian Mar 4, 2019
2a9996f
Define _DEFAULT_SOURCE to get various posix/gnu glibc functions decla…
keith-packard Mar 12, 2019
365dabb
Add automatic configuration of compiler to get large file support (#138)
keith-packard Mar 12, 2019
f26f75c
Merge branch 'upstream-master'
kivikakk Apr 8, 2019
b8eb2e0
Merge branch 'upstream-master'
kivikakk Apr 8, 2019
87c0139
Fix bug with determining if task is complete & adjust to spec. (#142)
NightFlyer Apr 29, 2019
4a7985e
Add XML attribute to tasklist (#145)
NightFlyer May 1, 2019
17169ab
Specify parenthesis matching in autolink extension (#148)
waldyrious May 1, 2019
78d8268
Fix valid domain ambiguity (#151)
JohelEGP May 3, 2019
10730e1
Fix extended email autolink ambiguity (#152)
JohelEGP May 3, 2019
ef13dc5
Fix table cannot be recoginsed without empty line (#154)
jinhucheung May 8, 2019
4ee4901
Fix hard line break example (#155)
JohelEGP May 8, 2019
6a90249
correct _STATIC_DEFINE flag names
kivikakk May 13, 2019
4b6ceb6
import spec changes
kivikakk May 15, 2019
4b625f5
Merge remote-tracking branch 'upstream/master'
kivikakk May 15, 2019
438f3b2
Change cmark_gfm_extensions_get_tasklist_state to cmark_gfm_extension…
NightFlyer May 31, 2019
f5c77c6
Make "set" methods public, add "set" method for tasklist (#162)
NightFlyer Jun 19, 2019
b47d804
Fixes Visual C++ 2019 compiler warnings for x64 targets (#166)
rysavyjan Jun 21, 2019
0996db0
Fix bug where tasklist extension was using union in two ways. (#169)
NightFlyer Jun 25, 2019
9a5bbf7
Revert "import spec changes"
kivikakk Jun 25, 2019
aed182e
Add link to Tcl bindings. (#171)
apnadkarni Jul 17, 2019
36c1553
Correct path to artifact (#173)
alkuzad Sep 5, 2019
8a624e5
Rebuild `ext_scanners.c` with latest `re2c`.
arthurschreiber Mar 3, 2020
db11187
[PATCH] Fix `O(n*n)` corner-case runtime in GFM's table extension.
Sjlver Mar 3, 2020
3267377
Add a test.
arthurschreiber Mar 3, 2020
ddf21bb
Restore compatibility with other changes.
arthurschreiber Mar 3, 2020
85d8952
Merge pull request from GHSA-7gc6-9qr5-hc85
philipturnbull Jun 30, 2020
88a6f87
Add Swift Package Manager Support
bitjammer Sep 23, 2020
b4e18c1
Use pre-set config.h header
bitjammer Oct 6, 2020
c773440
Track opening backtick count for inline code spans
bitjammer Oct 8, 2020
1429a7f
apply block offsets for autolink source position info
QuietMisdreavus Dec 7, 2020
57bee4e
don't let blocks get end lines before their start lines
QuietMisdreavus Dec 8, 2020
3489555
Add inline directive syntax
parkera Dec 15, 2020
f97a08c
properly set image/link sourcepos when spanning multiple lines
QuietMisdreavus Dec 17, 2020
482d443
Add ^ to special chars array
parkera Jan 17, 2021
39ae2a8
fixes existing data races
QuietMisdreavus Aug 3, 2021
d62fa12
add mutex initializer in new header
QuietMisdreavus Mar 30, 2021
437dcb0
add locks around arena ops
QuietMisdreavus Mar 30, 2021
92fb896
tweak definitions of statics in inlines.c
QuietMisdreavus Mar 30, 2021
cb88af7
add locks around extensions registry ops
QuietMisdreavus Mar 30, 2021
562c89a
make locking a compile-time setting
QuietMisdreavus Mar 30, 2021
18b7394
add latch macros and use them for registering plugins
QuietMisdreavus Mar 30, 2021
fc95a68
fix deadlock in arena
QuietMisdreavus Mar 30, 2021
0489d3c
use pthread_once instead of atomics
QuietMisdreavus Mar 31, 2021
a595ea9
Add preserve-whitespace and inline-only options
jmschonfeld Apr 14, 2021
471d20c
Allow all whitespace when preserving whitespace
jmschonfeld May 5, 2021
6df1faa
Don't emit an attribute node if it doesn't have parentheses
iCharlesHu May 18, 2021
2afe77a
update use of mutexes
QuietMisdreavus May 12, 2021
061a4d8
move global characters arrays into the parser
QuietMisdreavus May 18, 2021
fe9ba10
free special char blocks alongside the parser
QuietMisdreavus Jun 1, 2021
5d99168
don't reset the special-char blocks in parser_reset
QuietMisdreavus Jun 1, 2021
ea07fb5
add comment about freeing special-chars memory
QuietMisdreavus Jun 1, 2021
6f75d91
save special_chars/skip_chars in parser_reset
QuietMisdreavus Jun 2, 2021
7586471
don't leak my_ext in the parser_interrupt test
QuietMisdreavus Jun 2, 2021
cea3e64
Add custom attributes using ^[foo][N] syntax
iCharlesHu Jun 16, 2021
1424dac
Preserve leading newlines when CMARK_OPT_PRESERVE_WHITESPACE is set
jmschonfeld Jun 14, 2021
e9b454e
add cmark-gfm-bin target to Package.swift
QuietMisdreavus Jun 15, 2021
8a631d3
add .build/.swiftpm to gitignore
QuietMisdreavus Jun 15, 2021
4e7da18
add api_test to Package.swift
QuietMisdreavus Jun 15, 2021
f0c2fb1
fix warning in api_test
QuietMisdreavus Jun 15, 2021
4c9a330
add explicit modulemap for cmark-gfm
QuietMisdreavus Jun 15, 2021
44090a3
add intention to take upstream changes
bontoJR Jul 30, 2021
2190baa
Update README.md
franklinsch Aug 2, 2021
e21b3eb
[Bugfix] Fix the backticks bug
Kyle-Ye Nov 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Footnotes (#64)
* Add baseline test

* Some preliminary work.

* cont'd

* Add footnote reference

* Start postprocessing

* MVP: tests pass

* commonmark footnote out

* Factor out reference/footnote maps

* fix a memory leak & some asserts

* We don't assert/check snprintf elsewhere

* Remove bad linear search, extend test case

* cleanup

* man page update

* add footnotes as option

* bugfix (found in comrak first!)

* Shift static var into renderer struct
Ashe Connor authored Nov 16, 2017

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 59f723304ffc3b84f781431a320dffa2dea03fdd
42 changes: 41 additions & 1 deletion man/man3/cmark-gfm.3
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH cmark-gfm 3 "April 03, 2017" "LOCAL" "Library Functions Manual"
.TH cmark-gfm 3 "November 09, 2017" "LOCAL" "Library Functions Manual"
.SH
NAME
.PP
@@ -40,6 +40,7 @@ typedef enum {
CMARK_NODE_PARAGRAPH = CMARK_NODE_TYPE_BLOCK | 0x0008,
CMARK_NODE_HEADING = CMARK_NODE_TYPE_BLOCK | 0x0009,
CMARK_NODE_THEMATIC_BREAK = CMARK_NODE_TYPE_BLOCK | 0x000a,
CMARK_NODE_FOOTNOTE_DEFINITION = CMARK_NODE_TYPE_BLOCK | 0x000b,

/* Inline */
CMARK_NODE_TEXT = CMARK_NODE_TYPE_INLINE | 0x0001,
@@ -52,6 +53,7 @@ typedef enum {
CMARK_NODE_STRONG = CMARK_NODE_TYPE_INLINE | 0x0008,
CMARK_NODE_LINK = CMARK_NODE_TYPE_INLINE | 0x0009,
CMARK_NODE_IMAGE = CMARK_NODE_TYPE_INLINE | 0x000a,
CMARK_NODE_FOOTNOTE_REFERENCE = CMARK_NODE_TYPE_INLINE | 0x000b,
} cmark_node_type;
.RE
\f[]
@@ -780,6 +782,20 @@ responsibility to free the returned buffer.
As for \f[I]cmark_render_commonmark\f[], but specifying the allocator to
use for the resulting string.

.PP
\fIchar *\f[] \fBcmark_render_plaintext\f[](\fIcmark_node *root\f[], \fIint options\f[], \fIint width\f[])

.PP
Render a \f[I]node\f[] tree as a plain text document. It is the caller's
responsibility to free the returned buffer.

.PP
\fIchar *\f[] \fBcmark_render_plaintext_with_mem\f[](\fIcmark_node *root\f[], \fIint options\f[], \fIint width\f[], \fIcmark_mem *mem\f[])

.PP
As for \f[I]cmark_render_plaintext\f[], but specifying the allocator to
use for the resulting string.

.PP
\fIchar *\f[] \fBcmark_render_latex\f[](\fIcmark_node *root\f[], \fIint options\f[], \fIint width\f[])

@@ -917,6 +933,30 @@ dashes.
.PP
Use GitHub\-style tags for code blocks instead of .

.PP
.nf
\fC
.RS 0n
#define CMARK_OPT_LIBERAL_HTML_TAG (1 << 12)
.RE
\f[]
.fi

.PP
Be liberal in interpreting inline HTML tags.

.PP
.nf
\fC
.RS 0n
#define CMARK_OPT_FOOTNOTES (1 << 13)
.RE
\f[]
.fi

.PP
Parse footnotes.

.SS
Version information

4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -15,6 +15,8 @@ set(HEADERS
iterator.h
chunk.h
references.h
footnotes.h
map.h
utf8.h
scanners.h
inlines.h
@@ -36,6 +38,8 @@ set(LIBRARY_SOURCES
utf8.c
buffer.c
references.c
footnotes.c
map.c
render.c
man.c
xml.c
116 changes: 114 additions & 2 deletions src/blocks.c
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
#include "inlines.h"
#include "houdini.h"
#include "buffer.h"
#include "footnotes.h"

#define CODE_INDENT 4
#define TAB_STOP 4
@@ -97,7 +98,7 @@ static void cmark_parser_dispose(cmark_parser *parser) {
cmark_node_free(parser->root);

if (parser->refmap)
cmark_reference_map_free(parser->refmap);
cmark_map_free(parser->refmap);
}

static void cmark_parser_reset(cmark_parser *parser) {
@@ -408,7 +409,7 @@ void cmark_manage_extensions_special_characters(cmark_parser *parser, int add) {
// Walk through node and all children, recursively, parsing
// string content into inline content where appropriate.
static void process_inlines(cmark_parser *parser,
cmark_reference_map *refmap, int options) {
cmark_map *refmap, int options) {
cmark_iter *iter = cmark_iter_new(parser->root);
cmark_node *cur;
cmark_event_type ev_type;
@@ -429,6 +430,84 @@ static void process_inlines(cmark_parser *parser,
cmark_iter_free(iter);
}

static int sort_footnote_by_ix(const void *_a, const void *_b) {
cmark_footnote *a = *(cmark_footnote **)_a;
cmark_footnote *b = *(cmark_footnote **)_b;
return (int)a->ix - (int)b->ix;
}

static void process_footnotes(cmark_parser *parser) {
// * Collect definitions in a map.
// * Iterate the references in the document in order, assigning indices to
// definitions in the order they're seen.
// * Write out the footnotes at the bottom of the document in index order.

cmark_map *map = cmark_footnote_map_new(parser->mem);

cmark_iter *iter = cmark_iter_new(parser->root);
cmark_node *cur;
cmark_event_type ev_type;

while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
cur = cmark_iter_get_node(iter);
if (ev_type == CMARK_EVENT_EXIT && cur->type == CMARK_NODE_FOOTNOTE_DEFINITION) {
cmark_node_unlink(cur);
cmark_footnote_create(map, cur);
}
}

cmark_iter_free(iter);
iter = cmark_iter_new(parser->root);
unsigned int ix = 0;

while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
cur = cmark_iter_get_node(iter);
if (ev_type == CMARK_EVENT_EXIT && cur->type == CMARK_NODE_FOOTNOTE_REFERENCE) {
cmark_footnote *footnote = (cmark_footnote *)cmark_map_lookup(map, &cur->as.literal);
if (footnote) {
if (!footnote->ix)
footnote->ix = ++ix;

char n[32];
snprintf(n, sizeof(n), "%d", footnote->ix);
cmark_chunk_free(parser->mem, &cur->as.literal);
cmark_strbuf buf = CMARK_BUF_INIT(parser->mem);
cmark_strbuf_puts(&buf, n);

cur->as.literal = cmark_chunk_buf_detach(&buf);
} else {
cmark_node *text = (cmark_node *)parser->mem->calloc(1, sizeof(*text));
cmark_strbuf_init(parser->mem, &text->content, 0);
text->type = (uint16_t) CMARK_NODE_TEXT;

cmark_strbuf buf = CMARK_BUF_INIT(parser->mem);
cmark_strbuf_puts(&buf, "[^");
cmark_strbuf_put(&buf, cur->as.literal.data, cur->as.literal.len);
cmark_strbuf_putc(&buf, ']');

text->as.literal = cmark_chunk_buf_detach(&buf);
cmark_node_insert_after(cur, text);
cmark_node_free(cur);
}
}
}

cmark_iter_free(iter);

if (map->sorted) {
qsort(map->sorted, map->size, sizeof(cmark_map_entry *), sort_footnote_by_ix);
for (unsigned int i = 0; i < map->size; ++i) {
cmark_footnote *footnote = (cmark_footnote *)map->sorted[i];
if (!footnote->ix)
continue;
cmark_node_append_child(parser->root, footnote->node);
footnote->node = NULL;
}
}

cmark_map_free(map);
}

// Attempts to parse a list item marker (bullet or enumerated).
// On success, returns length of the marker, and populates
// data with the details. On failure, returns 0.
@@ -533,6 +612,8 @@ static cmark_node *finalize_document(cmark_parser *parser) {

finalize(parser, parser->root);
process_inlines(parser, parser->refmap, parser->options);
if (parser->options & CMARK_OPT_FOOTNOTES)
process_footnotes(parser);

return parser->root;
}
@@ -759,6 +840,18 @@ static bool parse_block_quote_prefix(cmark_parser *parser, cmark_chunk *input) {
return res;
}

static bool parse_footnote_definition_block_prefix(cmark_parser *parser, cmark_chunk *input,
cmark_node *container) {
if (parser->indent >= 4) {
S_advance_offset(parser, input, 4, true);
return true;
} else if (input->len > 0 && (input->data[0] == '\n' || (input->data[0] == '\r' && input->data[1] == '\n'))) {
return true;
}

return false;
}

static bool parse_node_item_prefix(cmark_parser *parser, cmark_chunk *input,
cmark_node *container) {
bool res = false;
@@ -913,6 +1006,10 @@ static cmark_node *check_open_blocks(cmark_parser *parser, cmark_chunk *input,
if (parser->blank)
goto done;
break;
case CMARK_NODE_FOOTNOTE_DEFINITION:
if (!parse_footnote_definition_block_prefix(parser, input, container))
goto done;
break;
default:
break;
}
@@ -1024,6 +1121,21 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
*container = add_child(parser, *container, CMARK_NODE_THEMATIC_BREAK,
parser->first_nonspace + 1);
S_advance_offset(parser, input, input->len - 1 - parser->offset, false);
} else if (!indented &&
parser->options & CMARK_OPT_FOOTNOTES &&
(matched = scan_footnote_definition(input, parser->first_nonspace))) {
cmark_chunk c = cmark_chunk_dup(input, parser->first_nonspace + 2, matched - 2);
cmark_chunk_to_cstr(parser->mem, &c);

while (c.data[c.len - 1] != ']')
--c.len;
--c.len;

S_advance_offset(parser, input, parser->first_nonspace + matched - parser->offset, false);
*container = add_child(parser, *container, CMARK_NODE_FOOTNOTE_DEFINITION, parser->first_nonspace + matched + 1);
(*container)->as.literal = c;

(*container)->internal_offset = matched;
} else if ((!indented || cont_type == CMARK_NODE_LIST) &&
(matched = parse_list_marker(
parser->mem, input, parser->first_nonspace,
4 changes: 2 additions & 2 deletions src/cmark.c
Original file line number Diff line number Diff line change
@@ -7,8 +7,8 @@
#include "cmark.h"
#include "buffer.h"

cmark_node_type CMARK_NODE_LAST_BLOCK = CMARK_NODE_THEMATIC_BREAK;
cmark_node_type CMARK_NODE_LAST_INLINE = CMARK_NODE_IMAGE;
cmark_node_type CMARK_NODE_LAST_BLOCK = CMARK_NODE_FOOTNOTE_DEFINITION;
cmark_node_type CMARK_NODE_LAST_INLINE = CMARK_NODE_FOOTNOTE_REFERENCE;

int cmark_version() { return CMARK_VERSION; }

6 changes: 6 additions & 0 deletions src/cmark.h
Original file line number Diff line number Diff line change
@@ -52,6 +52,7 @@ typedef enum {
CMARK_NODE_PARAGRAPH = CMARK_NODE_TYPE_BLOCK | 0x0008,
CMARK_NODE_HEADING = CMARK_NODE_TYPE_BLOCK | 0x0009,
CMARK_NODE_THEMATIC_BREAK = CMARK_NODE_TYPE_BLOCK | 0x000a,
CMARK_NODE_FOOTNOTE_DEFINITION = CMARK_NODE_TYPE_BLOCK | 0x000b,

/* Inline */
CMARK_NODE_TEXT = CMARK_NODE_TYPE_INLINE | 0x0001,
@@ -64,6 +65,7 @@ typedef enum {
CMARK_NODE_STRONG = CMARK_NODE_TYPE_INLINE | 0x0008,
CMARK_NODE_LINK = CMARK_NODE_TYPE_INLINE | 0x0009,
CMARK_NODE_IMAGE = CMARK_NODE_TYPE_INLINE | 0x000a,
CMARK_NODE_FOOTNOTE_REFERENCE = CMARK_NODE_TYPE_INLINE | 0x000b,
} cmark_node_type;

extern cmark_node_type CMARK_NODE_LAST_BLOCK;
@@ -718,6 +720,10 @@ char *cmark_render_latex_with_mem(cmark_node *root, int options, int width, cmar
*/
#define CMARK_OPT_LIBERAL_HTML_TAG (1 << 12)

/** Parse footnotes.
*/
#define CMARK_OPT_FOOTNOTES (1 << 13)

/**
* ## Version information
*/
23 changes: 23 additions & 0 deletions src/commonmark.c
Original file line number Diff line number Diff line change
@@ -463,6 +463,29 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
}
break;

case CMARK_NODE_FOOTNOTE_REFERENCE:
if (entering) {
LIT("[^");
OUT(cmark_chunk_to_cstr(renderer->mem, &node->as.literal), false, LITERAL);
LIT("]");
}
break;

case CMARK_NODE_FOOTNOTE_DEFINITION:
if (entering) {
renderer->footnote_ix += 1;
LIT("[^");
char n[32];
snprintf(n, sizeof(n), "%d", renderer->footnote_ix);
OUT(n, false, LITERAL);
LIT("]:\n");

cmark_strbuf_puts(renderer->prefix, " ");
} else {
cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 4);
}
break;

default:
assert(false);
break;
40 changes: 40 additions & 0 deletions src/footnotes.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "cmark.h"
#include "parser.h"
#include "footnotes.h"
#include "inlines.h"
#include "chunk.h"

static void footnote_free(cmark_map *map, cmark_map_entry *_ref) {
cmark_footnote *ref = (cmark_footnote *)_ref;
cmark_mem *mem = map->mem;
if (ref != NULL) {
mem->free(ref->entry.label);
if (ref->node)
cmark_node_free(ref->node);
mem->free(ref);
}
}

void cmark_footnote_create(cmark_map *map, cmark_node *node) {
cmark_footnote *ref;
unsigned char *reflabel = normalize_map_label(map->mem, &node->as.literal);

/* empty footnote name, or composed from only whitespace */
if (reflabel == NULL)
return;

assert(map->sorted == NULL);

ref = (cmark_footnote *)map->mem->calloc(1, sizeof(*ref));
ref->entry.label = reflabel;
ref->node = node;
ref->entry.age = map->size;
ref->entry.next = map->refs;

map->refs = (cmark_map_entry *)ref;
map->size++;
}

cmark_map *cmark_footnote_map_new(cmark_mem *mem) {
return cmark_map_new(mem, footnote_free);
}
25 changes: 25 additions & 0 deletions src/footnotes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef CMARK_FOOTNOTES_H
#define CMARK_FOOTNOTES_H

#include "map.h"

#ifdef __cplusplus
extern "C" {
#endif

struct cmark_footnote {
cmark_map_entry entry;
cmark_node *node;
unsigned int ix;
};

typedef struct cmark_footnote cmark_footnote;

void cmark_footnote_create(cmark_map *map, cmark_node *node);
cmark_map *cmark_footnote_map_new(cmark_mem *mem);

#ifdef __cplusplus
}
#endif

#endif
Loading