mmd-ruby 5.2.0.1

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 (59) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +78 -0
  3. data/MultiMarkdown-5/src/GLibFacade.c +310 -0
  4. data/MultiMarkdown-5/src/GLibFacade.h +100 -0
  5. data/MultiMarkdown-5/src/beamer.c +182 -0
  6. data/MultiMarkdown-5/src/beamer.h +11 -0
  7. data/MultiMarkdown-5/src/critic.c +117 -0
  8. data/MultiMarkdown-5/src/critic.h +15 -0
  9. data/MultiMarkdown-5/src/glib.h +11 -0
  10. data/MultiMarkdown-5/src/html.c +1171 -0
  11. data/MultiMarkdown-5/src/html.h +14 -0
  12. data/MultiMarkdown-5/src/latex.c +1234 -0
  13. data/MultiMarkdown-5/src/latex.h +16 -0
  14. data/MultiMarkdown-5/src/libMultiMarkdown.h +257 -0
  15. data/MultiMarkdown-5/src/lyx.c +2269 -0
  16. data/MultiMarkdown-5/src/lyx.h +37 -0
  17. data/MultiMarkdown-5/src/lyxbeamer.c +265 -0
  18. data/MultiMarkdown-5/src/lyxbeamer.h +11 -0
  19. data/MultiMarkdown-5/src/memoir.c +80 -0
  20. data/MultiMarkdown-5/src/memoir.h +10 -0
  21. data/MultiMarkdown-5/src/multimarkdown.c +559 -0
  22. data/MultiMarkdown-5/src/odf.c +1241 -0
  23. data/MultiMarkdown-5/src/odf.h +18 -0
  24. data/MultiMarkdown-5/src/opml.c +189 -0
  25. data/MultiMarkdown-5/src/opml.h +15 -0
  26. data/MultiMarkdown-5/src/parse_utilities.c +912 -0
  27. data/MultiMarkdown-5/src/parser.c +17341 -0
  28. data/MultiMarkdown-5/src/parser.h +190 -0
  29. data/MultiMarkdown-5/src/rng.c +117 -0
  30. data/MultiMarkdown-5/src/rtf.c +665 -0
  31. data/MultiMarkdown-5/src/rtf.h +17 -0
  32. data/MultiMarkdown-5/src/strtok.c +56 -0
  33. data/MultiMarkdown-5/src/strtok.h +9 -0
  34. data/MultiMarkdown-5/src/text.c +56 -0
  35. data/MultiMarkdown-5/src/text.h +11 -0
  36. data/MultiMarkdown-5/src/toc.c +157 -0
  37. data/MultiMarkdown-5/src/toc.h +15 -0
  38. data/MultiMarkdown-5/src/transclude.c +335 -0
  39. data/MultiMarkdown-5/src/transclude.h +28 -0
  40. data/MultiMarkdown-5/src/version.h +59 -0
  41. data/MultiMarkdown-5/src/writer.c +767 -0
  42. data/MultiMarkdown-5/src/writer.h +38 -0
  43. data/README.md +77 -0
  44. data/Rakefile +88 -0
  45. data/bin/mmd-ruby +123 -0
  46. data/ext/extconf.h +3 -0
  47. data/ext/extconf.rb +10 -0
  48. data/ext/multimarkdown.c +133 -0
  49. data/lib/mmd-jekyll.rb +19 -0
  50. data/lib/mmd-ruby.rb +1 -0
  51. data/lib/mmd.rb +1 -0
  52. data/lib/multimarkdown-ruby.rb +1 -0
  53. data/lib/multimarkdown.bundle +0 -0
  54. data/lib/multimarkdown.rb +69 -0
  55. data/lib/multimarkdown/version.rb +6 -0
  56. data/mmd-ruby.gemspec +37 -0
  57. data/test/extensions_test.rb +174 -0
  58. data/test/multimarkdown_test.rb +77 -0
  59. metadata +120 -0
