multimarkdown 4.5.0.r1

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 (51) hide show
  1. data/LICENSE +75 -0
  2. data/MultiMarkdown-4/GLibFacade.c +294 -0
  3. data/MultiMarkdown-4/GLibFacade.h +95 -0
  4. data/MultiMarkdown-4/beamer.c +179 -0
  5. data/MultiMarkdown-4/beamer.h +11 -0
  6. data/MultiMarkdown-4/critic.c +111 -0
  7. data/MultiMarkdown-4/critic.h +15 -0
  8. data/MultiMarkdown-4/glib.h +11 -0
  9. data/MultiMarkdown-4/html.c +1060 -0
  10. data/MultiMarkdown-4/html.h +14 -0
  11. data/MultiMarkdown-4/latex.c +1137 -0
  12. data/MultiMarkdown-4/latex.h +16 -0
  13. data/MultiMarkdown-4/libMultiMarkdown.h +156 -0
  14. data/MultiMarkdown-4/lyx.c +2163 -0
  15. data/MultiMarkdown-4/lyx.h +36 -0
  16. data/MultiMarkdown-4/lyxbeamer.c +267 -0
  17. data/MultiMarkdown-4/lyxbeamer.h +11 -0
  18. data/MultiMarkdown-4/memoir.c +79 -0
  19. data/MultiMarkdown-4/memoir.h +10 -0
  20. data/MultiMarkdown-4/multimarkdown.c +483 -0
  21. data/MultiMarkdown-4/odf.c +1201 -0
  22. data/MultiMarkdown-4/odf.h +18 -0
  23. data/MultiMarkdown-4/opml.c +188 -0
  24. data/MultiMarkdown-4/opml.h +15 -0
  25. data/MultiMarkdown-4/parse_utilities.c +752 -0
  26. data/MultiMarkdown-4/parser.c +15582 -0
  27. data/MultiMarkdown-4/parser.h +186 -0
  28. data/MultiMarkdown-4/rng.c +117 -0
  29. data/MultiMarkdown-4/rtf.c +648 -0
  30. data/MultiMarkdown-4/rtf.h +17 -0
  31. data/MultiMarkdown-4/strtok.c +56 -0
  32. data/MultiMarkdown-4/strtok.h +9 -0
  33. data/MultiMarkdown-4/text.c +53 -0
  34. data/MultiMarkdown-4/text.h +11 -0
  35. data/MultiMarkdown-4/transclude.c +213 -0
  36. data/MultiMarkdown-4/transclude.h +26 -0
  37. data/MultiMarkdown-4/writer.c +576 -0
  38. data/MultiMarkdown-4/writer.h +34 -0
  39. data/README.md +70 -0
  40. data/Rakefile +85 -0
  41. data/bin/ruby_multi_markdown +128 -0
  42. data/ext/extconf.h +3 -0
  43. data/ext/extconf.rb +17 -0
  44. data/ext/multi_markdown.c +100 -0
  45. data/lib/multi_markdown.bundle +0 -0
  46. data/lib/multi_markdown.rb +88 -0
  47. data/lib/multi_markdown/version.rb +6 -0
  48. data/lib/multimarkdown.rb +1 -0
  49. data/multi_markdown.gemspec +37 -0
  50. data/test/multi_markdown_test.rb +64 -0
  51. metadata +119 -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,188 @@
