rmultimarkdown 4.7.1.1 → 6.2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +2 -2
- data/README.md +7 -9
- data/Rakefile +33 -18
- data/ext/Makefile +261 -0
- data/ext/extconf.rb +23 -3
- data/ext/mmd/aho-corasick.c +596 -0
- data/ext/mmd/aho-corasick.h +120 -0
- data/ext/mmd/beamer.c +344 -0
- data/ext/mmd/beamer.h +72 -0
- data/ext/mmd/char.c +156 -0
- data/ext/mmd/char.h +111 -0
- data/ext/mmd/char_lookup.c +212 -0
- data/ext/mmd/critic_markup.c +330 -0
- data/ext/mmd/critic_markup.h +94 -0
- data/ext/mmd/d_string.c +402 -0
- data/ext/mmd/epub.c +563 -0
- data/ext/mmd/epub.h +69 -0
- data/ext/mmd/fodt.c +2288 -0
- data/ext/mmd/fodt.h +81 -0
- data/ext/mmd/html.c +2460 -0
- data/ext/mmd/html.h +81 -0
- data/ext/mmd/i18n.h +170 -0
- data/ext/mmd/include/d_string.h +182 -0
- data/ext/mmd/include/libMultiMarkdown.h +548 -0
- data/ext/mmd/include/token.h +233 -0
- data/ext/mmd/latex.c +2435 -0
- data/ext/mmd/latex.h +83 -0
- data/ext/mmd/lexer.c +3001 -0
- data/ext/mmd/lexer.h +75 -0
- data/ext/mmd/memoir.c +138 -0
- data/ext/mmd/memoir.h +67 -0
- data/ext/mmd/miniz.c +7557 -0
- data/ext/mmd/miniz.h +1328 -0
- data/ext/mmd/mmd.c +2798 -0
- data/ext/mmd/mmd.h +120 -0
- data/ext/mmd/object_pool.c +141 -0
- data/ext/mmd/object_pool.h +101 -0
- data/ext/mmd/opendocument-content.c +2071 -0
- data/ext/mmd/opendocument-content.h +135 -0
- data/ext/mmd/opendocument.c +981 -0
- data/ext/mmd/opendocument.h +118 -0
- data/ext/mmd/parser.c +1760 -0
- data/ext/mmd/parser.h +39 -0
- data/{MultiMarkdown-4 → ext/mmd}/rng.c +90 -49
- data/ext/mmd/scanners.c +77512 -0
- data/ext/mmd/scanners.h +101 -0
- data/ext/mmd/stack.c +142 -0
- data/ext/mmd/stack.h +113 -0
- data/ext/mmd/textbundle.c +455 -0
- data/ext/mmd/textbundle.h +115 -0
- data/ext/mmd/token.c +773 -0
- data/ext/mmd/token_pairs.c +263 -0
- data/ext/mmd/token_pairs.h +123 -0
- data/ext/mmd/transclude.c +549 -0
- data/ext/mmd/transclude.h +87 -0
- data/ext/mmd/uthash.h +1074 -0
- data/ext/mmd/uuid.c +154 -0
- data/ext/mmd/uuid.h +77 -0
- data/ext/mmd/version.h +111 -0
- data/ext/mmd/writer.c +2652 -0
- data/ext/mmd/writer.h +260 -0
- data/ext/mmd/zip.c +210 -0
- data/ext/mmd/zip.h +120 -0
- data/ext/{multi_markdown.c → ruby_multi_markdown.c} +87 -18
- data/lib/multi_markdown.bundle +0 -0
- data/lib/multi_markdown.rb +5 -8
- data/lib/multi_markdown/version.rb +1 -1
- data/rmultimarkdown.gemspec +2 -2
- data/test/{extensions_test.rb.rb → extensions_test.rb} +10 -54
- data/test/multi_markdown_test.rb +13 -0
- metadata +67 -47
- data/MultiMarkdown-4/GLibFacade.c +0 -310
- data/MultiMarkdown-4/GLibFacade.h +0 -100
- data/MultiMarkdown-4/beamer.c +0 -182
- data/MultiMarkdown-4/beamer.h +0 -11
- data/MultiMarkdown-4/critic.c +0 -111
- data/MultiMarkdown-4/critic.h +0 -15
- data/MultiMarkdown-4/glib.h +0 -11
- data/MultiMarkdown-4/html.c +0 -1117
- data/MultiMarkdown-4/html.h +0 -14
- data/MultiMarkdown-4/latex.c +0 -1217
- data/MultiMarkdown-4/latex.h +0 -16
- data/MultiMarkdown-4/libMultiMarkdown.h +0 -177
- data/MultiMarkdown-4/lyx.c +0 -2265
- data/MultiMarkdown-4/lyx.h +0 -37
- data/MultiMarkdown-4/lyxbeamer.c +0 -265
- data/MultiMarkdown-4/lyxbeamer.h +0 -11
- data/MultiMarkdown-4/memoir.c +0 -80
- data/MultiMarkdown-4/memoir.h +0 -10
- data/MultiMarkdown-4/multimarkdown.c +0 -518
- data/MultiMarkdown-4/odf.c +0 -1222
- data/MultiMarkdown-4/odf.h +0 -18
- data/MultiMarkdown-4/opml.c +0 -189
- data/MultiMarkdown-4/opml.h +0 -15
- data/MultiMarkdown-4/parse_utilities.c +0 -884
- data/MultiMarkdown-4/parser.c +0 -16656
- data/MultiMarkdown-4/parser.h +0 -188
- data/MultiMarkdown-4/rtf.c +0 -665
- data/MultiMarkdown-4/rtf.h +0 -17
- data/MultiMarkdown-4/strtok.c +0 -56
- data/MultiMarkdown-4/strtok.h +0 -9
- data/MultiMarkdown-4/text.c +0 -53
- data/MultiMarkdown-4/text.h +0 -11
- data/MultiMarkdown-4/toc.c +0 -142
- data/MultiMarkdown-4/toc.h +0 -15
- data/MultiMarkdown-4/transclude.c +0 -307
- data/MultiMarkdown-4/transclude.h +0 -28
- data/MultiMarkdown-4/writer.c +0 -731
- data/MultiMarkdown-4/writer.h +0 -38
@@ -0,0 +1,330 @@
|
|
1
|
+
/**
|
2
|
+
|
3
|
+
MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
|
4
|
+
|
5
|
+
@file critic_markup.c
|
6
|
+
|
7
|
+
@brief
|
8
|
+
|
9
|
+
|
10
|
+
@author Fletcher T. Penney
|
11
|
+
@bug
|
12
|
+
|
13
|
+
**/
|
14
|
+
|
15
|
+
/*
|
16
|
+
|
17
|
+
Copyright © 2016 - 2017 Fletcher T. Penney.
|
18
|
+
|
19
|
+
|
20
|
+
The `MultiMarkdown 6` project is released under the MIT License..
|
21
|
+
|
22
|
+
GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
|
23
|
+
|
24
|
+
https://github.com/fletcher/MultiMarkdown-4/
|
25
|
+
|
26
|
+
MMD 4 is released under both the MIT License and GPL.
|
27
|
+
|
28
|
+
|
29
|
+
CuTest is released under the zlib/libpng license. See CuTest.c for the
|
30
|
+
text of the license.
|
31
|
+
|
32
|
+
|
33
|
+
## The MIT License ##
|
34
|
+
|
35
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
36
|
+
a copy of this software and associated documentation files (the
|
37
|
+
"Software"), to deal in the Software without restriction, including
|
38
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
39
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
40
|
+
permit persons to whom the Software is furnished to do so, subject to
|
41
|
+
the following conditions:
|
42
|
+
|
43
|
+
The above copyright notice and this permission notice shall be
|
44
|
+
included in all copies or substantial portions of the Software.
|
45
|
+
|
46
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
47
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
48
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
49
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
50
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
51
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
52
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
53
|
+
|
54
|
+
|
55
|
+
*/
|
56
|
+
|
57
|
+
#include <stdbool.h>
|
58
|
+
#include <string.h>
|
59
|
+
|
60
|
+
|
61
|
+
#include "aho-corasick.h"
|
62
|
+
#include "critic_markup.h"
|
63
|
+
#include "stack.h"
|
64
|
+
#include "token_pairs.h"
|
65
|
+
|
66
|
+
|
67
|
+
token * mmd_critic_tokenize_string(const char * source, size_t start, size_t len) {
|
68
|
+
trie * ac = trie_new(0);
|
69
|
+
|
70
|
+
trie_insert(ac, "{++", CM_ADD_OPEN);
|
71
|
+
trie_insert(ac, "++}", CM_ADD_CLOSE);
|
72
|
+
|
73
|
+
trie_insert(ac, "{--", CM_DEL_OPEN);
|
74
|
+
trie_insert(ac, "--}", CM_DEL_CLOSE);
|
75
|
+
|
76
|
+
trie_insert(ac, "{~~", CM_SUB_OPEN);
|
77
|
+
trie_insert(ac, "~>", CM_SUB_DIV);
|
78
|
+
trie_insert(ac, "~~}", CM_SUB_CLOSE);
|
79
|
+
|
80
|
+
trie_insert(ac, "{==", CM_HI_OPEN);
|
81
|
+
trie_insert(ac, "==}", CM_HI_CLOSE);
|
82
|
+
|
83
|
+
trie_insert(ac, "{>>", CM_COM_OPEN);
|
84
|
+
trie_insert(ac, "<<}", CM_COM_CLOSE);
|
85
|
+
|
86
|
+
trie_insert(ac, "\\{", CM_PLAIN_TEXT);
|
87
|
+
trie_insert(ac, "\\}", CM_PLAIN_TEXT);
|
88
|
+
trie_insert(ac, "\\{", CM_PLAIN_TEXT);
|
89
|
+
trie_insert(ac, "\\+", CM_PLAIN_TEXT);
|
90
|
+
trie_insert(ac, "\\-", CM_PLAIN_TEXT);
|
91
|
+
trie_insert(ac, "\\~", CM_PLAIN_TEXT);
|
92
|
+
trie_insert(ac, "\\>", CM_PLAIN_TEXT);
|
93
|
+
trie_insert(ac, "\\=", CM_PLAIN_TEXT);
|
94
|
+
|
95
|
+
|
96
|
+
ac_trie_prepare(ac);
|
97
|
+
|
98
|
+
match * m = ac_trie_leftmost_longest_search(ac, source, start, len);
|
99
|
+
|
100
|
+
token * root = NULL;
|
101
|
+
|
102
|
+
if (m) {
|
103
|
+
match * walker = m->next;
|
104
|
+
|
105
|
+
root = token_new(0, 0, 0);
|
106
|
+
|
107
|
+
size_t last = start;
|
108
|
+
|
109
|
+
while (walker) {
|
110
|
+
if (walker->start > last) {
|
111
|
+
token_append_child(root, token_new(CM_PLAIN_TEXT, last, walker->start - last));
|
112
|
+
last = walker->start;
|
113
|
+
}
|
114
|
+
|
115
|
+
if (walker->start == last) {
|
116
|
+
token_append_child(root, token_new(walker->match_type, walker->start, walker->len));
|
117
|
+
last = walker->start + walker->len;
|
118
|
+
}
|
119
|
+
|
120
|
+
walker = walker->next;
|
121
|
+
}
|
122
|
+
|
123
|
+
if (last < start + len) {
|
124
|
+
token_append_child(root, token_new(CM_PLAIN_TEXT, last, start + len));
|
125
|
+
}
|
126
|
+
|
127
|
+
match_free(m);
|
128
|
+
trie_free(ac);
|
129
|
+
}
|
130
|
+
|
131
|
+
return root;
|
132
|
+
}
|
133
|
+
|
134
|
+
|
135
|
+
|
136
|
+
token * critic_parse_substring(const char * source, size_t start, size_t len) {
|
137
|
+
token * chain = mmd_critic_tokenize_string(source, start, len);
|
138
|
+
|
139
|
+
if (chain) {
|
140
|
+
token_pair_engine * e = token_pair_engine_new();
|
141
|
+
|
142
|
+
token_pair_engine_add_pairing(e, CM_ADD_OPEN, CM_ADD_CLOSE, CM_ADD_PAIR, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
|
143
|
+
token_pair_engine_add_pairing(e, CM_DEL_OPEN, CM_DEL_CLOSE, CM_DEL_PAIR, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
|
144
|
+
token_pair_engine_add_pairing(e, CM_SUB_OPEN, CM_SUB_CLOSE, CM_SUB_PAIR, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
|
145
|
+
token_pair_engine_add_pairing(e, CM_HI_OPEN, CM_HI_CLOSE, CM_HI_PAIR, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
|
146
|
+
token_pair_engine_add_pairing(e, CM_COM_OPEN, CM_COM_CLOSE, CM_COM_PAIR, PAIRING_ALLOW_EMPTY | PAIRING_PRUNE_MATCH);
|
147
|
+
|
148
|
+
stack * s = stack_new(0);
|
149
|
+
|
150
|
+
token_pairs_match_pairs_inside_token(chain, e, s, 0);
|
151
|
+
|
152
|
+
stack_free(s);
|
153
|
+
token_pair_engine_free(e);
|
154
|
+
}
|
155
|
+
|
156
|
+
return chain;
|
157
|
+
}
|
158
|
+
|
159
|
+
|
160
|
+
void accept_token_tree(DString * d, token * t);
|
161
|
+
void accept_token(DString * d, token * t);
|
162
|
+
|
163
|
+
|
164
|
+
void accept_token_tree_sub(DString * d, token * t) {
|
165
|
+
while (t) {
|
166
|
+
if (t->type == CM_SUB_DIV) {
|
167
|
+
while (t) {
|
168
|
+
d_string_erase(d, t->start, t->len);
|
169
|
+
t = t->prev;
|
170
|
+
}
|
171
|
+
|
172
|
+
return;
|
173
|
+
}
|
174
|
+
|
175
|
+
accept_token(d, t);
|
176
|
+
|
177
|
+
t = t->prev;
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
181
|
+
|
182
|
+
void accept_token(DString * d, token * t) {
|
183
|
+
switch (t->type) {
|
184
|
+
case CM_SUB_CLOSE:
|
185
|
+
if (t->mate) {
|
186
|
+
d_string_erase(d, t->start, t->len);
|
187
|
+
}
|
188
|
+
|
189
|
+
break;
|
190
|
+
|
191
|
+
case CM_SUB_OPEN:
|
192
|
+
case CM_ADD_OPEN:
|
193
|
+
case CM_ADD_CLOSE:
|
194
|
+
if (!t->mate) {
|
195
|
+
break;
|
196
|
+
}
|
197
|
+
|
198
|
+
case CM_SUB_DIV:
|
199
|
+
case CM_DEL_PAIR:
|
200
|
+
case CM_COM_PAIR:
|
201
|
+
// Erase these
|
202
|
+
d_string_erase(d, t->start, t->len);
|
203
|
+
break;
|
204
|
+
|
205
|
+
case CM_SUB_PAIR:
|
206
|
+
|
207
|
+
// Erase old version and markers
|
208
|
+
if (t->child) {
|
209
|
+
accept_token_tree_sub(d, t->child->mate);
|
210
|
+
}
|
211
|
+
|
212
|
+
break;
|
213
|
+
|
214
|
+
case CM_ADD_PAIR:
|
215
|
+
case CM_HI_PAIR:
|
216
|
+
|
217
|
+
// Check children
|
218
|
+
if (t->child) {
|
219
|
+
accept_token_tree(d, t->child->mate);
|
220
|
+
}
|
221
|
+
|
222
|
+
break;
|
223
|
+
}
|
224
|
+
}
|
225
|
+
|
226
|
+
|
227
|
+
void accept_token_tree(DString * d, token * t) {
|
228
|
+
while (t) {
|
229
|
+
accept_token(d, t);
|
230
|
+
|
231
|
+
// Iterate backwards so offsets are right
|
232
|
+
t = t->prev;
|
233
|
+
}
|
234
|
+
}
|
235
|
+
|
236
|
+
void mmd_critic_markup_accept(DString * d) {
|
237
|
+
token * t = critic_parse_substring(d->str, 0, d->currentStringLength);
|
238
|
+
|
239
|
+
if (t && t->child) {
|
240
|
+
accept_token_tree(d, t->child->tail);
|
241
|
+
}
|
242
|
+
|
243
|
+
token_free(t);
|
244
|
+
}
|
245
|
+
|
246
|
+
|
247
|
+
void reject_token_tree(DString * d, token * t);
|
248
|
+
void reject_token(DString * d, token * t);
|
249
|
+
|
250
|
+
|
251
|
+
void reject_token_tree_sub(DString * d, token * t) {
|
252
|
+
while (t && t->type != CM_SUB_DIV) {
|
253
|
+
d_string_erase(d, t->start, t->len);
|
254
|
+
t = t->prev;
|
255
|
+
}
|
256
|
+
|
257
|
+
while (t) {
|
258
|
+
|
259
|
+
reject_token(d, t);
|
260
|
+
|
261
|
+
t = t->prev;
|
262
|
+
}
|
263
|
+
}
|
264
|
+
|
265
|
+
|
266
|
+
void reject_token(DString * d, token * t) {
|
267
|
+
switch (t->type) {
|
268
|
+
case CM_SUB_CLOSE:
|
269
|
+
if (t->mate) {
|
270
|
+
d_string_erase(d, t->start, t->len);
|
271
|
+
}
|
272
|
+
|
273
|
+
break;
|
274
|
+
|
275
|
+
case CM_SUB_OPEN:
|
276
|
+
case CM_DEL_OPEN:
|
277
|
+
case CM_DEL_CLOSE:
|
278
|
+
if (!t->mate) {
|
279
|
+
break;
|
280
|
+
}
|
281
|
+
|
282
|
+
case CM_SUB_DIV:
|
283
|
+
case CM_ADD_PAIR:
|
284
|
+
case CM_COM_PAIR:
|
285
|
+
// Erase these
|
286
|
+
d_string_erase(d, t->start, t->len);
|
287
|
+
break;
|
288
|
+
|
289
|
+
case CM_SUB_PAIR:
|
290
|
+
|
291
|
+
// Erase new version and markers
|
292
|
+
if (t->child) {
|
293
|
+
reject_token_tree_sub(d, t->child->mate);
|
294
|
+
}
|
295
|
+
|
296
|
+
break;
|
297
|
+
|
298
|
+
case CM_DEL_PAIR:
|
299
|
+
case CM_HI_PAIR:
|
300
|
+
|
301
|
+
// Check children
|
302
|
+
if (t->child) {
|
303
|
+
reject_token_tree(d, t->child->mate);
|
304
|
+
}
|
305
|
+
|
306
|
+
break;
|
307
|
+
}
|
308
|
+
}
|
309
|
+
|
310
|
+
|
311
|
+
void reject_token_tree(DString * d, token * t) {
|
312
|
+
while (t) {
|
313
|
+
reject_token(d, t);
|
314
|
+
|
315
|
+
// Iterate backwards so offsets are right
|
316
|
+
t = t->prev;
|
317
|
+
}
|
318
|
+
}
|
319
|
+
|
320
|
+
void mmd_critic_markup_reject(DString * d) {
|
321
|
+
token * t = critic_parse_substring(d->str, 0, d->currentStringLength);
|
322
|
+
|
323
|
+
if (t && t->child) {
|
324
|
+
reject_token_tree(d, t->child->tail);
|
325
|
+
}
|
326
|
+
|
327
|
+
token_free(t);
|
328
|
+
|
329
|
+
}
|
330
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
/**
|
2
|
+
|
3
|
+
MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
|
4
|
+
|
5
|
+
@file critic_markup.h
|
6
|
+
|
7
|
+
@brief
|
8
|
+
|
9
|
+
|
10
|
+
@author Fletcher T. Penney
|
11
|
+
@bug
|
12
|
+
|
13
|
+
**/
|
14
|
+
|
15
|
+
/*
|
16
|
+
|
17
|
+
Copyright © 2016 - 2017 Fletcher T. Penney.
|
18
|
+
|
19
|
+
|
20
|
+
The `MultiMarkdown 6` project is released under the MIT License..
|
21
|
+
|
22
|
+
GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
|
23
|
+
|
24
|
+
https://github.com/fletcher/MultiMarkdown-4/
|
25
|
+
|
26
|
+
MMD 4 is released under both the MIT License and GPL.
|
27
|
+
|
28
|
+
|
29
|
+
CuTest is released under the zlib/libpng license. See CuTest.c for the
|
30
|
+
text of the license.
|
31
|
+
|
32
|
+
|
33
|
+
## The MIT License ##
|
34
|
+
|
35
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
36
|
+
a copy of this software and associated documentation files (the
|
37
|
+
"Software"), to deal in the Software without restriction, including
|
38
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
39
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
40
|
+
permit persons to whom the Software is furnished to do so, subject to
|
41
|
+
the following conditions:
|
42
|
+
|
43
|
+
The above copyright notice and this permission notice shall be
|
44
|
+
included in all copies or substantial portions of the Software.
|
45
|
+
|
46
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
47
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
48
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
49
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
50
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
51
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
52
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
53
|
+
|
54
|
+
|
55
|
+
*/
|
56
|
+
|
57
|
+
|
58
|
+
#ifndef CRITIC_MARKUP_MULTIMARKDOWN_H
|
59
|
+
#define CRITIC_MARKUP_MULTIMARKDOWN_H
|
60
|
+
|
61
|
+
#include "d_string.h"
|
62
|
+
|
63
|
+
enum cm_types {
|
64
|
+
CM_ADD_OPEN = 1, // Can't use type 0
|
65
|
+
CM_ADD_CLOSE,
|
66
|
+
|
67
|
+
CM_DEL_OPEN,
|
68
|
+
CM_DEL_CLOSE,
|
69
|
+
|
70
|
+
CM_SUB_OPEN,
|
71
|
+
CM_SUB_DIV,
|
72
|
+
CM_SUB_CLOSE,
|
73
|
+
|
74
|
+
CM_HI_OPEN,
|
75
|
+
CM_HI_CLOSE,
|
76
|
+
|
77
|
+
CM_COM_OPEN,
|
78
|
+
CM_COM_CLOSE,
|
79
|
+
|
80
|
+
CM_ADD_PAIR,
|
81
|
+
CM_DEL_PAIR,
|
82
|
+
CM_SUB_PAIR,
|
83
|
+
CM_HI_PAIR,
|
84
|
+
CM_COM_PAIR,
|
85
|
+
|
86
|
+
CM_PLAIN_TEXT
|
87
|
+
};
|
88
|
+
|
89
|
+
|
90
|
+
void mmd_critic_markup_accept(DString * d);
|
91
|
+
|
92
|
+
void mmd_critic_markup_reject(DString * d);
|
93
|
+
|
94
|
+
#endif
|
data/ext/mmd/d_string.c
ADDED
@@ -0,0 +1,402 @@
|
|
1
|
+
/**
|
2
|
+
|
3
|
+
MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
|
4
|
+
|
5
|
+
@file d_string.c
|
6
|
+
|
7
|
+
@brief Dynamic string -- refactoring of old GLibFacade. Provides a string
|
8
|
+
"object" that can grow to accomodate any size content that is appended.
|
9
|
+
|
10
|
+
|
11
|
+
@author Daniel Jalkut, modified by Fletcher T. Penney and Dan Lowe
|
12
|
+
|
13
|
+
@bug
|
14
|
+
|
15
|
+
**/
|
16
|
+
|
17
|
+
/*
|
18
|
+
|
19
|
+
Copyright © 2011 Daniel Jalkut.
|
20
|
+
Modifications by Fletcher T. Penney, Copyright © 2011-2017 Fletcher T. Penney.
|
21
|
+
Modifications by Dan Lowe, Copyright © 2011 Dan Lowe.
|
22
|
+
|
23
|
+
|
24
|
+
The `MultiMarkdown 6` project is released under the MIT License..
|
25
|
+
|
26
|
+
GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
|
27
|
+
|
28
|
+
https://github.com/fletcher/MultiMarkdown-4/
|
29
|
+
|
30
|
+
MMD 4 is released under both the MIT License and GPL.
|
31
|
+
|
32
|
+
|
33
|
+
CuTest is released under the zlib/libpng license. See CuTest.c for the text
|
34
|
+
of the license.
|
35
|
+
|
36
|
+
|
37
|
+
## The MIT License ##
|
38
|
+
|
39
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
40
|
+
of this software and associated documentation files (the "Software"), to deal
|
41
|
+
in the Software without restriction, including without limitation the rights
|
42
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
43
|
+
copies of the Software, and to permit persons to whom the Software is
|
44
|
+
furnished to do so, subject to the following conditions:
|
45
|
+
|
46
|
+
The above copyright notice and this permission notice shall be included in
|
47
|
+
all copies or substantial portions of the Software.
|
48
|
+
|
49
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
50
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
51
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
52
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
53
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
54
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
55
|
+
THE SOFTWARE.
|
56
|
+
|
57
|
+
*/
|
58
|
+
|
59
|
+
|
60
|
+
#include <stdio.h>
|
61
|
+
#include <stdlib.h>
|
62
|
+
#include <string.h>
|
63
|
+
#include <stdarg.h>
|
64
|
+
|
65
|
+
#include "d_string.h"
|
66
|
+
|
67
|
+
|
68
|
+
/*
|
69
|
+
* The following section came from:
|
70
|
+
*
|
71
|
+
* http://lists-archives.org/mingw-users/12649-asprintf-missing-vsnprintf-
|
72
|
+
* behaving-differently-and-_vsncprintf-undefined.html
|
73
|
+
*
|
74
|
+
* and
|
75
|
+
*
|
76
|
+
* http://groups.google.com/group/jansson-users/browse_thread/thread/
|
77
|
+
* 76a88d63d9519978/041a7d0570de2d48?lnk=raot
|
78
|
+
*/
|
79
|
+
|
80
|
+
// Some operating systems do not supply vasprintf() -- standardize on this
|
81
|
+
// replacement from:
|
82
|
+
// https://github.com/esp8266/Arduino/issues/1954
|
83
|
+
int vasprintf(char** strp, const char* fmt, va_list ap) {
|
84
|
+
va_list ap2;
|
85
|
+
va_copy(ap2, ap);
|
86
|
+
|
87
|
+
#if (defined(_WIN32) || defined(__WIN32__))
|
88
|
+
char *tmp = NULL;
|
89
|
+
int size = vsnprintf(tmp, 0, fmt, ap2);
|
90
|
+
#else
|
91
|
+
char tmp[1];
|
92
|
+
int size = vsnprintf(tmp, 1, fmt, ap2);
|
93
|
+
#endif
|
94
|
+
|
95
|
+
if (size <= 0) {
|
96
|
+
return size;
|
97
|
+
}
|
98
|
+
|
99
|
+
va_end(ap2);
|
100
|
+
size += 1;
|
101
|
+
*strp = (char*)malloc(size * sizeof(char));
|
102
|
+
return vsnprintf(*strp, size, fmt, ap);
|
103
|
+
}
|
104
|
+
|
105
|
+
|
106
|
+
/* DString */
|
107
|
+
|
108
|
+
#define kStringBufferStartingSize 1024 //!< Default size of string buffer capacity
|
109
|
+
#define kStringBufferGrowthMultiplier 2 //!< Multiply capacity by this factor when more space is needed
|
110
|
+
#define kStringBufferMaxIncrement 1024 * 1024 * 100 //!< Maximum growth increment when resizing (to limit exponential growth)
|
111
|
+
|
112
|
+
|
113
|
+
/// Create a new dynamic string
|
114
|
+
DString* d_string_new(const char * startingString) {
|
115
|
+
DString* newString = malloc(sizeof(DString));
|
116
|
+
|
117
|
+
if (!newString) {
|
118
|
+
return NULL;
|
119
|
+
}
|
120
|
+
|
121
|
+
if (startingString == NULL) {
|
122
|
+
startingString = "";
|
123
|
+
}
|
124
|
+
|
125
|
+
size_t startingBufferSize = kStringBufferStartingSize;
|
126
|
+
size_t startingStringSize = strlen(startingString);
|
127
|
+
|
128
|
+
while (startingBufferSize < (startingStringSize + 1)) {
|
129
|
+
startingBufferSize *= kStringBufferGrowthMultiplier;
|
130
|
+
}
|
131
|
+
|
132
|
+
newString->str = malloc(startingBufferSize);
|
133
|
+
|
134
|
+
if (!newString->str) {
|
135
|
+
free(newString);
|
136
|
+
return NULL;
|
137
|
+
}
|
138
|
+
|
139
|
+
newString->currentStringBufferSize = startingBufferSize;
|
140
|
+
strncpy(newString->str, startingString, startingStringSize);
|
141
|
+
newString->str[startingStringSize] = '\0';
|
142
|
+
newString->currentStringLength = startingStringSize;
|
143
|
+
|
144
|
+
return newString;
|
145
|
+
}
|
146
|
+
|
147
|
+
|
148
|
+
/// Free dynamic string
|
149
|
+
char* d_string_free(DString * ripString, bool freeCharacterData) {
|
150
|
+
if (ripString == NULL) {
|
151
|
+
return NULL;
|
152
|
+
}
|
153
|
+
|
154
|
+
char* returnedString = ripString->str;
|
155
|
+
|
156
|
+
if (freeCharacterData) {
|
157
|
+
if (ripString->str != NULL) {
|
158
|
+
free(ripString->str);
|
159
|
+
}
|
160
|
+
|
161
|
+
returnedString = NULL;
|
162
|
+
}
|
163
|
+
|
164
|
+
free(ripString);
|
165
|
+
|
166
|
+
return returnedString;
|
167
|
+
}
|
168
|
+
|
169
|
+
|
170
|
+
/// Ensure that dynamic string has specified capacity
|
171
|
+
static void ensureStringBufferCanHold(DString * baseString, size_t newStringSize) {
|
172
|
+
size_t newBufferSizeNeeded = newStringSize + 1;
|
173
|
+
|
174
|
+
if (newBufferSizeNeeded > baseString->currentStringBufferSize) {
|
175
|
+
size_t newBufferSize = baseString->currentStringBufferSize;
|
176
|
+
|
177
|
+
while (newBufferSizeNeeded > newBufferSize) {
|
178
|
+
if (newBufferSize > kStringBufferMaxIncrement) {
|
179
|
+
newBufferSize += kStringBufferMaxIncrement;
|
180
|
+
} else {
|
181
|
+
newBufferSize *= kStringBufferGrowthMultiplier;
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
char *temp;
|
186
|
+
temp = realloc(baseString->str, newBufferSize);
|
187
|
+
|
188
|
+
if (temp == NULL) {
|
189
|
+
/* realloc failed */
|
190
|
+
fprintf(stderr, "Error reallocating memory for d_string. Current buffer size %lu.\n", baseString->currentStringBufferSize);
|
191
|
+
|
192
|
+
exit(1);
|
193
|
+
}
|
194
|
+
|
195
|
+
baseString->str = temp;
|
196
|
+
baseString->currentStringBufferSize = newBufferSize;
|
197
|
+
}
|
198
|
+
}
|
199
|
+
|
200
|
+
|
201
|
+
/// Append null-terminated string to end of dynamic string
|
202
|
+
void d_string_append(DString * baseString, const char * appendedString) {
|
203
|
+
size_t appendedStringLength = strlen(appendedString);
|
204
|
+
|
205
|
+
if ((appendedString != NULL) && (appendedStringLength > 0)) {
|
206
|
+
size_t newStringLength = baseString->currentStringLength + appendedStringLength;
|
207
|
+
ensureStringBufferCanHold(baseString, newStringLength);
|
208
|
+
|
209
|
+
/* We already know where the current string ends, so pass that as the starting address for strncat */
|
210
|
+
strncat(baseString->str + baseString->currentStringLength, appendedString, appendedStringLength);
|
211
|
+
baseString->currentStringLength = newStringLength;
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
|
216
|
+
/// Append single character to end of dynamic string
|
217
|
+
void d_string_append_c(DString * baseString, char appendedCharacter) {
|
218
|
+
size_t newSizeNeeded = baseString->currentStringLength + 1;
|
219
|
+
ensureStringBufferCanHold(baseString, newSizeNeeded);
|
220
|
+
|
221
|
+
baseString->str[baseString->currentStringLength] = appendedCharacter;
|
222
|
+
baseString->currentStringLength++;
|
223
|
+
baseString->str[baseString->currentStringLength] = '\0';
|
224
|
+
}
|
225
|
+
|
226
|
+
|
227
|
+
/// Append array of characters to end of dynamic string
|
228
|
+
void d_string_append_c_array(DString * baseString, const char * appendedChars, size_t bytes) {
|
229
|
+
size_t newSizeNeeded = baseString->currentStringLength + bytes;
|
230
|
+
ensureStringBufferCanHold(baseString, newSizeNeeded);
|
231
|
+
|
232
|
+
memcpy(baseString->str + baseString->currentStringLength, appendedChars, bytes);
|
233
|
+
|
234
|
+
baseString->currentStringLength = newSizeNeeded;
|
235
|
+
baseString->str[baseString->currentStringLength] = '\0';
|
236
|
+
}
|
237
|
+
|
238
|
+
|
239
|
+
/// Append to end of dynamic string using format specifier
|
240
|
+
void d_string_append_printf(DString * baseString, const char * format, ...) {
|
241
|
+
va_list args;
|
242
|
+
va_start(args, format);
|
243
|
+
|
244
|
+
char* formattedString = NULL;
|
245
|
+
vasprintf(&formattedString, format, args);
|
246
|
+
|
247
|
+
if (formattedString != NULL) {
|
248
|
+
d_string_append(baseString, formattedString);
|
249
|
+
free(formattedString);
|
250
|
+
}
|
251
|
+
|
252
|
+
va_end(args);
|
253
|
+
}
|
254
|
+
|
255
|
+
|
256
|
+
/// Prepend null-terminated string to end of dynamic string
|
257
|
+
void d_string_prepend(DString * baseString, const char * prependedString) {
|
258
|
+
size_t prependedStringLength = strlen(prependedString);
|
259
|
+
|
260
|
+
if ((prependedString != NULL) && (prependedStringLength > 0)) {
|
261
|
+
size_t newStringLength = baseString->currentStringLength + prependedStringLength;
|
262
|
+
ensureStringBufferCanHold(baseString, newStringLength);
|
263
|
+
|
264
|
+
memmove(baseString->str + prependedStringLength, baseString->str, baseString->currentStringLength);
|
265
|
+
strncpy(baseString->str, prependedString, prependedStringLength);
|
266
|
+
baseString->currentStringLength = newStringLength;
|
267
|
+
baseString->str[baseString->currentStringLength] = '\0';
|
268
|
+
}
|
269
|
+
}
|
270
|
+
|
271
|
+
|
272
|
+
/// Insert null-terminated string inside dynamic string
|
273
|
+
void d_string_insert(DString * baseString, size_t pos, const char * insertedString) {
|
274
|
+
size_t insertedStringLength = strlen(insertedString);
|
275
|
+
|
276
|
+
if ((insertedString != NULL) && (insertedStringLength > 0)) {
|
277
|
+
if (pos > baseString->currentStringLength) {
|
278
|
+
pos = baseString->currentStringLength;
|
279
|
+
}
|
280
|
+
|
281
|
+
size_t newStringLength = baseString->currentStringLength + insertedStringLength;
|
282
|
+
ensureStringBufferCanHold(baseString, newStringLength);
|
283
|
+
|
284
|
+
/* Shift following string to 'right' */
|
285
|
+
memmove(baseString->str + pos + insertedStringLength, baseString->str + pos, baseString->currentStringLength - pos);
|
286
|
+
strncpy(baseString->str + pos, insertedString, insertedStringLength);
|
287
|
+
baseString->currentStringLength = newStringLength;
|
288
|
+
baseString->str[baseString->currentStringLength] = '\0';
|
289
|
+
}
|
290
|
+
}
|
291
|
+
|
292
|
+
|
293
|
+
/// Insert single character inside dynamic string
|
294
|
+
void d_string_insert_c(DString * baseString, size_t pos, char insertedCharacter) {
|
295
|
+
if (pos > baseString->currentStringLength) {
|
296
|
+
pos = baseString->currentStringLength;
|
297
|
+
}
|
298
|
+
|
299
|
+
size_t newSizeNeeded = baseString->currentStringLength + 1;
|
300
|
+
ensureStringBufferCanHold(baseString, newSizeNeeded);
|
301
|
+
|
302
|
+
/* Shift following string to 'right' */
|
303
|
+
memmove(baseString->str + pos + 1, baseString->str + pos, baseString->currentStringLength - pos);
|
304
|
+
|
305
|
+
baseString->str[pos] = insertedCharacter;
|
306
|
+
baseString->currentStringLength++;
|
307
|
+
baseString->str[baseString->currentStringLength] = '\0';
|
308
|
+
}
|
309
|
+
|
310
|
+
|
311
|
+
/// Insert inside dynamic string using format specifier
|
312
|
+
void d_string_insert_printf(DString * baseString, size_t pos, const char * format, ...) {
|
313
|
+
va_list args;
|
314
|
+
va_start(args, format);
|
315
|
+
|
316
|
+
char* formattedString = NULL;
|
317
|
+
vasprintf(&formattedString, format, args);
|
318
|
+
|
319
|
+
if (formattedString != NULL) {
|
320
|
+
d_string_insert(baseString, pos, formattedString);
|
321
|
+
free(formattedString);
|
322
|
+
}
|
323
|
+
|
324
|
+
va_end(args);
|
325
|
+
}
|
326
|
+
|
327
|
+
|
328
|
+
/// Erase portion of dynamic string
|
329
|
+
void d_string_erase(DString * baseString, size_t pos, size_t len) {
|
330
|
+
if ((pos > baseString->currentStringLength) || (len <= 0)) {
|
331
|
+
return;
|
332
|
+
}
|
333
|
+
|
334
|
+
if ((pos + len) >= baseString->currentStringLength) {
|
335
|
+
len = -1;
|
336
|
+
}
|
337
|
+
|
338
|
+
if (len == -1) {
|
339
|
+
baseString->currentStringLength = pos;
|
340
|
+
} else {
|
341
|
+
memmove(baseString->str + pos, baseString->str + pos + len, baseString->currentStringLength - pos - len);
|
342
|
+
baseString->currentStringLength -= len;
|
343
|
+
}
|
344
|
+
|
345
|
+
baseString->str[baseString->currentStringLength] = '\0';
|
346
|
+
}
|
347
|
+
|
348
|
+
/// Copy a portion of dynamic string
|
349
|
+
char * d_string_copy_substring(DString * d, size_t start, size_t len) {
|
350
|
+
char * result;
|
351
|
+
|
352
|
+
if (len == -1) {
|
353
|
+
len = d->currentStringLength - start;
|
354
|
+
} else {
|
355
|
+
if (start + len > d->currentStringLength) {
|
356
|
+
fprintf(stderr, "d_string: Asked to copy invalid substring range.\n");
|
357
|
+
fprintf(stderr, "start: %lu len: %lu string: %lu\n", start, len,
|
358
|
+
d->currentStringLength);
|
359
|
+
return NULL;
|
360
|
+
}
|
361
|
+
}
|
362
|
+
|
363
|
+
result = malloc(len + 1);
|
364
|
+
strncpy(result, &d->str[start], len);
|
365
|
+
result[len] = '\0';
|
366
|
+
|
367
|
+
return result;
|
368
|
+
}
|
369
|
+
|
370
|
+
|
371
|
+
/// Replace occurences of "original" with "replace" inside the specified range
|
372
|
+
/// Returns the change in overall length
|
373
|
+
long d_string_replace_text_in_range(DString * d, size_t pos, size_t len, const char * original, const char * replace) {
|
374
|
+
long delta = 0; // Overall change in length
|
375
|
+
|
376
|
+
long len_o = strlen(original);
|
377
|
+
long len_r = strlen(replace);
|
378
|
+
long change = len_r - len_o; // Change in length for each replacement
|
379
|
+
|
380
|
+
size_t stop;
|
381
|
+
|
382
|
+
if (len == -1) {
|
383
|
+
stop = d->currentStringLength;
|
384
|
+
} else {
|
385
|
+
stop = pos + len;
|
386
|
+
}
|
387
|
+
|
388
|
+
char * match = strstr(&(d->str[pos]), original);
|
389
|
+
|
390
|
+
while (match && (match - d->str < stop)) {
|
391
|
+
pos = match - d->str;
|
392
|
+
d_string_erase(d, match - d->str, len_o);
|
393
|
+
d_string_insert(d, match - d->str, replace);
|
394
|
+
|
395
|
+
delta += change;
|
396
|
+
stop += change;
|
397
|
+
match = strstr(d->str + pos + len_r, original);
|
398
|
+
}
|
399
|
+
|
400
|
+
return delta;
|
401
|
+
}
|
402
|
+
|