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,115 @@
1
+ /**
2
+
3
+ MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
4
+
5
+ @file textbundle.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
+ uthash library:
33
+ Copyright (c) 2005-2016, Troy D. Hanson
34
+
35
+ Licensed under Revised BSD license
36
+
37
+ miniz library:
38
+ Copyright 2013-2014 RAD Game Tools and Valve Software
39
+ Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
40
+
41
+ Licensed under the MIT license
42
+
43
+ argtable3 library:
44
+ Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
45
+ <sheitmann@users.sourceforge.net>
46
+ All rights reserved.
47
+
48
+ Licensed under the Revised BSD License
49
+
50
+
51
+ ## The MIT License ##
52
+
53
+ Permission is hereby granted, free of charge, to any person obtaining
54
+ a copy of this software and associated documentation files (the
55
+ "Software"), to deal in the Software without restriction, including
56
+ without limitation the rights to use, copy, modify, merge, publish,
57
+ distribute, sublicense, and/or sell copies of the Software, and to
58
+ permit persons to whom the Software is furnished to do so, subject to
59
+ the following conditions:
60
+
61
+ The above copyright notice and this permission notice shall be
62
+ included in all copies or substantial portions of the Software.
63
+
64
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
65
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
66
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
67
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
68
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
69
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
70
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
71
+
72
+
73
+ ## Revised BSD License ##
74
+
75
+ Redistribution and use in source and binary forms, with or without
76
+ modification, are permitted provided that the following conditions are
77
+ met:
78
+ * Redistributions of source code must retain the above copyright
79
+ notice, this list of conditions and the following disclaimer.
80
+ * Redistributions in binary form must reproduce the above
81
+ copyright notice, this list of conditions and the following
82
+ disclaimer in the documentation and/or other materials provided
83
+ with the distribution.
84
+ * Neither the name of the <organization> nor the
85
+ names of its contributors may be used to endorse or promote
86
+ products derived from this software without specific prior
87
+ written permission.
88
+
89
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
90
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
91
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
92
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT
93
+ HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
94
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
95
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR
96
+ PROFITS OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
97
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
98
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
99
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
100
+
101
+
102
+ */
103
+
104
+
105
+ #ifndef TEXTBUNDLE_MULTIMARKDOWN_H
106
+ #define TEXTBUNDLE_MULTIMARKDOWN_H
107
+
108
+ #include "d_string.h"
109
+ #include "mmd.h"
110
+
111
+ void textbundle_write_wrapper(const char * filepath, const char * body, mmd_engine * e, const char * directory);
112
+
113
+ DString * textbundle_create(const char * body, mmd_engine * e, const char * directory);
114
+
115
+ #endif
data/ext/mmd/token.c ADDED
@@ -0,0 +1,773 @@
1
+ /**
2
+
3
+ Parser-Template -- Boilerplate parser example using re2c lexer and lemon parser.
4
+
5
+ @file token.c
6
+
7
+ @brief Structure and functions to manage tokens representing portions of a
8
+ text string.
9
+
10
+
11
+ @author Fletcher T. Penney
12
+
13
+ @bug
14
+
15
+ **/
16
+
17
+ /*
18
+
19
+ Copyright © 2016 - 2017 Fletcher T. Penney.
20
+
21
+
22
+ The `MultiMarkdown 6` project is released under the MIT License..
23
+
24
+ GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
25
+
26
+ https://github.com/fletcher/MultiMarkdown-4/
27
+
28
+ MMD 4 is released under both the MIT License and GPL.
29
+
30
+
31
+ CuTest is released under the zlib/libpng license. See CuTest.c for the text
32
+ of the license.
33
+
34
+
35
+ ## The MIT License ##
36
+
37
+ Permission is hereby granted, free of charge, to any person obtaining a copy
38
+ of this software and associated documentation files (the "Software"), to deal
39
+ in the Software without restriction, including without limitation the rights
40
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
41
+ copies of the Software, and to permit persons to whom the Software is
42
+ furnished to do so, subject to the following conditions:
43
+
44
+ The above copyright notice and this permission notice shall be included in
45
+ all copies or substantial portions of the Software.
46
+
47
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
48
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
49
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
50
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
51
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
52
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
53
+ THE SOFTWARE.
54
+
55
+ */
56
+
57
+ #include <stdarg.h>
58
+ #include <stdbool.h>
59
+ #include <stdio.h>
60
+ #include <stdlib.h>
61
+
62
+ #include "char.h"
63
+ #include "token.h"
64
+
65
+
66
+ #ifdef kUseObjectPool
67
+ //!< Use an object pool to allocate tokens more efficiently to improve
68
+ //!< performance.
69
+
70
+ #include "object_pool.h"
71
+
72
+ static pool * token_pool = NULL; //!< Pointer to our object pool
73
+
74
+ /// Count number of uses of this pool to allow us know
75
+ /// when it's safe to drain the pool
76
+ static short token_pool_count = 0;
77
+
78
+ /// Intialize object pool for token allocation
79
+ void token_pool_init(void) {
80
+ if (token_pool == NULL) {
81
+ // No pool exists
82
+ token_pool = pool_new(sizeof(token));
83
+ }
84
+
85
+ // Increment counter
86
+ token_pool_count++;
87
+ }
88
+
89
+
90
+ /// Drain token allocator pool to prepare for another parse
91
+ void token_pool_drain(void) {
92
+ // Decrement counter
93
+ token_pool_count--;
94
+
95
+ if (token_pool_count == 0) {
96
+ pool_drain(token_pool);
97
+ }
98
+ }
99
+
100
+
101
+ /// Free token allocator pool
102
+ void token_pool_free(void) {
103
+ if (token_pool_count == 0) {
104
+ pool_free(token_pool);
105
+ token_pool = NULL;
106
+ } else {
107
+ fprintf(stderr, "ERROR: Attempted to drain token pool while still in use.\n");
108
+ }
109
+ }
110
+
111
+ #endif
112
+
113
+
114
+ /// Get pointer to a new token
115
+ token * token_new(unsigned short type, size_t start, size_t len) {
116
+
117
+
118
+ #ifdef kUseObjectPool
119
+ token * t = pool_allocate_object(token_pool);
120
+ #else
121
+ token * t = malloc(sizeof(token));
122
+ #endif
123
+
124
+ if (t) {
125
+ t->type = type;
126
+ t->start = start;
127
+ t->len = len;
128
+
129
+ t->next = NULL;
130
+ t->prev = NULL;
131
+ t->child = NULL;
132
+
133
+ t->tail = t;
134
+
135
+ t->can_open = true; //!< Default to true -- we assume openers can open and closers can close
136
+ t->can_close = true; //!< unless specified otherwise (e.g. for ambidextrous tokens)
137
+ t->unmatched = true;
138
+
139
+ t->mate = NULL;
140
+ }
141
+
142
+ return t;
143
+ }
144
+
145
+
146
+ /// Duplicate an existing token
147
+ token * token_copy(token * original) {
148
+ #ifdef kUseObjectPool
149
+ token * t = pool_allocate_object(token_pool);
150
+ #else
151
+ token * t = malloc(sizeof(token));
152
+ #endif
153
+
154
+ if (t) {
155
+ * t = * original;
156
+ }
157
+
158
+ return t;
159
+ }
160
+
161
+
162
+ /// Create a parent for a chain of tokens
163
+ token * token_new_parent(token * child, unsigned short type) {
164
+ if (child == NULL) {
165
+ return token_new(type, 0, 0);
166
+ }
167
+
168
+ token * t = token_new(type, child->start, 0);
169
+ t->child = child;
170
+ child->prev = NULL;
171
+
172
+ // Ensure that parent length correctly includes children
173
+ if (child == NULL) {
174
+ t->len = 0;
175
+ } else if (child->next == NULL) {
176
+ t->len = child->len;
177
+ } else {
178
+ while (child->next != NULL) {
179
+ child = child->next;
180
+ }
181
+
182
+ t->len = child->start + child->len - t->start;
183
+ }
184
+
185
+ return t;
186
+ }
187
+
188
+
189
+ /// Add a new token to the end of a token chain. The new token
190
+ /// may or may not also be the start of a chain
191
+ void token_chain_append(token * chain_start, token * t) {
192
+ if ((chain_start == NULL) ||
193
+ (t == NULL)) {
194
+ return;
195
+ }
196
+
197
+ // Append t
198
+ chain_start->tail->next = t;
199
+ t->prev = chain_start->tail;
200
+
201
+ // Adjust tail marker
202
+ chain_start->tail = t->tail;
203
+ }
204
+
205
+
206
+ /// Add a new token to the end of a parent's child
207
+ /// token chain. The new token may or may not be
208
+ /// the start of a chain.
209
+ void token_append_child(token * parent, token * t) {
210
+ if ((parent == NULL) || (t == NULL)) {
211
+ return;
212
+ }
213
+
214
+ if (parent->child == NULL) {
215
+ // Parent has no children
216
+ parent->child = t;
217
+ } else {
218
+ // Append to to existing child chain
219
+ token_chain_append(parent->child, t);
220
+ }
221
+
222
+ // Set len on parent
223
+ parent->len = parent->child->tail->start + parent->child->tail->len - parent->start;
224
+ }
225
+
226
+
227
+ /// Remove the first child of a token
228
+ void token_remove_first_child(token * parent) {
229
+ if ((parent == NULL) || (parent->child == NULL)) {
230
+ return;
231
+ }
232
+
233
+ token * t = parent->child;
234
+ parent->child = t->next;
235
+
236
+ if (parent->child) {
237
+ parent->child->prev = NULL;
238
+ parent->child->tail = t->tail;
239
+ }
240
+
241
+ token_free(t);
242
+ }
243
+
244
+
245
+ /// Remove the last child of a token
246
+ void token_remove_last_child(token * parent) {
247
+ if ((parent == NULL) || (parent->child == NULL)) {
248
+ return;
249
+ }
250
+
251
+ token * t = parent->child->tail;
252
+
253
+ if (t->prev) {
254
+ t->prev->next = NULL;
255
+ parent->child->tail = t->prev;
256
+ }
257
+
258
+ token_free(t);
259
+ }
260
+
261
+
262
+ /// Remove the last token in a chain
263
+ void token_remove_tail(token * head) {
264
+ if ((head == NULL) || (head->tail == head)) {
265
+ return;
266
+ }
267
+
268
+ token * t = head->tail;
269
+
270
+ if (t->prev) {
271
+ t->prev->next = NULL;
272
+ head->tail = t->prev;
273
+ }
274
+
275
+ token_free(t);
276
+ }
277
+
278
+
279
+ /// Pop token out of it's chain, connecting head and tail of chain back together.
280
+ /// Token must be freed if it is no longer needed.
281
+ /// \todo: If t is the tail token of a chain, the tail is no longer correct on the start of chain.
282
+ void token_pop_link_from_chain(token * t) {
283
+ if (t == NULL) {
284
+ return;
285
+ }
286
+
287
+ token * prev = t->prev;
288
+ token * next = t->next;
289
+
290
+ t->next = NULL;
291
+ t->prev = NULL;
292
+ t->tail = t;
293
+
294
+ if (prev) {
295
+ prev->next = next;
296
+ }
297
+
298
+ if (next) {
299
+ next->prev = prev;
300
+ }
301
+ }
302
+
303
+
304
+ /// Remove one or more tokens from chain
305
+ void tokens_prune(token * first, token * last) {
306
+ if (first == NULL || last == NULL) {
307
+ return;
308
+ }
309
+
310
+ token * prev = first->prev;
311
+ token * next = last->next;
312
+
313
+ if (prev != NULL) {
314
+ prev->next = next;
315
+ }
316
+
317
+ if (next != NULL) {
318
+ next->prev = prev;
319
+ }
320
+
321
+ first->prev = NULL;
322
+ last->next = NULL;
323
+
324
+ token_tree_free(first);
325
+ }
326
+
327
+
328
+ /// Given a start/stop point in token chain, create a new container token.
329
+ /// Return pointer to new container token.
330
+ token * token_prune_graft(token * first, token * last, unsigned short container_type) {
331
+ if (first == NULL || last == NULL) {
332
+ return first;
333
+ }
334
+
335
+ token * next = last->next;
336
+
337
+ // Duplicate first token -- this will be child of new container
338
+ token * new_child = token_copy(first);
339
+ new_child->prev = NULL;
340
+ new_child->tail = last;
341
+
342
+ if (new_child->next) {
343
+ new_child->next->prev = new_child;
344
+ }
345
+
346
+ // Swap last (if necessary)
347
+ if (first == last) {
348
+ last = new_child;
349
+ }
350
+
351
+ // Existing first token will be new container
352
+ first->child = new_child;
353
+ first->type = container_type;
354
+ first->len = last->start + last->len - first->start;
355
+ first->next = next;
356
+ first->can_close = 0;
357
+ first->can_open = 0;
358
+
359
+ // Fix mating
360
+ if (first->mate) {
361
+ first->mate = NULL;
362
+ new_child->mate->mate = new_child;
363
+ }
364
+
365
+ // Disconnect last token
366
+ last->next = NULL;
367
+
368
+ if (next) {
369
+ next->prev = first;
370
+ }
371
+
372
+ return first;
373
+ }
374
+
375
+
376
+ /// Free token
377
+ void token_free(token * t) {
378
+ #ifdef kUseObjectPool
379
+ return;
380
+ #else
381
+
382
+ if (t == NULL) {
383
+ return;
384
+ }
385
+
386
+ token_tree_free(t->child);
387
+
388
+ free(t);
389
+ #endif
390
+ }
391
+
392
+
393
+ /// Free token chain
394
+ void token_tree_free(token * t) {
395
+ #ifdef kUseObjectPool
396
+ return;
397
+ #else
398
+ token * n;
399
+
400
+ while (t != NULL) {
401
+ n = t->next;
402
+ token_free(t);
403
+
404
+ t = n;
405
+ }
406
+
407
+ #endif
408
+ }
409
+
410
+
411
+ /// Forward declaration
412
+ void print_token_tree(token * t, unsigned short depth, const char * string);
413
+
414
+
415
+ /// Print contents of the token based on specified string
416
+ void print_token(token * t, unsigned short depth, const char * string) {
417
+ if (t != NULL) {
418
+ for (int i = 0; i < depth; ++i) {
419
+ fprintf(stderr, "\t");
420
+ }
421
+
422
+ if (string == NULL) {
423
+ fprintf(stderr, "* (%d) %lu:%lu\n", t->type, t->start, t->len);
424
+ } else {
425
+ fprintf(stderr, "* (%d) %lu:%lu\t'%.*s'\n", t->type, t->start, t->len, (int)t->len, &string[t->start]);
426
+ }
427
+
428
+ if (t->child != NULL) {
429
+ print_token_tree(t->child, depth + 1, string);
430
+ }
431
+ }
432
+ }
433
+
434
+
435
+ /// Print contents of the token tree based on specified string
436
+ void print_token_tree(token * t, unsigned short depth, const char * string) {
437
+ while (t != NULL) {
438
+ print_token(t, depth, string);
439
+
440
+ t = t->next;
441
+ }
442
+ }
443
+
444
+
445
+ /// Print a description of the token based on specified string
446
+ void token_describe(token * t, const char * string) {
447
+ print_token(t, 0, string);
448
+ }
449
+
450
+
451
+ /// Print a description of the token tree based on specified string
452
+ void token_tree_describe(token * t, const char * string) {
453
+ fprintf(stderr, "=====>\n");
454
+
455
+ while (t != NULL) {
456
+ print_token(t, 0, string);
457
+
458
+ t = t->next;
459
+ }
460
+
461
+ fprintf(stderr, "<=====\n");
462
+ }
463
+
464
+
465
+ /// Find the child node of a given parent that contains the specified
466
+ /// offset position.
467
+ token * token_child_for_offset(
468
+ token * parent, //!< Pointer to parent token
469
+ size_t offset //!< Search position
470
+ ) {
471
+ if (parent == NULL) {
472
+ return NULL;
473
+ }
474
+
475
+ if ((parent->start > offset) ||
476
+ (parent->start + parent->len < offset)) {
477
+ return NULL;
478
+ }
479
+
480
+ token * walker = parent->child;
481
+
482
+ while (walker != NULL) {
483
+ if (walker->start <= offset) {
484
+ if (walker->start + walker->len > offset) {
485
+ return walker;
486
+ }
487
+ }
488
+
489
+ if (walker->start > offset) {
490
+ return NULL;
491
+ }
492
+
493
+ walker = walker->next;
494
+ }
495
+
496
+ return NULL;
497
+ }
498
+
499
+
500
+ /// Given two character ranges, see if they intersect (touching doesn't count)
501
+ static bool ranges_intersect(size_t start1, size_t len1, size_t start2, size_t len2) {
502
+ return ((start1 < start2 + len2) && (start2 < start1 + len1)) ? true : false;
503
+ }
504
+
505
+ /// Find first child node of a given parent that intersects the specified
506
+ /// offset range.
507
+ token * token_first_child_in_range(
508
+ token * parent, //!< Pointer to parent token
509
+ size_t start, //!< Start search position
510
+ size_t len //!< Search length
511
+ ) {
512
+ if (parent == NULL) {
513
+ return NULL;
514
+ }
515
+
516
+ if ((parent->start > start + len) ||
517
+ (parent->start + parent->len < start)) {
518
+ return NULL;
519
+ }
520
+
521
+ token * walker = parent->child;
522
+
523
+ while (walker != NULL) {
524
+ if (ranges_intersect(start, len, walker->start, walker->len)) {
525
+ return walker;
526
+ }
527
+
528
+ if (walker->start > start) {
529
+ return NULL;
530
+ }
531
+
532
+ walker = walker->next;
533
+ }
534
+
535
+ return NULL;
536
+ }
537
+
538
+
539
+ /// Find last child node of a given parent that intersects the specified
540
+ /// offset range.
541
+ token * token_last_child_in_range(
542
+ token * parent, //!< Pointer to parent token
543
+ size_t start, //!< Start search position
544
+ size_t len //!< Search length
545
+ ) {
546
+ if (parent == NULL) {
547
+ return NULL;
548
+ }
549
+
550
+ if ((parent->start > start + len) ||
551
+ (parent->start + parent->len < start)) {
552
+ return NULL;
553
+ }
554
+
555
+ token * walker = parent->child;
556
+ token * last = NULL;
557
+
558
+ while (walker != NULL) {
559
+ if (ranges_intersect(start, len, walker->start, walker->len)) {
560
+ last = walker;
561
+ }
562
+
563
+ if (walker->start > start + len) {
564
+ return last;
565
+ }
566
+
567
+ walker = walker->next;
568
+ }
569
+
570
+ return last;
571
+ }
572
+
573
+
574
+ void token_trim_leading_whitespace(token * t, const char * string) {
575
+ while (t->len && char_is_whitespace(string[t->start])) {
576
+ t->start++;
577
+ t->len--;
578
+ }
579
+ }
580
+
581
+
582
+ void token_trim_trailing_whitespace(token * t, const char * string) {
583
+ while (t->len && char_is_whitespace(string[t->start + t->len - 1])) {
584
+ t->len--;
585
+ }
586
+ }
587
+
588
+
589
+ void token_trim_whitespace(token * t, const char * string) {
590
+ token_trim_leading_whitespace(t, string);
591
+ token_trim_trailing_whitespace(t, string);
592
+ }
593
+
594
+
595
+ /// Check whether first token in the chain matches the given type.
596
+ /// If so, return and advance the chain.
597
+ token * token_chain_accept(token ** t, short type) {
598
+ token * result = NULL;
599
+
600
+ if (t && *t && ((*t)->type == type)) {
601
+ result = *t;
602
+ *t = (*t)->next;
603
+ }
604
+
605
+ return result;
606
+ }
607
+
608
+
609
+ /// Allow checking for multiple token types
610
+ token * token_chain_accept_multiple(token ** t, int n, ...) {
611
+ token * result = NULL;
612
+ va_list valist;
613
+
614
+ va_start(valist, n);
615
+
616
+ for (int i = 0; i < n; ++i) {
617
+ result = token_chain_accept(t, va_arg(valist, int));
618
+
619
+ if (result) {
620
+ break;
621
+ }
622
+ }
623
+
624
+ va_end(valist);
625
+
626
+ return result;
627
+ }
628
+
629
+
630
+ void token_skip_until_type(token ** t, short type) {
631
+ while ((*t) && ((*t)->type != type)) {
632
+ *t = (*t)->next;
633
+ }
634
+ }
635
+
636
+
637
+ /// Allow checking for multiple token types
638
+ void token_skip_until_type_multiple(token ** t, int n, ...) {
639
+ va_list valist;
640
+ int type[n];
641
+
642
+ va_start(valist, n);
643
+
644
+ // Load target types
645
+ for (int i = 0; i < n; ++i) {
646
+ type[i] = va_arg(valist, int);
647
+ }
648
+
649
+ //
650
+ while (*t) {
651
+ for (int i = 0; i < n; ++i) {
652
+ if ((*t)->type == type[i]) {
653
+ return;
654
+ }
655
+ }
656
+
657
+ *t = (*t)->next;
658
+ }
659
+
660
+ va_end(valist);
661
+ }
662
+
663
+
664
+ void token_split_on_char(token * t, const char * source, const char c) {
665
+ if (!t) {
666
+ return;
667
+ }
668
+
669
+ size_t start = t->start;
670
+ size_t pos = 0;
671
+ size_t stop = t->len;
672
+ token * new = NULL;
673
+
674
+ while (pos + 1 < stop) {
675
+ if (source[start + pos] == c) {
676
+ new = token_new(t->type, start + pos + 1, stop - (pos + 1));
677
+ new->next = t->next;
678
+ t->next = new;
679
+
680
+ t->len = pos;
681
+
682
+ t = t->next;
683
+ }
684
+
685
+ pos++;
686
+ }
687
+ }
688
+
689
+
690
+ // Split a token and create new ones as needed
691
+ void token_split(token * t, size_t start, size_t len, unsigned short new_type) {
692
+ if (!t) {
693
+ return;
694
+ }
695
+
696
+ size_t stop = start + len;
697
+
698
+ if (start < t->start) {
699
+ return;
700
+ }
701
+
702
+ if (stop > t->start + t->len) {
703
+ return;
704
+ }
705
+
706
+ token * A; // This will be new token
707
+ bool inset_start = false;
708
+ bool inset_stop = false;
709
+
710
+ // Will we need a leading token?
711
+ if (start > t->start) {
712
+ inset_start = true;
713
+ }
714
+
715
+ // Will we need a lagging token?
716
+ if (stop < t->start + t->len) {
717
+ inset_stop = true;
718
+ }
719
+
720
+
721
+ if (inset_start) {
722
+ A = token_new(new_type, start, len);
723
+
724
+ if (inset_stop) {
725
+ // We will end up with t->A->T2
726
+
727
+ // Create T2
728
+ token * T2 = token_new(t->type, stop, t->start + t->len - stop);
729
+ T2->next = t->next;
730
+
731
+ if (t->next) {
732
+ t->next->prev = T2;
733
+ }
734
+
735
+ A->next = T2;
736
+ T2->prev = A;
737
+ } else {
738
+ // We will end up with T->A
739
+ A->next = t->next;
740
+
741
+ if (t->next) {
742
+ t->next->prev = A;
743
+ }
744
+ }
745
+
746
+ t->next = A;
747
+ A->prev = t;
748
+
749
+ t->len = start - t->start;
750
+ } else {
751
+ if (inset_stop) {
752
+ // We will end up with A->T
753
+ // But we swap the tokens to ensure we don't
754
+ // cause difficulty pointing to this chain,
755
+ // resulting in T->A, where T is the new type
756
+ A = token_new(t->type, stop, t->start + t->len - stop);
757
+ A->prev = t;
758
+ A->next = t->next;
759
+ t->next = A;
760
+
761
+ if (A->next) {
762
+ A->next->prev = A;
763
+ }
764
+
765
+ t->len = stop - t->start;
766
+ t->type = new_type;
767
+ } else {
768
+ // We will end up with A
769
+ t->type = new_type;
770
+ }
771
+ }
772
+ }
773
+