1
+ /*
2
+
3
+ opml.c -- OPML add-on to LaTeX writer
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 "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
+ print_opml_string(out, n->str);
139
+ break;
140
+ case SPACE:
141
+ print_opml_string(out, n->str);
142
+ break;
143
+ case STR:
144
+ print_opml_string(out, n->str);
145
+ break;
146
+ case LINEBREAK:
147
+ g_string_append_printf(out, " &#10;");
148
+ break;
149
+ case PLAIN:
150
+ print_opml_node_tree(out, n->children, scratch);
151
+ if ((n->next != NULL) && (n->next->key == PLAIN)) {
152
+ g_string_append_printf(out, "&#10;");
153
+ }
154
+ break;
155
+ default:
156
+ fprintf(stderr, "print_opml_node encountered unknown element key = %d\n", n->key);
157
+ exit(EXIT_FAILURE);
158
+ }
159
+ #ifdef DEBUG_ON
160
+ fprintf(stderr, "finish print_opml_node: %d\n", n->key);
161
+ #endif
162
+ }
163
+
164
+ /* print_opml_string - print string, escaping for OPML */
165
+ void print_opml_string(GString *out, char *str) {
166
+ while (*str != '\0') {
167
+ switch (*str) {
168
+ case '&':
169
+ g_string_append_printf(out, "&amp;");
170
+ break;
171
+ case '<':
172
+ g_string_append_printf(out, "&lt;");
173
+ break;
174
+ case '>':
175
+ g_string_append_printf(out, "&gt;");
176
+ break;
177
+ case '"':
178
+ g_string_append_printf(out, "&quot;");
179
+ break;
180
+ case '\n': case '\r':
181
+ g_string_append_printf(out, "&#10;");
182
+ break;
183
+ default:
184
+ g_string_append_c(out, *str);
185
+ }
186
+ str++;
187
+ }
188
+ }
@@ -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,752 @@
1
+ /*
2
+
3
+ parse_utilities.c -- miscellaneous support functions
4
+
5
+ (c) 2013 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 <libgen.h>
24
+
25
+ #pragma mark - Parse Tree
26
+
27
+ /* Create a new node in the parse tree */
28
+ node * mk_node(int key) {
29
+ node *result = (node *) malloc(sizeof(node));
30
+ result->key = key;
31
+ result->str = NULL;
32
+ result->children = NULL;
33
+ result->next = NULL;
34
+ result->link_data = NULL;
35
+ return result;
36
+ }
37
+
38
+ /* Create a new node in the parse tree, and store str */
39
+ node * mk_str(char *string) {
40
+ node *result = mk_node(STR);
41
+ assert(string != NULL);
42
+ result->str = strdup(string);
43
+ return result;
44
+ }
45
+
46
+ /* mk_str_from_list - merge list into a STR */
47
+ node * mk_str_from_list(node *list, bool extra_newline) {
48
+ node *result = mk_node(STR);
49
+ node *rev = reverse_list(list);
50
+
51
+ GString *c = concat_string_list(rev);
52
+ if (extra_newline)
53
+ g_string_append(c, "\n");
54
+
55
+ result->str = c->str;
56
+
57
+ g_string_free(c, false);
58
+ return result;
59
+ }
60
+
61
+ node * mk_link(node *text, char *label, char *source, char *title, node *attr) {
62
+ node *result = mk_node(LINK);
63
+ result->link_data = mk_link_data(label, source, title, attr);
64
+ result->children = text;
65
+
66
+ return result;
67
+ }
68
+
69
+ node * mk_autolink(char *text) {
70
+ char *label = label_from_string(text);
71
+ GString *anchor = g_string_new(label);
72
+ g_string_prepend(anchor, "#");
73
+
74
+ node *result = mk_node(LINK);
75
+ result->link_data = mk_link_data(label, anchor->str, NULL, NULL);
76
+
77
+ g_string_free(anchor, TRUE);
78
+ free(label);
79
+ return result;
80
+ }
81
+
82
+ /* concat_string_list - create string from STR's */
83
+ GString * concat_string_list(node *list) {
84
+ GString *result;
85
+ node *next;
86
+ result = g_string_new("");
87
+ while (list != NULL) {
88
+ assert(list->key == STR);
89
+ assert(list->str != NULL);
90
+ g_string_append(result, list->str);
91
+ next = list->next;
92
+ free_node(list);
93
+ list = next;
94
+ }
95
+ return result;
96
+ }
97
+
98
+ /* Create a node that is basically a parent for other elements */
99
+ node * mk_list(int key, node *list) {
100
+ node *result;
101
+ result = mk_node(key);
102
+ result->children = reverse_list(list);
103
+ return result;
104
+ }
105
+
106
+ /* Create a new node with position information */
107
+ node * mk_pos_node(int key, char *string, unsigned int start, unsigned int stop) {
108
+ node *result = mk_node(key);
109
+ if (string != NULL)
110
+ result->str = strdup(string);
111
+
112
+ return result;
113
+ }
114
+
115
+ /* Create a new string node with position information */
116
+ node * mk_pos_str(char *string, unsigned int start, unsigned int stop) {
117
+ node *result = mk_str(string);
118
+
119
+ return result;
120
+ }
121
+
122
+ /* Create a new list node with position information */
123
+ node * mk_pos_list(int key, node *list, unsigned int start, unsigned int stop) {
124
+ node *result = mk_list(key, list);
125
+
126
+ return result;
127
+ }
128
+
129
+ /* free just the current node and children*/
130
+ void free_node(node *n) {
131
+ if (n == NULL)
132
+ return;
133
+
134
+ if (n->str != NULL)
135
+ free(n->str);
136
+ n->str = NULL;
137
+
138
+ free_link_data(n->link_data);
139
+ n->link_data = NULL;
140
+
141
+ if (n->children != NULL) {
142
+ free_node_tree(n->children);
143
+ n->children = NULL;
144
+ }
145
+ free(n);
146
+ }
147
+
148
+ /* free element and it's descendents/siblings */
149
+ void free_node_tree(node *n) {
150
+ node *next = NULL;
151
+
152
+ while (n != NULL) {
153
+ next = n->next;
154
+ free_node(n);
155
+ n = next;
156
+ }
157
+ }
158
+
159
+ /* print element list structure for testing */
160
+ void print_node_tree(node * n) {
161
+ while (n != NULL) {
162
+ fprintf(stderr,"node key: %d\n",n->key);
163
+ if (n->str != NULL)
164
+ fprintf(stderr,"node str: '%s'\n\n",n->str);
165
+
166
+ if (n->children != NULL) {
167
+ print_node_tree(n->children);
168
+ }
169
+ n = n->next;
170
+ }
171
+ }
172
+
173
+ /* cons -- add element to list (it goes to the beginning for performance reasons) */
174
+ node * cons(node *new, node *list) {
175
+ if (new != NULL) {
176
+ new->next = list;
177
+ return new;
178
+ }
179
+ return list;
180
+ }
181
+
182
+ /* reverse -- reverse a list to get it back into proper order */
183
+ node * reverse_list(node *list) {
184
+ node *new = NULL;
185
+ node *next = NULL;
186
+
187
+ while (list != NULL) {
188
+ next = list->next;
189
+ new = cons(list, new);
190
+ list = next;
191
+ }
192
+ return new;
193
+ }
194
+
195
+ /* append_list -- add element to end of list; slower than cons */
196
+ void append_list(node *new, node *list) {
197
+ if (new != NULL) {
198
+ node *step = list;
199
+
200
+ while (step->next != NULL) {
201
+ step = step->next;
202
+ }
203
+ /* new->next = NULL; // This could lose elements and prevents merging lists */
204
+ step->next = new;
205
+ }
206
+ }
207
+
208
+ #pragma mark - Parser Data
209
+
210
+ /* Create parser data - this is where you stash stuff to communicate
211
+ into and out of the parser */
212
+ parser_data * mk_parser_data(char *charbuf, unsigned long extensions) {
213
+ clock_t start = clock();
214
+
215
+ parser_data *result = (parser_data *)malloc(sizeof(parser_data));
216
+ result->extensions = extensions;
217
+ result->charbuf = charbuf;
218
+ result->original = charbuf;
219
+ result->autolabels = NULL;
220
+ result->result = NULL;
221
+
222
+ result->parse_aborted = 0;
223
+ result->stop_time = start + 3 * CLOCKS_PER_SEC; /* 3 second timeout */
224
+
225
+ return result;
226
+ }
227
+
228
+ void free_parser_data(parser_data *data) {
229
+ free_node_tree(data->result);
230
+ free_node_tree(data->autolabels);
231
+ /* don't do this - it's owned by someone else -- free(data->original); */
232
+ data->original = NULL;
233
+ data->charbuf = NULL;
234
+
235
+ free(data);
236
+ }
237
+
238
+ /* mk_scratch_pad -- store stuff here while exporting the result tree */
239
+ void ran_start(long seed);
240
+ scratch_pad * mk_scratch_pad(unsigned long extensions) {
241
+ scratch_pad *result = (scratch_pad *)malloc(sizeof(scratch_pad));
242
+ result->extensions = extensions;
243
+ result->language = 0;
244
+ result->baseheaderlevel = 1;
245
+ result->printing_notes = 0;
246
+ result->notes = mk_node(KEY_COUNTER); /* Need empty need for trimming later */
247
+ result->used_notes = mk_node(KEY_COUNTER);
248
+ result->links = mk_node(KEY_COUNTER);
249
+ result->glossary = mk_node(KEY_COUNTER);
250
+ result->citations = mk_node(KEY_COUNTER);
251
+ result->result_tree = NULL;
252
+ result->padded = 2;
253
+ result->footnote_to_print = 0;
254
+ result->footnote_para_counter = 0;
255
+ result->max_footnote_num = 0;
256
+ result->obfuscate = 0;
257
+ result->no_latex_footnote = 0;
258
+ result->latex_footer = NULL;
259
+ result->odf_list_needs_end_p = FALSE;
260
+ result->odf_para_type = PARA;
261
+ result->cell_type = 0;
262
+
263
+ if (extensions & EXT_RANDOM_FOOT) {
264
+ srand((int)time(NULL));
265
+ result->random_seed_base = rand() % 32000;
266
+ } else {
267
+ srand(1);
268
+ result->random_seed_base = 0;
269
+ }
270
+ ran_start(310952L);
271
+
272
+ result->lyx_para_type = PARA; /* CRC - Simple paragraph */
273
+ result->lyx_level = 0; /* CRC - out outside level */
274
+ result->no_lyx_footnote = 0; /* CRC */
275
+ result->lyx_number_headers = FALSE; /* CRC - default is not to number */
276
+ result->lyx_debug_nest = 0; /* CRC - initialize debug formatting */
277
+ result->lyx_debug_pad = g_string_new(""); /* CRC - initally, no indent */
278
+ result->lyx_definition_hit = TRUE; /* CRC - initialize to have hit it (closed) */
279
+ result->lyx_definition_open = FALSE; /* CRC - don't have an open definition */
280
+ result->lyx_fragile = FALSE; /* CRC - not in a fragile section */
281
+ result->lyx_beamerbullet = FALSE; /* CRC - not in a beamer bullet */
282
+ result->lyx_debug_nest = 0; /* CRC - no nesting yet */
283
+ result->lyx_table_need_line = FALSE; /* CRC - No table yet */
284
+ result->lyx_table_total_rows = 0; /* CRC - No rows */
285
+ result->lyx_table_total_cols = 0; /* CRC - No Columns */
286
+ return result;
287
+ }
288
+
289
+ void free_scratch_pad(scratch_pad *scratch) {
290
+ #ifdef DEBUG_ON
291
+ fprintf(stderr, "free scratch pad\n");
292
+ #endif
293
+
294
+ free_node_tree(scratch->notes);
295
+ free_node_tree(scratch->used_notes);
296
+ free_node_tree(scratch->links);
297
+ free_node_tree(scratch->glossary);
298
+ free_node_tree(scratch->citations);
299
+
300
+ g_string_free(scratch->lyx_debug_pad, true); /* CRC - initally, no indent */
301
+
302
+ if (scratch->latex_footer != NULL)
303
+ free(scratch->latex_footer);
304
+
305
+ free (scratch);
306
+ #ifdef DEBUG_ON
307
+ fprintf(stderr, "finished freeing scratch\n");
308
+ #endif
309
+ }
310
+
311
+ link_data * mk_link_data(char *label, char *source, char *title, node *attr) {
312
+ link_data *result = (link_data *)malloc(sizeof(link_data));
313
+ if (label != NULL)
314
+ result->label = strdup(label);
315
+ else result->label = NULL;
316
+ if (source != NULL)
317
+ result->source = strdup(source);
318
+ else result->source = NULL;
319
+ if (title != NULL)
320
+ result->title = strdup(title);
321
+ else result->title = NULL;
322
+
323
+ result->attr = attr;
324
+
325
+ return result;
326
+ }
327
+
328
+ void free_link_data(link_data *l) {
329
+ if (l == NULL)
330
+ return;
331
+
332
+ free(l->label);
333
+ l->label = NULL;
334
+ free(l->source);
335
+ l->source = NULL;
336
+ free(l->title);
337
+ l->title = NULL;
338
+ free_node_tree(l->attr);
339
+ l->attr = NULL;
340
+
341
+ free(l);
342
+ }
343
+
344
+ /* Check if the specified extension is flagged */
345
+ bool extension(int ext, unsigned long extensions) {
346
+ return (extensions & ext);
347
+ }
348
+
349
+ /* label_from_string -- convert raw string into format suitable for use as label */
350
+ /* As of HTML 5, any character is valid, but no space. Must be HTML escaped.
351
+ But since we also use in LaTeX, ODF, will be a bit more strict.
352
+ It *looks* like UTF-8 characters are ok in ODF, and don't break LaTeX any more than
353
+ having those characters in the original string. Will still limit the ASCII characters
354
+ however, to avoid trouble.
355
+
356
+ NOTE: This is still a bit experimental, and will be removed if it breaks things.
357
+ */
358
+ char *label_from_string(char *str) {
359
+ GString *out = g_string_new("");
360
+ char *label;
361
+ char *next_char;
362
+
363
+ while (*str != '\0') {
364
+ next_char = str;
365
+ next_char++;
366
+ /* Is this a multibyte character? */
367
+ if ((*next_char & 0xC0) == 0x80) {
368
+ g_string_append_c(out, *str);
369
+ while ((*next_char & 0xC0) == 0x80) {
370
+ str++;
371
+ /* fprintf(stderr, "multibyte\n"); */
372
+ g_string_append_c(out, *str);
373
+ next_char++;
374
+ }
375
+ }
376
+
377
+ /* can relax on following characters */
378
+ else if ((*str >= '0' && *str <= '9') || (*str >= 'A' && *str <= 'Z')
379
+ || (*str >= 'a' && *str <= 'z') || (*str == '.') || (*str== '_')
380
+ || (*str== '-') || (*str== ':'))
381
+ {
382
+ g_string_append_c(out, tolower(*str));
383
+ }
384
+ str++;
385
+ }
386
+ label = out->str;
387
+ g_string_free(out, false);
388
+ return label;
389
+ }
390
+
391
+ /* clean_string -- clean up whitespace */
392
+ char * clean_string(char *str) {
393
+ GString *out = g_string_new("");
394
+ char *clean;
395
+ bool block_whitespace = TRUE;
396
+
397
+ while (*str != '\0') {
398
+ if ((*str == '\t') || (*str == ' ') || (*str == '\n') || (*str == '\r')) {
399
+ if (!block_whitespace) {
400
+ g_string_append_c(out, ' ');
401
+ block_whitespace = TRUE;
402
+ }
403
+ } else {
404
+ g_string_append_c(out, *str);
405
+ block_whitespace = FALSE;
406
+ }
407
+ str++;
408
+ }
409
+
410
+ clean = out->str;
411
+ g_string_free(out, false);
412
+ return clean;
413
+ }
414
+
415
+ /* label_from_node_tree -- Returns a null-terminated string,
416
+ which must be freed after use. */
417
+ char *label_from_node_tree(node *n) {
418
+ char *label;
419
+ if (n == NULL)
420
+ return NULL;
421
+
422
+ #ifdef DEBUG_ON
423
+ fprintf(stderr, "\n\nstart label from node_tree\n");
424
+ #endif
425
+ GString *raw = g_string_new("");
426
+ print_raw_node_tree(raw, n);
427
+
428
+ #ifdef DEBUG_ON
429
+ fprintf(stderr, "halfway('%s')\n",raw->str);
430
+ #endif
431
+ label = label_from_string(raw->str);
432
+ g_string_free(raw,true);
433
+ #ifdef DEBUG_ON
434
+ fprintf(stderr, "finish label from node_tree: '%s'\n",label);
435
+ #endif
436
+ return label;
437
+ }
438
+
439
+ /* label_from_node -- Returns a null-terminated string,
440
+ which must be freed after use. */
441
+ char *label_from_node(node *n) {
442
+ char *label;
443
+ char *label2;
444
+ if (n == NULL)
445
+ return NULL;
446
+
447
+ GString *raw = g_string_new("");
448
+ print_raw_node(raw, n);
449
+ label = label_from_string(raw->str);
450
+ label2 = strdup(label);
451
+ free(label);
452
+ g_string_free(raw,true);
453
+ return label2;
454
+ }
455
+
456
+ /* print_raw_node - print an element as original text */
457
+ void print_raw_node(GString *out, node *n) {
458
+ if (n->str != NULL) {
459
+ #ifdef DEBUG_ON
460
+ fprintf(stderr, "print raw node %d: '%s'\n",n->key, n->str);
461
+ #endif
462
+ g_string_append_printf(out, "%s", n->str);
463
+ } else if (n->key == LINK) {
464
+ #ifdef DEBUG_ON
465
+ fprintf(stderr, "print raw node children from link\n");
466
+ #endif
467
+ /* this gets the text */
468
+ print_raw_node_tree(out, n->children);
469
+ /* need the label */
470
+ if ((n->link_data != NULL) && (n->link_data->label != NULL))
471
+ g_string_append_printf(out, "%s",n->link_data->label);
472
+ } else {
473
+ /* All others */
474
+ #ifdef DEBUG_ON
475
+ fprintf(stderr, "print raw node children from %d\n",n->key);
476
+ #endif
477
+ print_raw_node_tree(out, n->children);
478
+ }
479
+ #ifdef DEBUG_ON
480
+ fprintf(stderr, "finish print raw node %d: '%s'\n'%s'\n",n->key, n->str, out->str);
481
+ #endif
482
+ }
483
+
484
+ /* print_raw_node_tree - print a list of elements as original text */
485
+ void print_raw_node_tree(GString *out, node *n) {
486
+ #ifdef DEBUG_ON
487
+ if (n != NULL)
488
+ fprintf(stderr, "start print_raw_node_tree: '%d'\n",n->key);
489
+ #endif
490
+ while (n != NULL) {
491
+ print_raw_node(out, n);
492
+ n = n->next;
493
+ }
494
+ #ifdef DEBUG_ON
495
+ if (n != NULL)
496
+ fprintf(stderr, "finish print_raw_node_tree: '%d'\n",n->key);
497
+ #endif
498
+ }
499
+
500
+ /* preformat_text - allocate and copy text buffer while
501
+ * performing tab expansion. */
502
+ char * preformat_text(char *text) {
503
+ GString *buf;
504
+ char next_char;
505
+ int charstotab;
506
+ char *out;
507
+
508
+ int len = 0;
509
+
510
+ buf = g_string_new("");
511
+
512
+ charstotab = TABSTOP;
513
+ while ((next_char = *text++) != '\0') {
514
+ switch (next_char) {
515
+ case '\t':
516
+ while (charstotab > 0)
517
+ g_string_append_c(buf, ' '), len++, charstotab--;
518
+ break;
519
+ case '\n':
520
+ g_string_append_c(buf, '\n'), len++, charstotab = TABSTOP;
521
+ break;
522
+ default:
523
+ g_string_append_c(buf, next_char), len++, charstotab--;
524
+ }
525
+ if (charstotab == 0)
526
+ charstotab = TABSTOP;
527
+ }
528
+ g_string_append_printf(buf, "\n\n");
529
+ out = buf->str;
530
+ g_string_free(buf,false);
531
+ return(out);
532
+ }
533
+
534
+ /* Don't let us get caught in "infinite" loop;
535
+ 1 means we're ok
536
+ 0 means we're stuck -- abort */
537
+ bool check_timeout(parser_data *data) {
538
+ /* Once we abort, keep aborting */
539
+ if (data->parse_aborted)
540
+ return 0;
541
+ if (clock() > data->stop_time) {
542
+ data->parse_aborted = 1;
543
+ return 0;
544
+ }
545
+ return 1;
546
+ }
547
+
548
+ /* determine whether a certain element is contained within a given list */
549
+ bool tree_contains_key(node *list, int key) {
550
+ node *step = NULL;
551
+
552
+ step = list;
553
+ while ( step != NULL ) {
554
+ if (step->key == key) {
555
+ return TRUE;
556
+ }
557
+ if (step->children != NULL) {
558
+ if (tree_contains_key(step->children, key)) {
559
+ return TRUE;
560
+ }
561
+ }
562
+ step = step->next;
563
+ }
564
+ return FALSE;
565
+ }
566
+
567
+ /* Count number of matches of type */
568
+ int tree_contains_key_count(node *list, int key) {
569
+ node *step = NULL;
570
+ int counter = 0;
571
+
572
+ step = list;
573
+ while ( step != NULL ) {
574
+ if (step->key == key) {
575
+ counter++;
576
+ }
577
+ if (step->children != NULL) {
578
+ counter += tree_contains_key_count(step->children, key);
579
+ }
580
+ step = step->next;
581
+ }
582
+ return counter;
583
+ }
584
+
585
+ /* list all metadata keys, if present */
586
+ char * metadata_keys(node *list) {
587
+ node *step = NULL;
588
+ step = list;
589
+ GString *out = g_string_new("");
590
+ char *temp;
591
+
592
+ while (step != NULL) {
593
+ if (step->key == METADATA) {
594
+ /* search METAKEY children */
595
+ step = step->children;
596
+ while ( step != NULL) {
597
+ temp = label_from_string(step->str);
598
+ g_string_append_printf(out,"%s\n",temp);
599
+ free(temp);
600
+ step = step->next;
601
+ }
602
+
603
+ temp = out->str;
604
+ g_string_free(out, false);
605
+
606
+ return temp;
607
+ }
608
+ step = step->next;
609
+ }
610
+ temp = out->str;
611
+ g_string_free(out, false);
612
+
613
+ return temp;
614
+ }
615
+
616
+ /* find specified metadata key, if present */
617
+ node * metadata_for_key(char *key, node *list) {
618
+ node *step = NULL;
619
+ step = list;
620
+ char *label;
621
+ char *temp;
622
+
623
+ label = label_from_string(key);
624
+
625
+ while (step != NULL) {
626
+ if (step->key == METADATA) {
627
+ /* search METAKEY children */
628
+ step = step->children;
629
+ while ( step != NULL) {
630
+ temp = label_from_string(step->str);
631
+ if (strcmp(temp, label) == 0) {
632
+ free(temp);
633
+ free(label);
634
+ return step;
635
+ }
636
+ free(temp);
637
+ step = step->next;
638
+ }
639
+ free(label);
640
+ return NULL;
641
+ }
642
+ step = step->next;
643
+ }
644
+ free(label);
645
+ return NULL;
646
+ }
647
+
648
+ /* metavalue_for_key -- return the string value for metadata */
649
+ char * metavalue_for_key(char *key, node *list) {
650
+ char *result;
651
+
652
+ list = metadata_for_key(key, list);
653
+
654
+ if (list == NULL)
655
+ return NULL;
656
+
657
+ result = strdup(list->children->str);
658
+ trim_trailing_whitespace(result);
659
+
660
+ return result;
661
+ }
662
+
663
+ /* Trim spaces at end of string */
664
+ void trim_trailing_whitespace(char *str) {
665
+ unsigned long l;
666
+
667
+ if (str == NULL)
668
+ return;
669
+
670
+ l = strlen(str);
671
+
672
+ if (l < 1)
673
+ return;
674
+
675
+ while ( (l > 0) && (( str[l - 1] == ' ' ) ||
676
+ ( str[l - 1] == '\n' ) ||
677
+ ( str[l - 1] == '\r' ) ||
678
+ ( str[l - 1] == '\t' )) ) {
679
+ str[l - 1] = '\0';
680
+ l = strlen(str);
681
+ }
682
+ }
683
+
684
+ /* Trim spaces at end of string */
685
+ void trim_trailing_newlines(char *str) {
686
+ unsigned long l;
687
+
688
+ if (str == NULL)
689
+ return;
690
+
691
+ l = strlen(str);
692
+
693
+ if (l < 1)
694
+ return;
695
+
696
+ while ( (l > 0) && (( str[l - 1] == '\n' ) ||
697
+ ( str[l - 1] == '\r' )) ) {
698
+ str[l - 1] = '\0';
699
+ l = strlen(str);
700
+ }
701
+ }
702
+
703
+ /* Return version */
704
+ char * mmd_version(void) {
705
+ char *result;
706
+ result = strdup(MMD_VERSION);
707
+ return result;
708
+ }
709
+
710
+ void debug_node(node *n) {
711
+ while (n != NULL) {
712
+ fprintf(stderr, "node (%d) '%s'\n",n->key, n->str);
713
+ if (n->children != NULL)
714
+ debug_node(n->children);
715
+ n = n->next;
716
+ }
717
+ }
718
+
719
+ node * copy_node(node *n) {
720
+ if (n == NULL)
721
+ return NULL;
722
+ else {
723
+ node *m = (node *) malloc(sizeof(node));
724
+
725
+ *m = *n;
726
+
727
+ if (n->str != NULL)
728
+ m->str = strdup(n->str);
729
+
730
+ if (n->link_data != NULL) {
731
+ 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));
732
+ }
733
+
734
+ if (n->children != NULL)
735
+ m->children = copy_node_tree(n->children);
736
+
737
+ return m;
738
+ }
739
+ }
740
+
741
+ node * copy_node_tree(node *n) {
742
+ if (n == NULL)
743
+ return NULL;
744
+ else {
745
+ node *m = copy_node(n);
746
+
747
+ if (n->next != NULL)
748
+ m->next = copy_node_tree(n->next);
749
+
750
+ return m;
751
+ }
752
+ }