@@ -0,0 +1,17 @@
1
+ #ifndef RTF_PARSER_H
2
+ #define RTF_PARSER_H
3
+
4
+ #include "parser.h"
5
+ #include "writer.h"
6
+
7
+ void begin_rtf_output(GString *out, node* list, scratch_pad *scratch);
8
+ void end_rtf_output(GString *out, node* list, scratch_pad *scratch);
9
+ void print_rtf_node_tree(GString *out, node *list, scratch_pad *scratch);
10
+ void print_rtf_node(GString *out, node *n, scratch_pad *scratch);
11
+ void print_rtf_localized_typography(GString *out, int character, scratch_pad *scratch);
12
+ void print_rtf_string(GString *out, char *str, scratch_pad *scratch);
13
+ void print_rtf_code_string(GString *out, char *str, scratch_pad *scratch);
14
+ void print_rtf_endnotes(GString *out, scratch_pad *scratch);
15
+ void pad_rtf(GString *out, int pad, scratch_pad *scratch);
16
+
17
+ #endif
@@ -0,0 +1,56 @@
1
+ /*
2
+ * public domain strtok_r() by Charlie Gordon
3
+ *
4
+ * from comp.lang.c 9/14/2007
5
+ *
6
+ * http://groups.google.com/group/comp.lang.c/msg/2ab1ecbb86646684
7
+ *
8
+ * (Declaration that it's public domain):
9
+ * http://groups.google.com/group/comp.lang.c/msg/7c7b39328fefab9c
10
+ */
11
+
12
+ /* This file is only included since MINGW doesn't have strtok_r, so I can't
13
+ compile for Windows without this */
14
+
15
+ /* Also, fixed by Fletcher T. Penney --- added the "return NULL" when *nextp == NULL */
16
+
17
+ /* This fix is also in the public domain */
18
+
19
+ #include "strtok.h"
20
+
21
+ char* strtok_r(
22
+ char *str,
23
+ const char *delim,
24
+ char **nextp)
25
+ {
26
+ char *ret;
27
+
28
+ if (str == NULL)
29
+ {
30
+ str = *nextp;
31
+ }
32
+
33
+ if (str == NULL) {
34
+ return NULL;
35
+ }
36
+
37
+ str += strspn(str, delim);
38
+
39
+ if (*str == '\0')
40
+ {
41
+ return NULL;
42
+ }
43
+
44
+ ret = str;
45
+
46
+ str += strcspn(str, delim);
47
+
48
+ if (*str)
49
+ {
50
+ *str++ = '\0';
51
+ }
52
+
53
+ *nextp = str;
54
+
55
+ return ret;
56
+ }
@@ -0,0 +1,9 @@
1
+ /* This file is only included since MINGW doesn't have strtok_r, so I can't
2
+ compile for Windows without this */
3
+
4
+ #include <string.h>
5
+
6
+ char* strtok_r(
7
+ char *str,
8
+ const char *delim,
9
+ char **nextp);
@@ -0,0 +1,56 @@
1
+ /*
2
+
3
+ test.c -- plain text writer function as an example.
4
+ Recreates the input source.
5
+
6
+ (c) 2013-2016 Fletcher T. Penney (http://fletcherpenney.net/).
7
+
8
+ This program is free software; you can redistribute it and/or modify
9
+ it under the terms of the GNU General Public License or the MIT
10
+ license. See LICENSE for details.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+
18
+ WARNING -- Not complete and not intended for use
19
+
20
+ */
21
+
22
+ #include "text.h"
23
+
24
+
25
+ /* print_text_node_tree -- convert node tree to plain text */
26
+ void print_text_node_tree(GString *out, node *list, scratch_pad *scratch) {
27
+ while (list != NULL) {
28
+ print_text_node(out, list, scratch);
29
+ list = list->next;
30
+ }
31
+ }
32
+
33
+ /* print_text_node -- convert given node to plain text and append */
34
+ void print_text_node(GString *out, node *n, scratch_pad *scratch) {
35
+ switch (n->key) {
36
+ case STR:
37
+ g_string_append_printf(out,"%s",n->str);
38
+ break;
39
+ case METADATA:
40
+ print_text_node_tree(out,n->children,scratch);
41
+ break;
42
+ case METAKEY:
43
+ g_string_append_printf(out,"%s:\t",n->str);
44
+ print_text_node(out,n->children,scratch);
45
+ break;
46
+ case METAVALUE:
47
+ g_string_append_printf(out,"%s",n->str);
48
+ pad(out,1, scratch);
49
+ break;
50
+ case FOOTER:
51
+ break;
52
+ default:
53
+ fprintf(stderr, "print_text_node encountered unknown node key = %d\n",n->key);
54
+ exit(EXIT_FAILURE);
55
+ }
56
+ }
@@ -0,0 +1,11 @@
1
+ #ifndef TEXT_PARSER_H
2
+ #define TEXT_PARSER_H
3
+
4
+ #include "parser.h"
5
+ #include "writer.h"
6
+
7
+ void print_text_node_tree(GString *out, node *list, scratch_pad *scratch);
8
+ void print_text_node(GString *out, node *n, scratch_pad *scratch);
9
+
10
+
11
+ #endif
@@ -0,0 +1,157 @@
1
+ /*
2
+
3
+ toc.c -- Table of contents
4
+
5
+ (c) 2013-2016 Fletcher T. Penney (http://fletcherpenney.net/).
6
+
7
+ This program is free software; you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License or the MIT
9
+ license. See LICENSE for details.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ #include "toc.h"
19
+
20
+
21
+ /* print_toc_node_tree -- convert node tree to MultiMarkdown */
22
+ void print_toc_node_tree(GString *out, node *list, scratch_pad *scratch) {
23
+ #ifdef DEBUG_ON
24
+ fprintf(stderr, "print_toc_node_tree\n");
25
+ #endif
26
+ int lev;
27
+ while (list != NULL) {
28
+ if (list->key == HEADINGSECTION) {
29
+ lev = list->children->key;
30
+
31
+ print_toc_section_and_children(out, list, scratch);
32
+
33
+ while ((list->next != NULL) && (list->next->key == HEADINGSECTION)
34
+ && (list->next->children->key > lev)) {
35
+ list = list->next;
36
+ }
37
+ } else {
38
+ print_toc_node(out, list, scratch);
39
+ }
40
+ list = list->next;
41
+ }
42
+ }
43
+
44
+ /* print_toc_section_and_children -- we want to stay inside the outline structure */
45
+ void print_toc_section_and_children(GString *out, node *list, scratch_pad *scratch) {
46
+ #ifdef DEBUG_ON
47
+ fprintf(stderr, "print_toc_section_and_children: %d\n",list->key);
48
+ #endif
49
+ int lev = list->children->key;
50
+
51
+ /* print current section (parent) */
52
+ print_toc_node(out, list, scratch);
53
+
54
+ scratch->toc_level ++;
55
+
56
+ /* check for child nodes */
57
+ while ((list->next != NULL) && (list->next->key == HEADINGSECTION) && (list->next->children->key > lev)) {
58
+ /* next item is also a HEADINGSECTION and is a child */
59
+ if (list->next->children->key - lev == 1)
60
+ print_toc_section_and_children(out, list->next, scratch);
61
+ list = list->next;
62
+ }
63
+
64
+ scratch->toc_level --;
65
+ }
66
+
67
+ /* print_toc_node -- convert given node to MultiMarkdown and append */
68
+ void print_toc_node(GString *out, node *n, scratch_pad *scratch) {
69
+ char *temp;
70
+ int i;
71
+
72
+ #ifdef DEBUG_ON
73
+ fprintf(stderr, "print_toc_node: %d\n",n->key);
74
+ #endif
75
+ switch (n->key) {
76
+ case HEADINGSECTION:
77
+ /* Need to handle "nesting" properly */
78
+ for (i = 0; i < scratch->toc_level; ++i)
79
+ {
80
+ g_string_append_printf(out, "\t");
81
+ }
82
+ g_string_append_printf(out, "* ");
83
+
84
+ /* Print header */
85
+ print_toc_node(out, n->children, scratch);
86
+
87
+ break;
88
+ case H1: case H2: case H3: case H4: case H5: case H6:
89
+ if ((n->children != NULL) && (n->children->key == AUTOLABEL)) {
90
+ temp = label_from_string(n->children->str);
91
+ /* use label for header since one was specified (MMD)*/
92
+ g_string_append_printf(out, "[");
93
+ print_toc_node_tree(out, n->children, scratch);
94
+ g_string_append_printf(out, "][%s]\n", temp);
95
+ } else {
96
+ temp = label_from_node_tree(n->children);
97
+ g_string_append_printf(out, "[");
98
+ print_toc_node_tree(out, n->children, scratch);
99
+ g_string_append_printf(out, "][%s]\n", temp);
100
+ }
101
+ free(temp);
102
+ break;
103
+ case STR:
104
+ print_toc_string(out, n->str);
105
+ break;
106
+ case EMPH:
107
+ g_string_append_printf(out, "*");
108
+ print_toc_node_tree(out, n->children, scratch);
109
+ g_string_append_printf(out, "*");
110
+ break;
111
+ case STRONG:
112
+ g_string_append_printf(out, "**");
113
+ print_toc_node_tree(out, n->children, scratch);
114
+ g_string_append_printf(out, "**");
115
+ break;
116
+ case SPACE:
117
+ g_string_append_printf(out, "%s", n->str);
118
+ break;
119
+ case LINK:
120
+ print_toc_node_tree(out, n->children, scratch);
121
+ break;
122
+ case HTML:
123
+ break;
124
+ case LINKREFERENCE:
125
+ break;
126
+ case AUTOLABEL:
127
+ break;
128
+ case VARIABLE:
129
+ g_string_append_printf(out, "[%%%s]",n->str);
130
+ break;
131
+ case LIST:
132
+ print_toc_node_tree(out, n->children, scratch);
133
+ break;
134
+ default: fprintf(stderr, "print_toc_node encountered unknown node key = %d\n",n->key);
135
+ break;
136
+ }
137
+ #ifdef DEBUG_ON
138
+ fprintf(stderr, "finish print_toc_node: %d\n", n->key);
139
+ #endif
140
+ }
141
+
142
+ /* print_toc_string - print string, escaping for MultiMarkdown */
143
+ void print_toc_string(GString *out, char *str) {
144
+ while (*str != '\0') {
145
+ switch (*str) {
146
+ case '[':
147
+ g_string_append_printf(out, "\\[");
148
+ break;
149
+ case ']':
150
+ g_string_append_printf(out, "\\]");
151
+ break;
152
+ default:
153
+ g_string_append_c(out, *str);
154
+ }
155
+ str++;
156
+ }
157
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef TOC_PARSER_H
2
+ #define TOC_PARSER_H
3
+
4
+ #include "parser.h"
5
+ #include "writer.h"
6
+
7
+ void begin_toc_output(GString *out, node* list, scratch_pad *scratch);
8
+ void print_toc_node_tree(GString *out, node *list, scratch_pad *scratch);
9
+ void print_toc_node(GString *out, node *n, scratch_pad *scratch);
10
+ void print_toc_section_and_children(GString *out, node *list, scratch_pad *scratch);
11
+ void end_toc_output(GString *out, node* list, scratch_pad *scratch);
12
+ void print_toc_string(GString *out, char *str);
13
+
14
+
15
+ #endif
@@ -0,0 +1,335 @@
1
+ /*
2
+
3
+ transclude.c -- miscellaneous support functions
4
+
5
+ (c) 2013 Fletcher T. Penney (http://fletcherpenney.net/).
6
+
7
+ This program is free software; you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License or the MIT
9
+ license. See LICENSE for details.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ #include "transclude.h"
19
+ #include "parser.h"
20
+ #if defined(__WIN32)
21
+ #include <windows.h>
22
+ #endif
23
+
24
+
25
+ /* Windows can use either `\` or `/` as a separator -- thanks to t-beckmann on github
26
+ for suggesting a fix for this. */
27
+
28
+ bool is_separator(char c) {
29
+ #if defined(__WIN32)
30
+ return c == '\\' || c == '/';
31
+ #else
32
+ return c == '/';
33
+ #endif
34
+ }
35
+
36
+ /* Combine directory and filename to create a full path */
37
+ char * path_from_dir_base(char *dir, char *base) {
38
+ #if defined(__WIN32)
39
+ char sep = '\\';
40
+ #else
41
+ char sep = '/';
42
+ #endif
43
+ GString *path = NULL;
44
+ char *result;
45
+
46
+ if ((base != NULL) && (is_separator(base[0]))) {
47
+ path = g_string_new(base);
48
+ } else {
49
+ path = g_string_new(dir);
50
+
51
+ /* Ensure that folder ends in "/" */
52
+ if (!is_separator(path->str[strlen(path->str)-1]) ) {
53
+ g_string_append_c(path, sep);
54
+ }
55
+
56
+ g_string_append_printf(path, "%s", base);
57
+ }
58
+
59
+ result = path->str;
60
+ g_string_free(path, false);
61
+
62
+ return result;
63
+ }
64
+
65
+ /* Separate filename and directory from a full path */
66
+ /* See http://stackoverflow.com/questions/1575278/function-to-split-a-filepath-into-path-and-file */
67
+ void split_path_file(char** dir, char** file, char *path) {
68
+ char *slash = path, *next;
69
+ #if defined(__WIN32)
70
+ const char sep[] = "\\/"; // Windows allows either variant
71
+ #else
72
+ const char sep[] = "/";
73
+ #endif
74
+
75
+ while ((next = strpbrk(slash + 1, sep))) slash = next;
76
+ if (path != slash) slash++;
77
+ *dir = my_strndup(path, slash - path);
78
+ *file = strdup(slash);
79
+ }
80
+
81
+ /* Return pointer to beginning of text without metadata */
82
+ /* NOTE: This is not a new string, and does not need to be freed separately */
83
+ char * source_without_metadata(char * source, unsigned long extensions ) {
84
+ char *result;
85
+
86
+ if (has_metadata(source, extensions)) {
87
+ /* If we have metadata, then return just the body */
88
+ /* TODO: This could miss YAML Metadata that does not contain
89
+ blank line afterwards */
90
+ result = strstr(source, "\n\n");
91
+
92
+ if (result != NULL)
93
+ return result + 2;
94
+ }
95
+
96
+ /* No metadata, so return original pointer */
97
+
98
+ /* But check for UTF-8 BOM and skip if present */
99
+ if (strncmp(source, "\xef\xbb\xbf",3) == 0)
100
+ return source + 3;
101
+
102
+ return source;
103
+ }
104
+
105
+ /* Given a GString containing MMD source, and optional base directory,
106
+ substitute transclusion references in the source
107
+
108
+ Pass the path to the current folder if available -- should be a full path.
109
+
110
+ Keep track of what we're parsing to prevent recursion using stack. */
111
+ void transclude_source(GString *source, char *basedir, char *stack, int output_format, GString *manifest) {
112
+ char *base = NULL;
113
+ char *path = NULL;
114
+ char *start;
115
+ char *stop;
116
+ char *temp;
117
+ int curchar;
118
+ size_t pos;
119
+ char real[1000];
120
+ FILE *input;
121
+ long offset;
122
+
123
+ if (basedir == NULL) {
124
+ base = strdup("");
125
+ } else {
126
+ base = strdup(basedir);
127
+ }
128
+
129
+ GString *folder = NULL;
130
+ GString *filename = NULL;
131
+ GString *filebuffer = NULL;
132
+ GString *stackstring = NULL;
133
+
134
+ path = strdup(base);
135
+
136
+ /* Look for override folder inside document */
137
+ if (has_metadata(source->str, 0x000000)) {
138
+ char *meta = extract_metadata_value(source->str, 0x000000, "transcludebase");
139
+ if (meta != NULL) {
140
+ free(path);
141
+ path = path_from_dir_base(base, meta);
142
+ free(meta);
143
+ }
144
+ }
145
+
146
+ if (path == NULL) {
147
+ /* We have nowhere to look, so nothing to do */
148
+ free(base);
149
+ return;
150
+ }
151
+
152
+ folder = g_string_new(path);
153
+
154
+ /* Ensure that folder ends in "/" */
155
+ /* TODO: adjust for windows */
156
+ if (!(folder->str[strlen(folder->str)-1] == '/') ) {
157
+ g_string_append_c(folder, '/');
158
+ }
159
+
160
+ /* fprintf(stderr, "Transclude using '%s'\n", folder->str); */
161
+
162
+ /* Iterate through {{foo.txt}} and substitute contents of file without metadata */
163
+
164
+ start = strstr(source->str,"{{");
165
+
166
+ while (start != NULL) {
167
+ stop = strstr(start,"}}");
168
+ if (stop == NULL)
169
+ break;
170
+
171
+ /* Check that we found something reasonable -- we cap at 1000 characters */
172
+ if (stop - start < 1000) {
173
+ strncpy(real,start+2,stop-start-2);
174
+ real[stop-start-2] = '\0';
175
+
176
+ if (is_separator(real[0])) {
177
+ filename = g_string_new(real);
178
+ } else {
179
+ filename = g_string_new(folder->str);
180
+ g_string_append_printf(filename, "%s",real);
181
+ }
182
+
183
+ if (strcmp(filename->str,"./TOC") == 0) {
184
+ pos = stop - source->str;
185
+ start = strstr(source->str + pos,"{{");
186
+ g_string_free(filename, true);
187
+ continue;
188
+ }
189
+
190
+ /* Adjust for wildcard extensions */
191
+ /* But not if output_format == 0 */
192
+ if (output_format && strncmp(&filename->str[strlen(filename->str) - 2],".*",2) == 0) {
193
+ g_string_erase(filename, strlen(filename->str) - 2, 2);
194
+ if (output_format == TEXT_FORMAT) {
195
+ g_string_append(filename,".txt");
196
+ } else if (output_format == HTML_FORMAT) {
197
+ g_string_append(filename,".html");
198
+ } else if (output_format == LATEX_FORMAT) {
199
+ g_string_append(filename,".tex");
200
+ } else if (output_format == BEAMER_FORMAT) {
201
+ g_string_append(filename,".tex");
202
+ } else if (output_format == MEMOIR_FORMAT) {
203
+ g_string_append(filename,".tex");
204
+ } else if (output_format == ODF_FORMAT) {
205
+ g_string_append(filename,".fodt");
206
+ } else if (output_format == OPML_FORMAT) {
207
+ g_string_append(filename,".opml");
208
+ } else if (output_format == LYX_FORMAT) {
209
+ g_string_append(filename,".lyx");
210
+ } else if (output_format == RTF_FORMAT) {
211
+ g_string_append(filename,".rtf");
212
+ } else {
213
+ /* default extension -- in this case we only have 1 */
214
+ g_string_append(filename,".txt");
215
+ }
216
+ }
217
+
218
+ pos = stop - source->str;
219
+
220
+ /* Add to the manifest (if not already included) */
221
+ if (manifest != NULL) {
222
+ temp = strstr(manifest->str,filename->str);
223
+
224
+ offset = temp - manifest->str;
225
+ if ((temp != NULL) &&
226
+ ((temp == manifest->str) || ((manifest->str)[offset - 1] == '\n')) &&
227
+ (temp[strlen(filename->str)] == '\n') ){
228
+ /* Already on manifest, so don't add again */
229
+ } else {
230
+ g_string_append_printf(manifest,"%s\n",filename->str);
231
+ }
232
+ }
233
+
234
+
235
+ /* Don't reparse ourselves */
236
+ if (stack != NULL) {
237
+ temp = strstr(stack,filename->str);
238
+
239
+ if ((temp != NULL) && (temp[strlen(filename->str)] == '\n')){
240
+ start = strstr(source->str + pos,"{{");
241
+ g_string_free(filename, true);
242
+ continue;
243
+ }
244
+ }
245
+
246
+ /* Read file */
247
+ #if defined(__WIN32)
248
+ int wchars_num = MultiByteToWideChar(CP_UTF8, 0, filename->str, -1, NULL, 0);
249
+ wchar_t wstr[wchars_num];
250
+ MultiByteToWideChar(CP_UTF8, 0, filename->str, -1, wstr, wchars_num);
251
+
252
+ if ((input = _wfopen(wstr, L"r")) != NULL ) {
253
+ #else
254
+ if ((input = fopen(filename->str, "r")) != NULL ) {
255
+ #endif
256
+ filebuffer = g_string_new("");
257
+
258
+ while ((curchar = fgetc(input)) != EOF)
259
+ g_string_append_c(filebuffer, curchar);
260
+
261
+ fclose(input);
262
+
263
+ pos = start - source->str;
264
+
265
+ g_string_erase(source, pos, 2 + stop - start);
266
+
267
+ /* Update stack list */
268
+ stackstring = g_string_new(stack);
269
+ g_string_append_printf(stackstring,"%s\n",filename->str);
270
+
271
+
272
+ /* Recursively transclude files */
273
+
274
+ /* We want to reset the base directory if we enter a subdirectory */
275
+ char * new_dir;
276
+ char * file_only;
277
+ split_path_file(&new_dir, &file_only, filename->str);
278
+
279
+ /* transclude_source(filebuffer, folder->str, stackstring->str, output_format, manifest); */
280
+ transclude_source(filebuffer, new_dir, stackstring->str, output_format, manifest);
281
+
282
+ free(new_dir);
283
+ free(file_only);
284
+
285
+ temp = source_without_metadata(filebuffer->str, 0x000000);
286
+
287
+ g_string_insert(source, pos, temp);
288
+
289
+ pos += strlen(temp);
290
+ g_string_free(filebuffer, true);
291
+ g_string_free(stackstring, true);
292
+ } else {
293
+ /* fprintf(stderr, "error opening file: %s\n", filename->str); */
294
+ }
295
+
296
+ g_string_free(filename, true);
297
+ } else {
298
+ /* Our "match" was > 1000 characters long */
299
+ pos = stop - source->str;
300
+ }
301
+ start = strstr(source->str + pos,"{{");
302
+ }
303
+
304
+ g_string_free(folder, true);
305
+ free(path);
306
+ free(base);
307
+ }
308
+
309
+ /* Allow for a footer to specify files to be appended to the end of the text, and then transcluded.
310
+ Useful for appending a list of footnotes, citations, abbreviations, etc. to each separate file,
311
+ but not including multiple copies when processing the master file. */
312
+ void append_mmd_footer(GString *source) {
313
+ /* Look for mmd_footer metadata */
314
+ if (has_metadata(source->str, 0x000000)) {
315
+ char *meta = extract_metadata_value(source->str, 0x000000, "mmdfooter");
316
+ if (meta != NULL)
317
+ g_string_append_printf(source, "\n\n{{%s}}\n", meta);
318
+ }
319
+ }
320
+
321
+ void prepend_mmd_header(GString *source) {
322
+ /* Same thing, but to be inserted after metadata and before content */
323
+ if (has_metadata(source->str, 0x000000)) {
324
+ char *meta = extract_metadata_value(source->str, 0x000000, "mmdheader");
325
+ if (meta != NULL) {
326
+ char *content = strstr(source->str, "\n\n");
327
+ if (content != NULL) {
328
+ size_t pos = content - source->str;
329
+ g_string_insert_printf(source, pos, "\n\n{{%s}}", meta);
330
+ } else {
331
+ g_string_append_printf(source, "\n\n{{%s}}\n", meta);
332
+ }
333
+ }
334
+ }
335
+ }