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.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +2 -2
  3. data/README.md +7 -9
  4. data/Rakefile +33 -18
  5. data/ext/Makefile +261 -0
  6. data/ext/extconf.rb +23 -3
  7. data/ext/mmd/aho-corasick.c +596 -0
  8. data/ext/mmd/aho-corasick.h +120 -0
  9. data/ext/mmd/beamer.c +344 -0
  10. data/ext/mmd/beamer.h +72 -0
  11. data/ext/mmd/char.c +156 -0
  12. data/ext/mmd/char.h +111 -0
  13. data/ext/mmd/char_lookup.c +212 -0
  14. data/ext/mmd/critic_markup.c +330 -0
  15. data/ext/mmd/critic_markup.h +94 -0
  16. data/ext/mmd/d_string.c +402 -0
  17. data/ext/mmd/epub.c +563 -0
  18. data/ext/mmd/epub.h +69 -0
  19. data/ext/mmd/fodt.c +2288 -0
  20. data/ext/mmd/fodt.h +81 -0
  21. data/ext/mmd/html.c +2460 -0
  22. data/ext/mmd/html.h +81 -0
  23. data/ext/mmd/i18n.h +170 -0
  24. data/ext/mmd/include/d_string.h +182 -0
  25. data/ext/mmd/include/libMultiMarkdown.h +548 -0
  26. data/ext/mmd/include/token.h +233 -0
  27. data/ext/mmd/latex.c +2435 -0
  28. data/ext/mmd/latex.h +83 -0
  29. data/ext/mmd/lexer.c +3001 -0
  30. data/ext/mmd/lexer.h +75 -0
  31. data/ext/mmd/memoir.c +138 -0
  32. data/ext/mmd/memoir.h +67 -0
  33. data/ext/mmd/miniz.c +7557 -0
  34. data/ext/mmd/miniz.h +1328 -0
  35. data/ext/mmd/mmd.c +2798 -0
  36. data/ext/mmd/mmd.h +120 -0
  37. data/ext/mmd/object_pool.c +141 -0
  38. data/ext/mmd/object_pool.h +101 -0
  39. data/ext/mmd/opendocument-content.c +2071 -0
  40. data/ext/mmd/opendocument-content.h +135 -0
  41. data/ext/mmd/opendocument.c +981 -0
  42. data/ext/mmd/opendocument.h +118 -0
  43. data/ext/mmd/parser.c +1760 -0
  44. data/ext/mmd/parser.h +39 -0
  45. data/{MultiMarkdown-4 → ext/mmd}/rng.c +90 -49
  46. data/ext/mmd/scanners.c +77512 -0
  47. data/ext/mmd/scanners.h +101 -0
  48. data/ext/mmd/stack.c +142 -0
  49. data/ext/mmd/stack.h +113 -0
  50. data/ext/mmd/textbundle.c +455 -0
  51. data/ext/mmd/textbundle.h +115 -0
  52. data/ext/mmd/token.c +773 -0
  53. data/ext/mmd/token_pairs.c +263 -0
  54. data/ext/mmd/token_pairs.h +123 -0
  55. data/ext/mmd/transclude.c +549 -0
  56. data/ext/mmd/transclude.h +87 -0
  57. data/ext/mmd/uthash.h +1074 -0
  58. data/ext/mmd/uuid.c +154 -0
  59. data/ext/mmd/uuid.h +77 -0
  60. data/ext/mmd/version.h +111 -0
  61. data/ext/mmd/writer.c +2652 -0
  62. data/ext/mmd/writer.h +260 -0
  63. data/ext/mmd/zip.c +210 -0
  64. data/ext/mmd/zip.h +120 -0
  65. data/ext/{multi_markdown.c → ruby_multi_markdown.c} +87 -18
  66. data/lib/multi_markdown.bundle +0 -0
  67. data/lib/multi_markdown.rb +5 -8
  68. data/lib/multi_markdown/version.rb +1 -1
  69. data/rmultimarkdown.gemspec +2 -2
  70. data/test/{extensions_test.rb.rb → extensions_test.rb} +10 -54
  71. data/test/multi_markdown_test.rb +13 -0
  72. metadata +67 -47
  73. data/MultiMarkdown-4/GLibFacade.c +0 -310
  74. data/MultiMarkdown-4/GLibFacade.h +0 -100
  75. data/MultiMarkdown-4/beamer.c +0 -182
  76. data/MultiMarkdown-4/beamer.h +0 -11
  77. data/MultiMarkdown-4/critic.c +0 -111
  78. data/MultiMarkdown-4/critic.h +0 -15
  79. data/MultiMarkdown-4/glib.h +0 -11
  80. data/MultiMarkdown-4/html.c +0 -1117
  81. data/MultiMarkdown-4/html.h +0 -14
  82. data/MultiMarkdown-4/latex.c +0 -1217
  83. data/MultiMarkdown-4/latex.h +0 -16
  84. data/MultiMarkdown-4/libMultiMarkdown.h +0 -177
  85. data/MultiMarkdown-4/lyx.c +0 -2265
  86. data/MultiMarkdown-4/lyx.h +0 -37
  87. data/MultiMarkdown-4/lyxbeamer.c +0 -265
  88. data/MultiMarkdown-4/lyxbeamer.h +0 -11
  89. data/MultiMarkdown-4/memoir.c +0 -80
  90. data/MultiMarkdown-4/memoir.h +0 -10
  91. data/MultiMarkdown-4/multimarkdown.c +0 -518
  92. data/MultiMarkdown-4/odf.c +0 -1222
  93. data/MultiMarkdown-4/odf.h +0 -18
  94. data/MultiMarkdown-4/opml.c +0 -189
  95. data/MultiMarkdown-4/opml.h +0 -15
  96. data/MultiMarkdown-4/parse_utilities.c +0 -884
  97. data/MultiMarkdown-4/parser.c +0 -16656
  98. data/MultiMarkdown-4/parser.h +0 -188
  99. data/MultiMarkdown-4/rtf.c +0 -665
  100. data/MultiMarkdown-4/rtf.h +0 -17
  101. data/MultiMarkdown-4/strtok.c +0 -56
  102. data/MultiMarkdown-4/strtok.h +0 -9
  103. data/MultiMarkdown-4/text.c +0 -53
  104. data/MultiMarkdown-4/text.h +0 -11
  105. data/MultiMarkdown-4/toc.c +0 -142
  106. data/MultiMarkdown-4/toc.h +0 -15
  107. data/MultiMarkdown-4/transclude.c +0 -307
  108. data/MultiMarkdown-4/transclude.h +0 -28
  109. data/MultiMarkdown-4/writer.c +0 -731
  110. 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
@@ -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
+