rmultimarkdown 6.4.0.3 → 6.7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. checksums.yaml +5 -5
  2. data/Rakefile +7 -13
  3. data/ext/Makefile +67 -55
  4. data/ext/extconf.rb +8 -6
  5. data/ext/mmd/aho-corasick.c +8 -8
  6. data/ext/mmd/aho-corasick.h +3 -3
  7. data/ext/mmd/argtable3.c +6537 -0
  8. data/ext/mmd/argtable3.h +273 -0
  9. data/ext/mmd/beamer.c +12 -1
  10. data/ext/mmd/char.c +120 -27
  11. data/ext/mmd/char.h +23 -23
  12. data/ext/mmd/critic_markup.c +7 -6
  13. data/ext/mmd/d_string.c +88 -32
  14. data/ext/mmd/{include/d_string.h → d_string.h} +50 -38
  15. data/ext/mmd/epub.c +36 -12
  16. data/ext/mmd/epub.h +2 -2
  17. data/ext/mmd/file.c +50 -40
  18. data/ext/mmd/file.h +2 -2
  19. data/ext/mmd/html.c +164 -99
  20. data/ext/mmd/html.h +3 -2
  21. data/ext/mmd/i18n.h +15 -11
  22. data/ext/mmd/itmz-lexer.c +16978 -0
  23. data/ext/mmd/itmz-lexer.h +132 -0
  24. data/ext/mmd/itmz-parser.c +1189 -0
  25. data/ext/mmd/itmz-parser.h +11 -0
  26. data/ext/mmd/itmz-reader.c +388 -0
  27. data/ext/mmd/itmz-reader.h +111 -0
  28. data/ext/mmd/itmz.c +567 -0
  29. data/ext/mmd/itmz.h +117 -0
  30. data/ext/mmd/latex.c +93 -41
  31. data/ext/mmd/lexer.c +3506 -2774
  32. data/ext/mmd/{include/libMultiMarkdown.h → libMultiMarkdown.h} +49 -2
  33. data/ext/mmd/main.c +612 -0
  34. data/ext/mmd/memoir.c +4 -1
  35. data/ext/mmd/miniz.c +6905 -6680
  36. data/ext/mmd/miniz.h +456 -476
  37. data/ext/mmd/mmd.c +399 -94
  38. data/ext/mmd/mmd.h +25 -25
  39. data/ext/mmd/object_pool.h +3 -3
  40. data/ext/mmd/opendocument-content.c +137 -69
  41. data/ext/mmd/opendocument-content.h +2 -2
  42. data/ext/mmd/opendocument.c +35 -14
  43. data/ext/mmd/opendocument.h +2 -2
  44. data/ext/mmd/opml-lexer.c +259 -637
  45. data/ext/mmd/opml-lexer.h +1 -17
  46. data/ext/mmd/opml-parser.c +194 -188
  47. data/ext/mmd/opml-reader.c +72 -142
  48. data/ext/mmd/opml-reader.h +1 -1
  49. data/ext/mmd/opml.c +13 -13
  50. data/ext/mmd/opml.h +1 -1
  51. data/ext/mmd/parser.c +1623 -1244
  52. data/ext/mmd/rng.c +8 -3
  53. data/ext/mmd/scanners.c +66625 -103198
  54. data/ext/mmd/scanners.h +1 -0
  55. data/ext/mmd/stack.c +62 -20
  56. data/ext/mmd/stack.h +10 -21
  57. data/ext/mmd/textbundle.c +23 -7
  58. data/ext/mmd/textbundle.h +2 -2
  59. data/ext/mmd/token.c +42 -16
  60. data/ext/mmd/{include/token.h → token.h} +22 -8
  61. data/ext/mmd/token_pairs.c +0 -16
  62. data/ext/mmd/transclude.c +6 -2
  63. data/ext/mmd/uthash.h +745 -745
  64. data/ext/mmd/version.h +8 -8
  65. data/ext/mmd/writer.c +225 -63
  66. data/ext/mmd/writer.h +50 -36
  67. data/ext/mmd/xml.c +855 -0
  68. data/ext/mmd/xml.h +134 -0
  69. data/ext/mmd/zip.c +71 -4
  70. data/ext/mmd/zip.h +7 -1
  71. data/ext/ruby_multi_markdown.c +9 -18
  72. data/lib/multi_markdown/version.rb +1 -1
  73. data/lib/multi_markdown.bundle +0 -0
  74. data/rmultimarkdown.gemspec +0 -2
  75. metadata +22 -28
  76. data/ext/mmd/char_lookup.c +0 -212
