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,18 @@
1
+ #ifndef ODF_PARSER_H
2
+ #define ODF_PARSER_H
3
+
4
+ #include "parser.h"
5
+ #include "html.h" /* Use some of the HTML routines */
6
+ #include "writer.h"
7
+
8
+ void begin_odf_output(GString *out, node* list, scratch_pad *scratch);
9
+ void print_odf_node_tree(GString *out, node *list, scratch_pad *scratch);
10
+ void print_odf_node(GString *out, node *n, scratch_pad *scratch);
11
+ void print_odf_section_and_children(GString *out, node *list, scratch_pad *scratch);
12
+ void end_odf_output(GString *out, node* list, scratch_pad *scratch);
13
+ void print_odf_string(GString *out, char *str);
14
+ void print_odf_code_string(GString *out, char *str);
15
+ void print_odf_header(GString *out);
16
+ void print_odf_footer(GString *out);
17
+
18
+ #endif
@@ -0,0 +1,189 @@
1
+ /*
2
+
3
+ opml.c -- OPML add-on to LaTeX writer
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 "opml.h"
19
+
20
+ /* begin_opml_output -- handle the initial prefix, if any */
21
+ void begin_opml_output(GString *out, node* list, scratch_pad *scratch) {
22
+ #ifdef DEBUG_ON
23
+ fprintf(stderr, "begin_opml_output\n");
24
+ #endif
25
+ node *title;
26
+
27
+ g_string_append_printf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<opml version=\"1.0\">\n");
28
+
29
+ if (tree_contains_key(list, METAKEY)) {
30
+ title = metadata_for_key("title", list);
31
+ if (title != NULL) {
32
+ char *temp_str;
33
+ GString *temp = g_string_new("");
34
+ g_string_append_printf(out, "<head><title>");
35
+ print_raw_node_tree(temp, title->children);
36
+ temp_str = strdup(temp->str);
37
+ trim_trailing_whitespace(temp_str);
38
+ print_opml_string(out, temp_str);
39
+ g_string_append_printf(out, "</title></head>\n",temp_str);
40
+ free(temp_str);
41
+ g_string_free(temp, true);
42
+ }
43
+ }
44
+ g_string_append_printf(out, "<body>\n");
45
+ }
46
+
47
+ /* end_opml_output -- close the document */
48
+ void end_opml_output(GString *out, node* list, scratch_pad *scratch) {
49
+ #ifdef DEBUG_ON
50
+ fprintf(stderr, "end_opml_output\n");
51
+ #endif
52
+ if (tree_contains_key(list, METAKEY)) {
53
+ g_string_append_printf(out, "<outline text=\"Metadata\">\n");
54
+ print_opml_node_tree(out, list->children, scratch);
55
+ g_string_append_printf(out, "</outline>");
56
+ }
57
+ g_string_append_printf(out, "</body>\n</opml>");
58
+ }
59
+
60
+ /* print_opml_node_tree -- convert node tree to LaTeX */
61
+ void print_opml_node_tree(GString *out, node *list, scratch_pad *scratch) {
62
+ #ifdef DEBUG_ON
63
+ fprintf(stderr, "print_opml_node_tree\n");
64
+ #endif
65
+ int lev;
66
+ while (list != NULL) {
67
+ if (list->key == HEADINGSECTION) {
68
+ lev = list->children->key;
69
+
70
+ print_opml_section_and_children(out, list, scratch);
71
+
72
+ while ((list->next != NULL) && (list->next->key == HEADINGSECTION)
73
+ && (list->next->children->key > lev)) {
74
+ list = list->next;
75
+ }
76
+ } else {
77
+ print_opml_node(out, list, scratch);
78
+ }
79
+ list = list->next;
80
+ }
81
+ }
82
+
83
+ /* print_opml_section_and_children -- we want to stay inside the outline structure */
84
+ void print_opml_section_and_children(GString *out, node *list, scratch_pad *scratch) {
85
+ #ifdef DEBUG_ON
86
+ fprintf(stderr, "print_opml_section_and_children: %d\n",list->key);
87
+ #endif
88
+ int lev = list->children->key;
89
+
90
+ /* print current section (parent) */
91
+ print_opml_node(out, list, scratch);
92
+
93
+ /* check for child nodes */
94
+ while ((list->next != NULL) && (list->next->key == HEADINGSECTION) && (list->next->children->key > lev)) {
95
+ /* next item is also a HEADINGSECTION and is a child */
96
+ if (list->next->children->key - lev == 1)
97
+ print_opml_section_and_children(out, list->next, scratch);
98
+ list = list->next;
99
+ }
100
+ g_string_append_printf(out, "</outline>\n");
101
+ }
102
+
103
+ /* print_opml_node -- convert given node to OPML and append */
104
+ void print_opml_node(GString *out, node *n, scratch_pad *scratch) {
105
+ #ifdef DEBUG_ON
106
+ fprintf(stderr, "print_opml_node: %d\n",n->key);
107
+ #endif
108
+ switch (n->key) {
109
+ case METADATA:
110
+ /* Metadata is present, so will need to be appended later */
111
+ break;
112
+ case METAKEY:
113
+ g_string_append_printf(out, "<outline text=\"");
114
+ print_opml_string(out, n->str);
115
+ g_string_append_printf(out, "\" _note=\"");
116
+ trim_trailing_newlines(n->children->str);
117
+ print_opml_string(out, n->children->str);
118
+ g_string_append_printf(out, "\"/>");
119
+ break;
120
+ case HEADINGSECTION:
121
+ /* Need to handle "nesting" properly */
122
+ g_string_append_printf(out, "<outline ");
123
+
124
+ /* Print header */
125
+ print_opml_node(out, n->children, scratch);
126
+
127
+ /* print remainder of paragraphs as note */
128
+ g_string_append_printf(out, " _note=\"");
129
+ print_opml_node_tree(out, n->children->next, scratch);
130
+ g_string_append_printf(out, "\">");
131
+ break;
132
+ case H1: case H2: case H3: case H4: case H5: case H6:
133
+ g_string_append_printf(out, "text=\"");
134
+ print_opml_string(out, n->str);
135
+ g_string_append_printf(out,"\"");
136
+ break;
137
+ case VERBATIM:
138
+ case VERBATIMFENCE:
139
+ print_opml_string(out, n->str);
140
+ break;
141
+ case SPACE:
142
+ print_opml_string(out, n->str);
143
+ break;
144
+ case STR:
145
+ print_opml_string(out, n->str);
146
+ break;
147
+ case LINEBREAK:
148
+ g_string_append_printf(out, " &#10;");
149
+ break;
150
+ case PLAIN:
151
+ print_opml_node_tree(out, n->children, scratch);
152
+ if ((n->next != NULL) && (n->next->key == PLAIN)) {
153
+ g_string_append_printf(out, "&#10;");
154
+ }
155
+ break;
156
+ default:
157
+ fprintf(stderr, "print_opml_node encountered unknown element key = %d\n", n->key);
158
+ exit(EXIT_FAILURE);
159
+ }
160
+ #ifdef DEBUG_ON
161
+ fprintf(stderr, "finish print_opml_node: %d\n", n->key);
162
+ #endif
163
+ }
164
+
165
+ /* print_opml_string - print string, escaping for OPML */
166
+ void print_opml_string(GString *out, char *str) {
167
+ while (*str != '\0') {
168
+ switch (*str) {
169
+ case '&':
170
+ g_string_append_printf(out, "&amp;");
171
+ break;
172
+ case '<':
173
+ g_string_append_printf(out, "&lt;");
174
+ break;
175
+ case '>':
176
+ g_string_append_printf(out, "&gt;");
177
+ break;
178
+ case '"':
179
+ g_string_append_printf(out, "&quot;");
180
+ break;
181
+ case '\n': case '\r':
182
+ g_string_append_printf(out, "&#10;");
183
+ break;
184
+ default:
185
+ g_string_append_c(out, *str);
186
+ }
187
+ str++;
188
+ }
189
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef OPML_PARSER_H
2
+ #define OPML_PARSER_H
3
+
4
+ #include "parser.h"
5
+ #include "writer.h"
6
+
7
+ void begin_opml_output(GString *out, node* list, scratch_pad *scratch);
8
+ void print_opml_node_tree(GString *out, node *list, scratch_pad *scratch);
9
+ void print_opml_node(GString *out, node *n, scratch_pad *scratch);
10
+ void print_opml_section_and_children(GString *out, node *list, scratch_pad *scratch);
11
+ void end_opml_output(GString *out, node* list, scratch_pad *scratch);
12
+ void print_opml_string(GString *out, char *str);
13
+
14
+
15
+ #endif
@@ -0,0 +1,912 @@
1
+ /*
2
+
3
+ parse_utilities.c -- miscellaneous support functions
4
+
5
+ (c) 2013-2016 Fletcher T. Penney (http://fletcherpenney.net/).
6
+
7
+ Derived from peg-multimarkdown, which was forked from peg-markdown,
8
+ which is (c) 2008 John MacFarlane (jgm at berkeley dot edu), and
9
+ licensed under GNU GPL or MIT.
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of the GNU General Public License or the MIT
13
+ license. See LICENSE for details.
14
+
15
+ This program is distributed in the hope that it will be useful,
16
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ GNU General Public License for more details.
19
+
20
+ */
21
+
22
+ #include "parser.h"
23
+ #include "version.h"
24
+ #include <libgen.h>
25
+
26
+ #pragma mark - Parse Tree
27
+
28
+ /* Create a new node in the parse tree */
29
+ node * mk_node(int key) {
30
+ node *result = (node *) malloc(sizeof(node));
31
+ result->key = key;
32
+ result->str = NULL;
33
+ result->children = NULL;
34
+ result->next = NULL;
35
+ result->link_data = NULL;
36
+ return result;
37
+ }
38
+
39
+ /* Create a new node in the parse tree, and store str */
40
+ node * mk_str(char *string) {
41
+ node *result = mk_node(STR);
42
+ assert(string != NULL);
43
+ result->str = strdup(string);
44
+ return result;
45
+ }
46
+
47
+ /* mk_str_from_list - merge list into a STR */
48
+ node * mk_str_from_list(node *list, bool extra_newline) {
49
+ node *result = mk_node(STR);
50
+ node *rev = reverse_list(list);
51
+
52
+ GString *c = concat_string_list(rev);
53
+ if (extra_newline)
54
+ g_string_append(c, "\n");
55
+
56
+ result->str = c->str;
57
+
58
+ g_string_free(c, false);
59
+ return result;
60
+ }
61
+
62
+ node * mk_link(node *text, char *label, char *source, char *title, node *attr) {
63
+ node *result = mk_node(LINK);
64
+ result->link_data = mk_link_data(label, source, title, attr);
65
+ result->children = text;
66
+
67
+ return result;
68
+ }
69
+
70
+ node * mk_autolink(char *text) {
71
+ char *label = label_from_string(text);
72
+ GString *anchor = g_string_new(label);
73
+ g_string_prepend(anchor, "#");
74
+
75
+ node *result = mk_node(LINK);
76
+ result->link_data = mk_link_data(label, anchor->str, NULL, NULL);
77
+
78
+ g_string_free(anchor, TRUE);
79
+ free(label);
80
+ return result;
81
+ }
82
+
83
+ /* concat_string_list - create string from STR's */
84
+ GString * concat_string_list(node *list) {
85
+ GString *result;
86
+ node *next;
87
+ result = g_string_new("");
88
+ while (list != NULL) {
89
+ assert(list->key == STR);
90
+ assert(list->str != NULL);
91
+ g_string_append(result, list->str);
92
+ next = list->next;
93
+ free_node(list);
94
+ list = next;
95
+ }
96
+ return result;
97
+ }
98
+
99
+ /* Create a node that is basically a parent for other elements */
100
+ node * mk_list(int key, node *list) {
101
+ node *result;
102
+ result = mk_node(key);
103
+ result->children = reverse_list(list);
104
+ return result;
105
+ }
106
+
107
+ /* free just the current node and children*/
108
+ void free_node(node *n) {
109
+ if (n == NULL)
110
+ return;
111
+
112
+ if (n->str != NULL)
113
+ free(n->str);
114
+ n->str = NULL;
115
+
116
+ free_link_data(n->link_data);
117
+ n->link_data = NULL;
118
+
119
+ if (n->children != NULL) {
120
+ free_node_tree(n->children);
121
+ n->children = NULL;
122
+ }
123
+ n->next = NULL;
124
+ free(n);
125
+ }
126
+
127
+ /* free element and it's descendents/siblings */
128
+ void free_node_tree(node *n) {
129
+ node *next = NULL;
130
+
131
+ while (n != NULL) {
132
+ next = n->next;
133
+ free_node(n);
134
+ n = next;
135
+ }
136
+ }
137
+
138
+ /* print element list structure for testing */
139
+ void print_node_tree(node * n) {
140
+ while (n != NULL) {
141
+ fprintf(stderr,"node key: %d\n",n->key);
142
+ if (n->str != NULL)
143
+ fprintf(stderr,"node str: '%s'\n\n",n->str);
144
+
145
+ if (n->children != NULL) {
146
+ print_node_tree(n->children);
147
+ }
148
+ n = n->next;
149
+ }
150
+ }
151
+
152
+ /* cons -- add element to list (it goes to the beginning for performance reasons) */
153
+ node * cons(node *new, node *list) {
154
+ if (new != NULL) {
155
+ new->next = list;
156
+ return new;
157
+ }
158
+ return list;
159
+ }
160
+
161
+ /* reverse -- reverse a list to get it back into proper order */
162
+ node * reverse_list(node *list) {
163
+ node *new = NULL;
164
+ node *next = NULL;
165
+ #ifdef DEBUG_ON
166
+ if ((list != NULL) && (list->str != NULL))
167
+ fprintf(stderr, "reverse_list: '%s'\n",list->str);
168
+ #endif
169
+
170
+ while (list != NULL) {
171
+ next = list->next;
172
+ list->next = NULL;
173
+ new = cons(list, new);
174
+ list = next;
175
+ }
176
+ return new;
177
+ }
178
+
179
+ /* append_list -- add element to end of list; slower than cons */
180
+ void append_list(node *new, node *list) {
181
+
182
+ /* If we append to an empty list... */
183
+ if (list == NULL) {
184
+ list = new;
185
+ return;
186
+ }
187
+
188
+ if (new != NULL) {
189
+ node *step = list;
190
+
191
+
192
+ while (step->next != NULL) {
193
+ step = step->next;
194
+ }
195
+ /* new->next = NULL; // This could lose elements and prevents merging lists */
196
+ step->next = new;
197
+ }
198
+ }
199
+
200
+ #pragma mark - Parser Data
201
+
202
+ /* Create parser data - this is where you stash stuff to communicate
203
+ into and out of the parser */
204
+ parser_data * mk_parser_data(const char *charbuf, unsigned long extensions) {
205
+ clock_t start = clock();
206
+
207
+ parser_data *result = (parser_data *)malloc(sizeof(parser_data));
208
+ result->extensions = extensions;
209
+ result->charbuf = charbuf;
210
+ result->original = charbuf;
211
+ result->autolabels = NULL;
212
+ result->result = NULL;
213
+
214
+ result->parse_aborted = 0;
215
+ result->stop_time = start + 3 * CLOCKS_PER_SEC; /* 3 second timeout */
216
+
217
+ return result;
218
+ }
219
+
220
+ void free_parser_data_preserving_result(parser_data *data) {
221
+ free_node_tree(data->autolabels);
222
+ /* don't do this - it's owned by someone else -- free(data->original); */
223
+ data->original = NULL;
224
+ data->charbuf = NULL;
225
+
226
+ free(data);
227
+ }
228
+
229
+ void free_parser_data(parser_data *data) {
230
+ free_node_tree(data->result);
231
+ free_node_tree(data->autolabels);
232
+ /* don't do this - it's owned by someone else -- free(data->original); */
233
+ data->original = NULL;
234
+ data->charbuf = NULL;
235
+
236
+ free(data);
237
+ }
238
+
239
+ /* mk_scratch_pad -- store stuff here while exporting the result tree */
240
+ void ran_start(long seed);
241
+ scratch_pad * mk_scratch_pad(unsigned long extensions) {
242
+ scratch_pad *result = (scratch_pad *)malloc(sizeof(scratch_pad));
243
+ result->extensions = extensions;
244
+ result->language = 0;
245
+ result->baseheaderlevel = 1;
246
+ result->printing_notes = 0;
247
+ result->notes = mk_node(KEY_COUNTER); /* Need empty need for trimming later */
248
+ result->used_notes = mk_node(KEY_COUNTER);
249
+ result->links = mk_node(KEY_COUNTER);
250
+ result->glossary = mk_node(KEY_COUNTER);
251
+ result->citations = mk_node(KEY_COUNTER);
252
+ result->abbreviations = mk_node(KEY_COUNTER);
253
+ result->result_tree = NULL;
254
+ result->padded = 2;
255
+ result->footnote_to_print = 0;
256
+ result->footnote_para_counter = 0;
257
+ result->max_footnote_num = 0;
258
+ result->obfuscate = 0;
259
+ result->html_footer = NULL;
260
+ result->no_latex_footnote = 0;
261
+ result->latex_footer = NULL;
262
+ result->odf_list_needs_end_p = FALSE;
263
+ result->odf_para_type = PARA;
264
+ result->cell_type = 0;
265
+ result->table_alignment = NULL;
266
+ result->table_column = 0;
267
+ result->header_column = 0;
268
+ result->inside_footnote = 0;
269
+
270
+ if (extensions & EXT_RANDOM_FOOT) {
271
+ srand((int)time(NULL));
272
+ result->random_seed_base = rand() % 32000;
273
+ } else {
274
+ srand(1);
275
+ result->random_seed_base = 0;
276
+ }
277
+ ran_start(310952L);
278
+
279
+ result->lyx_para_type = PARA; /* CRC - Simple paragraph */
280
+ result->lyx_level = 0; /* CRC - out outside level */
281
+ result->no_lyx_footnote = 0; /* CRC */
282
+ result->lyx_number_headers = FALSE; /* CRC - default is not to number */
283
+ result->lyx_debug_nest = 0; /* CRC - initialize debug formatting */
284
+ result->lyx_debug_pad = g_string_new(""); /* CRC - initally, no indent */
285
+ result->lyx_definition_hit = TRUE; /* CRC - initialize to have hit it (closed) */
286
+ result->lyx_definition_open = FALSE; /* CRC - don't have an open definition */
287
+ result->lyx_in_frame = FALSE; /* CRC - not in a frame */
288
+ result->lyx_beamerbullet = FALSE; /* CRC - not in a beamer bullet */
289
+ result->lyx_debug_nest = 0; /* CRC - no nesting yet */
290
+ result->lyx_table_need_line = FALSE; /* CRC - No table yet */
291
+ result->lyx_table_total_rows = 0; /* CRC - No rows */
292
+ result->lyx_table_total_cols = 0; /* CRC - No Columns */
293
+ return result;
294
+ }
295
+
296
+ void free_scratch_pad(scratch_pad *scratch) {
297
+ #ifdef DEBUG_ON
298
+ fprintf(stderr, "free scratch pad\n");
299
+ #endif
300
+
301
+ free_node_tree(scratch->notes);
302
+ free_node_tree(scratch->used_notes);
303
+ free_node_tree(scratch->links);
304
+ free_node_tree(scratch->glossary);
305
+ free_node_tree(scratch->citations);
306
+ free_node_tree(scratch->abbreviations);
307
+
308
+ g_string_free(scratch->lyx_debug_pad, true); /* CRC - initally, no indent */
309
+
310
+ if (scratch->html_footer != NULL)
311
+ free(scratch->html_footer);
312
+
313
+ if (scratch->latex_footer != NULL)
314
+ free(scratch->latex_footer);
315
+
316
+ if (scratch->table_alignment != NULL)
317
+ free(scratch->table_alignment);
318
+
319
+ free (scratch);
320
+ #ifdef DEBUG_ON
321
+ fprintf(stderr, "finished freeing scratch\n");
322
+ #endif
323
+ }
324
+
325
+ link_data * mk_link_data(char *label, char *source, char *title, node *attr) {
326
+ link_data *result = (link_data *)malloc(sizeof(link_data));
327
+ if (label != NULL)
328
+ result->label = strdup(label);
329
+ else result->label = NULL;
330
+ if (source != NULL)
331
+ result->source = strdup(source);
332
+ else result->source = NULL;
333
+ if (title != NULL)
334
+ result->title = strdup(title);
335
+ else result->title = NULL;
336
+
337
+ result->attr = attr;
338
+
339
+ return result;
340
+ }
341
+
342
+ void free_link_data(link_data *l) {
343
+ if (l == NULL)
344
+ return;
345
+
346
+ free(l->label);
347
+ l->label = NULL;
348
+ free(l->source);
349
+ l->source = NULL;
350
+ free(l->title);
351
+ l->title = NULL;
352
+ free_node_tree(l->attr);
353
+ l->attr = NULL;
354
+
355
+ free(l);
356
+ }
357
+
358
+ /* Check if the specified extension is flagged */
359
+ bool extension(int ext, unsigned long extensions) {
360
+ return (extensions & ext);
361
+ }
362
+
363
+ /* label_from_string -- convert raw string into format suitable for use as label */
364
+ /* As of HTML 5, any character is valid, but no space. Must be HTML escaped.
365
+ But since we also use in LaTeX, ODF, will be a bit more strict.
366
+ It *looks* like UTF-8 characters are ok in ODF, and don't break LaTeX any more than
367
+ having those characters in the original string. Will still limit the ASCII characters
368
+ however, to avoid trouble.
369
+
370
+ NOTE: This is still a bit experimental, and will be removed if it breaks things.
371
+ */
372
+ char *label_from_string(char *str) {
373
+ GString *out = g_string_new("");
374
+ char *label;
375
+ char *next_char;
376
+
377
+ while (*str != '\0') {
378
+ next_char = str;
379
+ next_char++;
380
+ /* Is this a multibyte character? */
381
+ if ((*next_char & 0xC0) == 0x80) {
382
+ g_string_append_c(out, *str);
383
+ while ((*next_char & 0xC0) == 0x80) {
384
+ str++;
385
+ /* fprintf(stderr, "multibyte\n"); */
386
+ g_string_append_c(out, *str);
387
+ next_char++;
388
+ }
389
+ }
390
+
391
+ /* can relax on following characters */
392
+ else if ((*str >= '0' && *str <= '9') || (*str >= 'A' && *str <= 'Z')
393
+ || (*str >= 'a' && *str <= 'z') || (*str == '.') || (*str== '_')
394
+ || (*str== '-') || (*str== ':'))
395
+ {
396
+ g_string_append_c(out, tolower(*str));
397
+ }
398
+ str++;
399
+ }
400
+ label = out->str;
401
+ g_string_free(out, false);
402
+ return label;
403
+ }
404
+
405
+ char *ascii_label_from_string(char *str) {
406
+ GString *out = g_string_new("");
407
+ char *label;
408
+ char *next_char;
409
+
410
+ while (*str != '\0') {
411
+ next_char = str;
412
+ next_char++;
413
+ /* Is this a multibyte character? */
414
+ if ((*next_char & 0xC0) == 0x80) {
415
+ while ((*next_char & 0xC0) == 0x80) {
416
+ str++;
417
+ /* fprintf(stderr, "multibyte\n"); */
418
+ next_char++;
419
+ }
420
+ }
421
+
422
+ /* can relax on following characters */
423
+ else if ((*str >= '0' && *str <= '9') || (*str >= 'A' && *str <= 'Z')
424
+ || (*str >= 'a' && *str <= 'z') || (*str == '.') || (*str== '_')
425
+ || (*str== '-') || (*str== ':'))
426
+ {
427
+ g_string_append_c(out, tolower(*str));
428
+ }
429
+ str++;
430
+ }
431
+ label = out->str;
432
+ g_string_free(out, false);
433
+ return label;
434
+ }
435
+
436
+ /* clean_string -- clean up whitespace */
437
+ char * clean_string(char *str) {
438
+ GString *out = g_string_new("");
439
+ char *clean;
440
+ bool block_whitespace = TRUE;
441
+
442
+ while (*str != '\0') {
443
+ if ((*str == '\t') || (*str == ' ') || (*str == '\n') || (*str == '\r')) {
444
+ if (!block_whitespace) {
445
+ g_string_append_c(out, ' ');
446
+ block_whitespace = TRUE;
447
+ }
448
+ } else {
449
+ g_string_append_c(out, *str);
450
+ block_whitespace = FALSE;
451
+ }
452
+ str++;
453
+ }
454
+
455
+ clean = out->str;
456
+ g_string_free(out, false);
457
+ return clean;
458
+ }
459
+
460
+ /* lower_string -- return lower case version of string */
461
+ char * lower_string(char *str) {
462
+ GString *out = g_string_new("");
463
+ char *result;
464
+ char *next_char;
465
+
466
+ while (*str != '\0') {
467
+ next_char = str;
468
+ next_char++;
469
+ /* Is this a multibyte character? */
470
+ if ((*next_char & 0xC0) == 0x80) {
471
+ g_string_append_c(out, *str);
472
+ while ((*next_char & 0xC0) == 0x80) {
473
+ str++;
474
+ /* fprintf(stderr, "multibyte\n"); */
475
+ g_string_append_c(out, *str);
476
+ next_char++;
477
+ }
478
+ }
479
+
480
+ /* can relax on following characters */
481
+ else if (*str >= 'A' && *str <= 'Z')
482
+ {
483
+ g_string_append_c(out, tolower(*str));
484
+ } else {
485
+ g_string_append_c(out, *str);
486
+ }
487
+ str++;
488
+ }
489
+
490
+ result = out->str;
491
+ g_string_free(out, false);
492
+ return result;
493
+ }
494
+
495
+ /* string_from_node_tree -- Returns a null-terminated string,
496
+ which must be freed after use. */
497
+ char * string_from_node_tree(node *n) {
498
+ char *result;
499
+ if (n == NULL)
500
+ return NULL;
501
+
502
+ GString *raw = g_string_new("");
503
+ print_raw_node_tree(raw, n);
504
+
505
+ result = raw->str;
506
+ g_string_free(raw, false);
507
+
508
+ return result;
509
+ }
510
+
511
+ /* label_from_node_tree -- Returns a null-terminated string,
512
+ which must be freed after use. */
513
+ char * label_from_node_tree(node *n) {
514
+ char *label;
515
+ if (n == NULL)
516
+ return NULL;
517
+
518
+ #ifdef DEBUG_ON
519
+ fprintf(stderr, "\n\nstart label from node_tree\n");
520
+ #endif
521
+ GString *raw = g_string_new("");
522
+ print_raw_node_tree(raw, n);
523
+
524
+ #ifdef DEBUG_ON
525
+ fprintf(stderr, "halfway('%s')\n",raw->str);
526
+ #endif
527
+ label = label_from_string(raw->str);
528
+ g_string_free(raw,true);
529
+ #ifdef DEBUG_ON
530
+ fprintf(stderr, "finish label from node_tree: '%s'\n",label);
531
+ #endif
532
+ return label;
533
+ }
534
+
535
+ /* ascii_label_from_node_tree -- Returns a null-terminated string,
536
+ which must be freed after use. */
537
+ char * ascii_label_from_node_tree(node *n) {
538
+ char *label;
539
+ if (n == NULL)
540
+ return NULL;
541
+
542
+ #ifdef DEBUG_ON
543
+ fprintf(stderr, "\n\nstart label from node_tree\n");
544
+ #endif
545
+ GString *raw = g_string_new("");
546
+ print_raw_node_tree(raw, n);
547
+
548
+ #ifdef DEBUG_ON
549
+ fprintf(stderr, "halfway('%s')\n",raw->str);
550
+ #endif
551
+ label = ascii_label_from_string(raw->str);
552
+ g_string_free(raw,true);
553
+ #ifdef DEBUG_ON
554
+ fprintf(stderr, "finish label from node_tree: '%s'\n",label);
555
+ #endif
556
+ return label;
557
+ }
558
+
559
+ /* label_from_node -- Returns a null-terminated string,
560
+ which must be freed after use. */
561
+ char *label_from_node(node *n) {
562
+ char *label;
563
+ char *label2;
564
+ if (n == NULL)
565
+ return NULL;
566
+
567
+ GString *raw = g_string_new("");
568
+ print_raw_node(raw, n);
569
+ label = label_from_string(raw->str);
570
+ label2 = strdup(label);
571
+ free(label);
572
+ g_string_free(raw,true);
573
+ return label2;
574
+ }
575
+
576
+ /* ascii_label_from_node -- Returns a null-terminated string,
577
+ which must be freed after use. */
578
+ char *ascii_label_from_node(node *n) {
579
+ char *label;
580
+ char *label2;
581
+ if (n == NULL)
582
+ return NULL;
583
+
584
+ GString *raw = g_string_new("");
585
+ print_raw_node(raw, n);
586
+ label = ascii_label_from_string(raw->str);
587
+ label2 = strdup(label);
588
+ free(label);
589
+ g_string_free(raw,true);
590
+ return label2;
591
+ }
592
+
593
+ /* print_raw_node - print an element as original text */
594
+ void print_raw_node(GString *out, node *n) {
595
+ if (n->str != NULL) {
596
+ #ifdef DEBUG_ON
597
+ fprintf(stderr, "print raw node %d: '%s'\n",n->key, n->str);
598
+ #endif
599
+ g_string_append_printf(out, "%s", n->str);
600
+ } else if (n->key == LINK) {
601
+ #ifdef DEBUG_ON
602
+ fprintf(stderr, "print raw node children from link\n");
603
+ #endif
604
+ /* this gets the text */
605
+ print_raw_node_tree(out, n->children);
606
+ /* need the label */
607
+ if ((n->link_data != NULL) && (n->link_data->label != NULL))
608
+ g_string_append_printf(out, "%s",n->link_data->label);
609
+ } else {
610
+ /* All others */
611
+ #ifdef DEBUG_ON
612
+ fprintf(stderr, "print raw node children from %d\n",n->key);
613
+ #endif
614
+ print_raw_node_tree(out, n->children);
615
+ }
616
+ #ifdef DEBUG_ON
617
+ fprintf(stderr, "finish print raw node %d: '%s'\n'%s'\n",n->key, n->str, out->str);
618
+ #endif
619
+ }
620
+
621
+ /* print_raw_node_tree - print a list of elements as original text */
622
+ void print_raw_node_tree(GString *out, node *n) {
623
+ #ifdef DEBUG_ON
624
+ if (n != NULL)
625
+ fprintf(stderr, "start print_raw_node_tree: '%d'\n",n->key);
626
+ #endif
627
+ while (n != NULL) {
628
+ print_raw_node(out, n);
629
+ n = n->next;
630
+ }
631
+ #ifdef DEBUG_ON
632
+ if (n != NULL)
633
+ fprintf(stderr, "finish print_raw_node_tree: '%d'\n",n->key);
634
+ #endif
635
+ }
636
+
637
+ /* preformat_text - allocate and copy text buffer while
638
+ * performing tab expansion. */
639
+ char * preformat_text(const char *text) {
640
+ GString *buf;
641
+ char next_char;
642
+ int charstotab;
643
+ char *out;
644
+
645
+ int len = 0;
646
+
647
+ buf = g_string_new("");
648
+
649
+ charstotab = TABSTOP;
650
+ while ((next_char = *text++) != '\0') {
651
+ switch (next_char) {
652
+ case '\t':
653
+ while (charstotab > 0)
654
+ g_string_append_c(buf, ' '), len++, charstotab--;
655
+ break;
656
+ case '\n':
657
+ g_string_append_c(buf, '\n'), len++, charstotab = TABSTOP;
658
+ break;
659
+ default:
660
+ g_string_append_c(buf, next_char), len++, charstotab--;
661
+ }
662
+ if (charstotab == 0)
663
+ charstotab = TABSTOP;
664
+ }
665
+ g_string_append_printf(buf, "\n\n");
666
+ out = buf->str;
667
+ g_string_free(buf,false);
668
+ return(out);
669
+ }
670
+
671
+ /* Don't let us get caught in "infinite" loop;
672
+ 1 means we're ok
673
+ 0 means we're stuck -- abort */
674
+ bool check_timeout(parser_data *data) {
675
+ /* Once we abort, keep aborting */
676
+ if (data->parse_aborted)
677
+ return 0;
678
+ if (clock() > data->stop_time) {
679
+ data->parse_aborted = 1;
680
+ return 0;
681
+ }
682
+ return 1;
683
+ }
684
+
685
+ /* determine whether a certain element is contained within a given list */
686
+ bool tree_contains_key(node *list, int key) {
687
+ node *step = NULL;
688
+
689
+ step = list;
690
+ while ( step != NULL ) {
691
+ if (step->key == key) {
692
+ return TRUE;
693
+ }
694
+ if (step->children != NULL) {
695
+ if (tree_contains_key(step->children, key)) {
696
+ return TRUE;
697
+ }
698
+ }
699
+ step = step->next;
700
+ }
701
+ return FALSE;
702
+ }
703
+
704
+ /* Count number of matches of type */
705
+ int tree_contains_key_count(node *list, int key) {
706
+ node *step = NULL;
707
+ int counter = 0;
708
+
709
+ step = list;
710
+ while ( step != NULL ) {
711
+ if (step->key == key) {
712
+ counter++;
713
+ }
714
+ if (step->children != NULL) {
715
+ counter += tree_contains_key_count(step->children, key);
716
+ }
717
+ step = step->next;
718
+ }
719
+ return counter;
720
+ }
721
+
722
+ /* list all metadata keys, if present */
723
+ char * metadata_keys(node *list) {
724
+ node *step = NULL;
725
+ step = list;
726
+ GString *out = g_string_new("");
727
+ char *temp;
728
+
729
+ while (step != NULL) {
730
+ if (step->key == METADATA) {
731
+ /* search METAKEY children */
732
+ step = step->children;
733
+ while ( step != NULL) {
734
+ temp = label_from_string(step->str);
735
+ g_string_append_printf(out,"%s\n",temp);
736
+ free(temp);
737
+ step = step->next;
738
+ }
739
+
740
+ temp = out->str;
741
+ g_string_free(out, false);
742
+
743
+ return temp;
744
+ }
745
+ step = step->next;
746
+ }
747
+ temp = out->str;
748
+ g_string_free(out, false);
749
+
750
+ return temp;
751
+ }
752
+
753
+ /* find specified metadata key, if present */
754
+ node * metadata_for_key(char *key, node *list) {
755
+ node *step = NULL;
756
+ step = list;
757
+ char *label;
758
+ char *temp;
759
+
760
+ label = label_from_string(key);
761
+
762
+ while (step != NULL) {
763
+ if (step->key == METADATA) {
764
+ /* search METAKEY children */
765
+ step = step->children;
766
+ while ( step != NULL) {
767
+ temp = label_from_string(step->str);
768
+ if (strcmp(temp, label) == 0) {
769
+ free(temp);
770
+ free(label);
771
+ return step;
772
+ }
773
+ free(temp);
774
+ step = step->next;
775
+ }
776
+ free(label);
777
+ return NULL;
778
+ }
779
+ step = step->next;
780
+ }
781
+ free(label);
782
+ return NULL;
783
+ }
784
+
785
+ /* metavalue_for_key -- return the string value for metadata */
786
+ char * metavalue_for_key(char *key, node *list) {
787
+ char *result;
788
+
789
+ list = metadata_for_key(key, list);
790
+
791
+ if (list == NULL)
792
+ return NULL;
793
+
794
+ result = strdup(list->children->str);
795
+ trim_trailing_whitespace(result);
796
+
797
+ return result;
798
+ }
799
+
800
+ /* Trim spaces at end of string */
801
+ void trim_trailing_whitespace(char *str) {
802
+ unsigned long l;
803
+
804
+ if (str == NULL)
805
+ return;
806
+
807
+ l = strlen(str);
808
+
809
+ if (l < 1)
810
+ return;
811
+
812
+ while ( (l > 0) && (( str[l - 1] == ' ' ) ||
813
+ ( str[l - 1] == '\n' ) ||
814
+ ( str[l - 1] == '\r' ) ||
815
+ ( str[l - 1] == '\t' )) ) {
816
+ str[l - 1] = '\0';
817
+ l = strlen(str);
818
+ }
819
+ }
820
+
821
+ /* Trim spaces at end of string */
822
+ void trim_trailing_newlines(char *str) {
823
+ unsigned long l;
824
+
825
+ if (str == NULL)
826
+ return;
827
+
828
+ l = strlen(str);
829
+
830
+ if (l < 1)
831
+ return;
832
+
833
+ while ( (l > 0) && (( str[l - 1] == '\n' ) ||
834
+ ( str[l - 1] == '\r' )) ) {
835
+ str[l - 1] = '\0';
836
+ l = strlen(str);
837
+ }
838
+ }
839
+
840
+ /* Return version */
841
+ char * mmd_version(void) {
842
+ char *result;
843
+ result = strdup(MULTIMARKDOWN_VERSION);
844
+ return result;
845
+ }
846
+
847
+ void debug_node(node *n) {
848
+ if (n != NULL) {
849
+ fprintf(stderr, "node (%d) '%s'\n",n->key, n->str);
850
+ if (n->children != NULL)
851
+ debug_node_tree(n->children);
852
+ }
853
+ }
854
+
855
+ void debug_node_tree(node *n) {
856
+ while (n != NULL) {
857
+ fprintf(stderr, "node (%d) '%s'\n",n->key, n->str);
858
+ if (n->children != NULL)
859
+ debug_node_tree(n->children);
860
+ n = n->next;
861
+ }
862
+ }
863
+
864
+ node * copy_node(node *n) {
865
+ if (n == NULL)
866
+ return NULL;
867
+ else {
868
+ node *m = (node *) malloc(sizeof(node));
869
+
870
+ *m = *n;
871
+
872
+ if (n->str != NULL)
873
+ m->str = strdup(n->str);
874
+
875
+ if (n->link_data != NULL) {
876
+ m->link_data = mk_link_data(n->link_data->label, n->link_data->source, n->link_data->title, copy_node_tree(n->link_data->attr));
877
+ }
878
+
879
+ if (n->children != NULL)
880
+ m->children = copy_node_tree(n->children);
881
+
882
+ return m;
883
+ }
884
+ }
885
+
886
+ node * copy_node_tree(node *n) {
887
+ if (n == NULL)
888
+ return NULL;
889
+ else {
890
+ node *m = copy_node(n);
891
+
892
+ if (n->next != NULL)
893
+ m->next = copy_node_tree(n->next);
894
+
895
+ return m;
896
+ }
897
+ }
898
+
899
+ char * my_strndup(const char * source, size_t n) {
900
+ size_t len = strlen(source);
901
+ char * result;
902
+
903
+ if (n < len)
904
+ len = n;
905
+
906
+ result = malloc(len + 1);
907
+
908
+ memcpy(result, source, len);
909
+ result[len] = '\0';
910
+
911
+ return result;
912
+ }