data/ext/mmd/main.c ADDED
@@ -0,0 +1,612 @@
1
+ /**
2
+
3
+ MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
4
+
5
+ @file main.c
6
+
7
+ @brief Create command-line frontend for libMultiMarkdown.
8
+
9
+
10
+ @author Fletcher T. Penney
11
+ @bug
12
+
13
+
14
+ **/
15
+
16
+ /*
17
+
18
+ Copyright © 2016 - 2017 Fletcher T. Penney.
19
+
20
+
21
+ The `MultiMarkdown 6` project is released under the MIT License..
22
+
23
+ GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
24
+
25
+ https://github.com/fletcher/MultiMarkdown-4/
26
+
27
+ MMD 4 is released under both the MIT License and GPL.
28
+
29
+
30
+ CuTest is released under the zlib/libpng license. See CuTest.c for the text
31
+ of the license.
32
+
33
+
34
+ ## The MIT License ##
35
+
36
+ Permission is hereby granted, free of charge, to any person obtaining a copy
37
+ of this software and associated documentation files (the "Software"), to deal
38
+ in the Software without restriction, including without limitation the rights
39
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40
+ copies of the Software, and to permit persons to whom the Software is
41
+ furnished to do so, subject to the following conditions:
42
+
43
+ The above copyright notice and this permission notice shall be included in
44
+ all copies or substantial portions of the Software.
45
+
46
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
52
+ THE SOFTWARE.
53
+
54
+ */
55
+
56
+ #include <ctype.h>
57
+ #include <libgen.h>
58
+ #include <limits.h>
59
+ #include <stdio.h>
60
+ #include <stdlib.h>
61
+ #include <string.h>
62
+
63
+
64
+ #include "argtable3.h"
65
+ #include "d_string.h"
66
+ #include "file.h"
67
+ #include "i18n.h"
68
+ #include "libMultiMarkdown.h"
69
+ #include "token.h"
70
+ #include "uuid.h"
71
+ #include "version.h"
72
+ #include "zip.h"
73
+
74
+ #define kBUFFERSIZE 4096 // How many bytes to read at a time
75
+
76
+ // argtable structs
77
+ struct arg_lit * a_help, *a_version, *a_compatibility, *a_nolabels, *a_batch,
78
+ *a_accept, *a_reject, *a_full, *a_snippet, *a_random, *a_unique, *a_meta,
79
+ *a_notransclude, *a_nosmart, *a_opml, *a_itmz;
80
+ struct arg_str * a_format, *a_lang, *a_extract;
81
+ struct arg_file * a_file, *a_o;
82
+ struct arg_end * a_end;
83
+ struct arg_rem * a_rem1, *a_rem2, *a_rem3, *a_rem4, *a_rem5, *a_rem6;
84
+
85
+
86
+ /// strdup() not available on all platforms
87
+ static char * my_strdup(const char * source) {
88
+ if (source == NULL) {
89
+ return NULL;
90
+ }
91
+
92
+ char * result = malloc(strlen(source) + 1);
93
+
94
+ if (result) {
95
+ strcpy(result, source);
96
+ }
97
+
98
+ return result;
99
+ }
100
+
101
+
102
+ /// Given a filename, remove the extension and replace it with a new one.
103
+ /// The next extension must include the leading '.', e.g. '.html'
104
+ char * filename_with_extension(const char * original, const char * new_extension) {
105
+ char * name_no_ext;
106
+ DString * new_name;
107
+
108
+ // Determine output filename without file extension
109
+ name_no_ext = my_strdup(original);
110
+
111
+ if (strrchr(name_no_ext, '.') != NULL) {
112
+ long count = strrchr(name_no_ext, '.') - name_no_ext;
113
+
114
+ if (count != 0) {
115
+ name_no_ext[count] = '\0';
116
+ }
117
+ }
118
+
119
+ new_name = d_string_new(name_no_ext);
120
+ free(name_no_ext);
121
+
122
+ d_string_append(new_name, new_extension);
123
+
124
+ name_no_ext = new_name->str;
125
+
126
+ d_string_free(new_name, false);
127
+
128
+ return name_no_ext;
129
+ }
130
+
131
+
132
+ int main(int argc, char ** argv) {
133
+ int exitcode = EXIT_SUCCESS;
134
+ char * binname = "multimarkdown";
135
+ short format = FORMAT_HTML;
136
+ short language = LC_EN;
137
+
138
+ // Initialize argtable structs
139
+ void * argtable[] = {
140
+ a_help = arg_lit0(NULL, "help", "display this help and exit"),
141
+ a_version = arg_lit0(NULL, "version", "display version info and exit"),
142
+
143
+ a_rem1 = arg_rem("", ""),
144
+
145
+ a_batch = arg_lit0("b", "batch", "process each file separately"),
146
+ a_full = arg_lit0("f", "full", "force a complete document"),
147
+ a_snippet = arg_lit0("s", "snippet", "force a snippet"),
148
+ a_compatibility = arg_lit0("c", "compatibility", "Markdown compatibility mode"),
149
+ a_random = arg_lit0(NULL, "random", "use random numbers for footnote anchors"),
150
+ a_unique = arg_lit0(NULL, "unique", "use random numbers for header labels unless manually specified"),
151
+ a_nosmart = arg_lit0(NULL, "nosmart", "Disable smart typography"),
152
+ a_nolabels = arg_lit0(NULL, "nolabels", "Disable id attributes for headers"),
153
+ a_notransclude = arg_lit0(NULL, "notransclude", "Disable file transclusion"),
154
+ a_opml = arg_lit0(NULL, "opml", "Convert OPML source to plain text before processing"),
155
+ a_itmz = arg_lit0(NULL, "itmz", "Convert ITMZ (iThoughts) source to plain text before processing"),
156
+
157
+ a_rem2 = arg_rem("", ""),
158
+
159
+ a_format = arg_str0("t", "to", "FORMAT", "convert to FORMAT, FORMAT = html|latex|beamer|memoir|mmd|odt|fodt|epub|opml|itmz|bundle|bundlezip"),
160
+ a_o = arg_file0("o", "output", "FILE", "send output to FILE"),
161
+
162
+ a_rem3 = arg_rem("", ""),
163
+
164
+ a_accept = arg_lit0("a", "accept", "accept all CriticMarkup changes"),
165
+ a_reject = arg_lit0("r", "reject", "reject all CriticMarkup changes"),
166
+
167
+ a_rem4 = arg_rem("", ""),
168
+
169
+ a_lang = arg_str0("l", "lang", "LANG", "language/smart quote localization, LANG = en|es|de|fr|he|nl|sv"),
170
+
171
+ a_rem5 = arg_rem("", ""),
172
+
173
+ a_meta = arg_lit0("m", "metadata-keys", "list all metadata keys"),
174
+ a_extract = arg_str0("e", "extract", "KEY", "extract specified metadata key"),
175
+
176
+ a_rem6 = arg_rem("", ""),
177
+
178
+ a_file = arg_filen(NULL, NULL, "<FILE>", 0, argc + 2, "read input from file(s) -- use stdin if no files given"),
179
+
180
+ a_end = arg_end(20),
181
+ };
182
+
183
+ // Set default options
184
+ a_o->filename[0] = "-"; // Default to stdout if no option specified
185
+
186
+ int nerrors = arg_parse(argc, argv, argtable);
187
+
188
+ // '--help' takes precedence
189
+ if (a_help->count > 0) {
190
+ printf("\n%s v%s -- %s\n\n", LIBMULTIMARKDOWN_NAME, LIBMULTIMARKDOWN_VERSION, LIBMULTIMARKDOWN_COPYRIGHT);
191
+ printf("\tUsage: %s", binname);
192
+ arg_print_syntax(stdout, argtable, "\n\n");
193
+ printf("Options:\n");
194
+ arg_print_glossary(stdout, argtable, "\t%-25s %s\n");
195
+ printf("\n");
196
+ goto exit2;
197
+ }
198
+
199
+ if (nerrors > 0) {
200
+ // Report errors
201
+ arg_print_errors(stdout, a_end, LIBMULTIMARKDOWN_NAME);
202
+ printf("Try '%s --help' for more information.\n", binname);
203
+ exitcode = 1;
204
+ goto exit2;
205
+ }
206
+
207
+ // '--version' also takes precedence
208
+ if (a_version->count > 0) {
209
+ printf("\nMultiMarkdown 6 v%s\n", LIBMULTIMARKDOWN_VERSION);
210
+ printf("%s\n\n", LIBMULTIMARKDOWN_COPYRIGHT);
211
+ printf("%s\n", LIBMULTIMARKDOWN_LICENSE);
212
+ printf("\n");
213
+ goto exit2;
214
+ }
215
+
216
+
217
+ // Parse options
218
+ unsigned long extensions = EXT_SMART | EXT_NOTES | EXT_CRITIC | EXT_TRANSCLUDE;
219
+
220
+ if (a_compatibility->count > 0) {
221
+ // Compatibility mode disables certain features
222
+ // Reset extensions
223
+ extensions = EXT_COMPATIBILITY | EXT_NO_LABELS | EXT_OBFUSCATE | EXT_NO_METADATA;
224
+ }
225
+
226
+ if (a_nosmart->count > 0) {
227
+ // Disable smart typography
228
+ extensions &= ~EXT_SMART;
229
+ }
230
+
231
+ if (a_nolabels->count > 0) {
232
+ // Disable header id attributes
233
+ extensions |= EXT_NO_LABELS;
234
+ }
235
+
236
+ if (a_notransclude->count > 0) {
237
+ // Disable file transclusion
238
+ extensions &= ~EXT_TRANSCLUDE;
239
+ }
240
+
241
+ if (a_opml->count > 0) {
242
+ // Attempt to convert from OPML
243
+ extensions |= EXT_PARSE_OPML;
244
+ } else if (a_itmz->count > 0) {
245
+ // Attempt to convert from ITMZ
246
+ extensions |= EXT_PARSE_ITMZ;
247
+ }
248
+
249
+ if (a_accept->count > 0) {
250
+ // Accept CriticMarkup changes
251
+ extensions |= EXT_CRITIC_ACCEPT | EXT_CRITIC;
252
+ }
253
+
254
+ if (a_reject->count > 0) {
255
+ // Reject CriticMarkup changes
256
+ extensions |= EXT_CRITIC_REJECT | EXT_CRITIC;
257
+ }
258
+
259
+ if (a_reject->count && a_accept->count) {
260
+ // Old options that don't apply now, so change them
261
+ extensions &= ~(EXT_CRITIC_REJECT | EXT_CRITIC_ACCEPT);
262
+ }
263
+
264
+ if (a_full->count > 0) {
265
+ // Force complete document
266
+ extensions |= EXT_COMPLETE;
267
+ }
268
+
269
+ if (a_snippet->count > 0) {
270
+ // Force snippet
271
+ extensions |= EXT_SNIPPET;
272
+ }
273
+
274
+ if (a_random->count > 0) {
275
+ // Use random anchors
276
+ extensions |= EXT_RANDOM_FOOT;
277
+ }
278
+
279
+ if (a_unique->count > 0) {
280
+ // Use random header labels
281
+ extensions |= EXT_RANDOM_LABELS;
282
+ }
283
+
284
+ if (a_format->count > 0) {
285
+ if (strcmp(a_format->sval[0], "html") == 0) {
286
+ format = FORMAT_HTML;
287
+ } else if (strcmp(a_format->sval[0], "latex") == 0) {
288
+ format = FORMAT_LATEX;
289
+ } else if (strcmp(a_format->sval[0], "beamer") == 0) {
290
+ format = FORMAT_BEAMER;
291
+ } else if (strcmp(a_format->sval[0], "memoir") == 0) {
292
+ format = FORMAT_MEMOIR;
293
+ } else if (strcmp(a_format->sval[0], "mmd") == 0) {
294
+ format = FORMAT_MMD;
295
+ } else if (strcmp(a_format->sval[0], "odt") == 0) {
296
+ format = FORMAT_ODT;
297
+ } else if (strcmp(a_format->sval[0], "fodt") == 0) {
298
+ format = FORMAT_FODT;
299
+ } else if (strcmp(a_format->sval[0], "epub") == 0) {
300
+ format = FORMAT_EPUB;
301
+ } else if (strcmp(a_format->sval[0], "bundle") == 0) {
302
+ format = FORMAT_TEXTBUNDLE;
303
+ } else if (strcmp(a_format->sval[0], "bundlezip") == 0) {
304
+ format = FORMAT_TEXTBUNDLE_COMPRESSED;
305
+ } else if (strcmp(a_format->sval[0], "opml") == 0) {
306
+ format = FORMAT_OPML;
307
+ } else if (strcmp(a_format->sval[0], "itmz") == 0) {
308
+ format = FORMAT_ITMZ;
309
+ } else {
310
+ // No valid format found
311
+ fprintf(stderr, "%s: Unknown output format '%s'\n", binname, a_format->sval[0]);
312
+ exitcode = 1;
313
+ goto exit2;
314
+ }
315
+ }
316
+
317
+ if (a_lang->count > 0) {
318
+ language = LANG_FROM_STR(a_lang->sval[0]);
319
+ }
320
+
321
+ // Determine input
322
+ if (a_file->count == 0) {
323
+ // Read from stdin
324
+ } else {
325
+ // Read from files
326
+ }
327
+
328
+ DString * buffer = NULL;
329
+ DString * result = NULL;
330
+ char * char_result = NULL;
331
+ FILE * output_stream;
332
+ char * output_filename;
333
+
334
+ // Increment counter and prepare token pool
335
+ #ifdef kUseObjectPool
336
+ token_pool_init();
337
+ #endif
338
+
339
+ // Seed random numbers
340
+ custom_seed_rand();
341
+
342
+ // Determine processing mode -- batch/stdin/files??
343
+
344
+ if ((a_batch->count) && (a_file->count)) {
345
+ // Batch process 1 or more files
346
+ for (int i = 0; i < a_file->count; ++i) {
347
+
348
+ buffer = scan_file(a_file->filename[i]);
349
+
350
+ if (buffer == NULL) {
351
+ fprintf(stderr, "Error reading file '%s'\n", a_file->filename[i]);
352
+ exitcode = 1;
353
+ goto exit2;
354
+ }
355
+
356
+ // Append output file extension
357
+ switch (format) {
358
+ case FORMAT_HTML:
359
+ output_filename = filename_with_extension(a_file->filename[i], ".html");
360
+ break;
361
+
362
+ case FORMAT_LATEX:
363
+ case FORMAT_BEAMER:
364
+ case FORMAT_MEMOIR:
365
+ output_filename = filename_with_extension(a_file->filename[i], ".tex");
366
+ break;
367
+
368
+ case FORMAT_FODT:
369
+ output_filename = filename_with_extension(a_file->filename[i], ".fodt");
370
+ break;
371
+
372
+ case FORMAT_ODT:
373
+ output_filename = filename_with_extension(a_file->filename[i], ".odt");
374
+ break;
375
+
376
+ case FORMAT_MMD:
377
+ output_filename = filename_with_extension(a_file->filename[i], ".mmdtext");
378
+ break;
379
+
380
+ case FORMAT_EPUB:
381
+ output_filename = filename_with_extension(a_file->filename[i], ".epub");
382
+ break;
383
+
384
+ case FORMAT_TEXTBUNDLE:
385
+ output_filename = filename_with_extension(a_file->filename[i], ".textbundle");
386
+ break;
387
+
388
+ case FORMAT_TEXTBUNDLE_COMPRESSED:
389
+ output_filename = filename_with_extension(a_file->filename[i], ".textpack");
390
+ break;
391
+
392
+ case FORMAT_OPML:
393
+ output_filename = filename_with_extension(a_file->filename[i], ".opml");
394
+ break;
395
+
396
+ case FORMAT_ITMZ:
397
+ output_filename = filename_with_extension(a_file->filename[i], ".itmz");
398
+ break;
399
+ }
400
+
401
+ // Perform transclusion(s)
402
+ char * folder = dirname((char *) a_file->filename[i]);
403
+
404
+ if (!(extensions & EXT_COMPATIBILITY)) {
405
+ mmd_prepend_mmd_header(buffer);
406
+ mmd_append_mmd_footer(buffer);
407
+ }
408
+
409
+ if (extensions & EXT_TRANSCLUDE) {
410
+ mmd_transclude_source(buffer, folder, a_file->filename[i], format, NULL, NULL);
411
+
412
+ // Don't free folder -- owned by dirname
413
+ }
414
+
415
+ // Perform block level CriticMarkup?
416
+ if (extensions & EXT_CRITIC_ACCEPT) {
417
+ mmd_critic_markup_accept(buffer);
418
+ }
419
+
420
+ if (extensions & EXT_CRITIC_REJECT) {
421
+ mmd_critic_markup_reject(buffer);
422
+ }
423
+
424
+ // Increment counter and prepare token pool
425
+ #ifdef kUseObjectPool
426
+ token_pool_init();
427
+ #endif
428
+
429
+ if (a_meta->count > 0) {
430
+ // List metadata keys
431
+ char_result = mmd_string_metadata_keys(buffer->str);
432
+
433
+ if (char_result) {
434
+ fputs(char_result, stdout);
435
+
436
+ free(char_result);
437
+ }
438
+ } else if (a_extract->count > 0) {
439
+ // Extract metadata key
440
+ const char * query = a_extract->sval[0];
441
+
442
+ char_result = mmd_string_metavalue_for_key(buffer->str, query);
443
+
444
+ if (char_result) {
445
+ fputs(char_result, stdout);
446
+ fputc('\n', stdout);
447
+
448
+ free(char_result);
449
+ }
450
+ } else {
451
+ // Regular processing
452
+
453
+ result = mmd_d_string_convert_to_data(buffer, extensions, format, language, folder);
454
+
455
+ if (FORMAT_TEXTBUNDLE == format) {
456
+ unzip_data_to_path(result->str, result->currentStringLength, output_filename);
457
+ } else {
458
+ if (!(output_stream = fopen(output_filename, "wb"))) {
459
+ // Failed to open file
460
+ perror(output_filename);
461
+ } else {
462
+ fwrite(result->str, result->currentStringLength, 1, output_stream);
463
+ fclose(output_stream);
464
+ }
465
+ }
466
+
467
+ d_string_free(result, true);
468
+ }
469
+
470
+ d_string_free(buffer, true);
471
+ free(output_filename);
472
+
473
+ // Decrement counter and drain
474
+ #ifdef kUseObjectPool
475
+ token_pool_drain();
476
+ #endif
477
+ }
478
+ } else {
479
+ if (a_file->count) {
480
+ // We have files to process
481
+ buffer = d_string_new("");
482
+ DString * file_buffer;
483
+
484
+ // Concatenate all input files
485
+ for (int i = 0; i < a_file->count; ++i) {
486
+ file_buffer = scan_file(a_file->filename[i]);
487
+
488
+ if (file_buffer == NULL) {
489
+ fprintf(stderr, "Error reading file '%s'\n", a_file->filename[i]);
490
+ exitcode = 1;
491
+ goto exit;
492
+ }
493
+
494
+ d_string_append_c_array(buffer, file_buffer->str, file_buffer->currentStringLength);
495
+ d_string_free(file_buffer, true);
496
+ }
497
+ } else {
498
+ // Obtain input from stdin
499
+ buffer = stdin_buffer();
500
+ }
501
+
502
+ char * folder = NULL;
503
+
504
+ if (!(extensions & EXT_COMPATIBILITY)) {
505
+ mmd_prepend_mmd_header(buffer);
506
+ mmd_append_mmd_footer(buffer);
507
+ }
508
+
509
+ if ((extensions & EXT_TRANSCLUDE) && (a_file->count == 1)) {
510
+ // Perform transclusion(s)
511
+
512
+ // Convert to absolute path for first file to enable proper path resolution
513
+ #ifdef PATH_MAX
514
+ // If PATH_MAX defined, use it
515
+ char absolute[PATH_MAX + 1];
516
+ realpath(a_file->filename[0], absolute);
517
+ folder = dirname((char *) a_file->filename[0]);
518
+
519
+ mmd_transclude_source(buffer, folder, absolute, format, NULL, NULL);
520
+ #else
521
+ // If undefined, then we *should* be able to use a NULL pointer to allocate
522
+ char * absolute = realpath(a_file->filename[0], NULL);
523
+ folder = dirname((char *) a_file->filename[0]);
524
+ mmd_transclude_source(buffer, folder, absolute, format, NULL, NULL);
525
+ free(absolute);
526
+ #endif
527
+ // Don't free folder -- owned by dirname
528
+ }
529
+
530
+ if (a_file->count == 1) {
531
+ // Must do this after realpath, b/c on some OS's (e.g. Travis-CI linux)
532
+ // this truncates a_file->filename[0]
533
+ folder = dirname((char *) a_file->filename[0]);
534
+ }
535
+
536
+ // Perform block level CriticMarkup?
537
+ if (extensions & EXT_CRITIC_ACCEPT) {
538
+ mmd_critic_markup_accept(buffer);
539
+ }
540
+
541
+ if (extensions & EXT_CRITIC_REJECT) {
542
+ mmd_critic_markup_reject(buffer);
543
+ }
544
+
545
+ if (a_meta->count > 0) {
546
+ // List metadata keys
547
+ char_result = mmd_string_metadata_keys(buffer->str);
548
+
549
+ if (char_result) {
550
+ fputs(char_result, stdout);
551
+
552
+ free(char_result);
553
+ }
554
+ } else if (a_extract->count > 0) {
555
+ // Extract metadata key
556
+ const char * query = a_extract->sval[0];
557
+
558
+ char_result = mmd_string_metavalue_for_key(buffer->str, query);
559
+
560
+ if (char_result) {
561
+ fputs(char_result, stdout);
562
+ fputc('\n', stdout);
563
+
564
+ free(char_result);
565
+ }
566
+ } else {
567
+ // Regular processing
568
+
569
+ result = mmd_d_string_convert_to_data(buffer, extensions, format, language, folder);
570
+
571
+ // Where does output go?
572
+ if (strcmp(a_o->filename[0], "-") == 0) {
573
+ // direct to stdout
574
+ output_stream = stdout;
575
+ } else if (!(output_stream = fopen(a_o->filename[0], "wb"))) {
576
+ perror(a_o->filename[0]);
577
+ free(result);
578
+ d_string_free(buffer, true);
579
+
580
+ exitcode = 1;
581
+ goto exit;
582
+ }
583
+
584
+ fwrite(result->str, result->currentStringLength, 1, output_stream);
585
+
586
+ if (output_stream != stdout) {
587
+ fclose(output_stream);
588
+ }
589
+
590
+ d_string_free(result, true);
591
+ }
592
+
593
+ d_string_free(buffer, true);
594
+ }
595
+
596
+
597
+ exit:
598
+
599
+ #ifdef kUseObjectPool
600
+ // Decrement counter and clean up token pool
601
+ token_pool_drain();
602
+
603
+ token_pool_free();
604
+ #endif
605
+
606
+ exit2:
607
+
608
+ // Clean up after argtable
609
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
610
+ return exitcode;
611
+ }
612
+
data/ext/mmd/memoir.c CHANGED
@@ -102,7 +102,10 @@ void mmd_export_token_memoir(DString * out, const char * source, token * t, scra
102
102
  d_string_append_c_array(out, &source[t->child->next->start], temp_token->start - t->child->next->start);
103
103
  scratch->padded = 1;
104
104
  } else {
105
- d_string_append_c_array(out, &source[t->child->start + t->child->len], t->start + t->len - t->child->next->start);
105
+ if (t->child->next) {
106
+ d_string_append_c_array(out, &source[t->child->start + t->child->len], t->start + t->len - t->child->next->start);
107
+ }
108
+
106
109
  scratch->padded = 0;
107
110
  }
108
111
  }