multimarkdown 4.5.0.r1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +75 -0
- data/MultiMarkdown-4/GLibFacade.c +294 -0
- data/MultiMarkdown-4/GLibFacade.h +95 -0
- data/MultiMarkdown-4/beamer.c +179 -0
- data/MultiMarkdown-4/beamer.h +11 -0
- data/MultiMarkdown-4/critic.c +111 -0
- data/MultiMarkdown-4/critic.h +15 -0
- data/MultiMarkdown-4/glib.h +11 -0
- data/MultiMarkdown-4/html.c +1060 -0
- data/MultiMarkdown-4/html.h +14 -0
- data/MultiMarkdown-4/latex.c +1137 -0
- data/MultiMarkdown-4/latex.h +16 -0
- data/MultiMarkdown-4/libMultiMarkdown.h +156 -0
- data/MultiMarkdown-4/lyx.c +2163 -0
- data/MultiMarkdown-4/lyx.h +36 -0
- data/MultiMarkdown-4/lyxbeamer.c +267 -0
- data/MultiMarkdown-4/lyxbeamer.h +11 -0
- data/MultiMarkdown-4/memoir.c +79 -0
- data/MultiMarkdown-4/memoir.h +10 -0
- data/MultiMarkdown-4/multimarkdown.c +483 -0
- data/MultiMarkdown-4/odf.c +1201 -0
- data/MultiMarkdown-4/odf.h +18 -0
- data/MultiMarkdown-4/opml.c +188 -0
- data/MultiMarkdown-4/opml.h +15 -0
- data/MultiMarkdown-4/parse_utilities.c +752 -0
- data/MultiMarkdown-4/parser.c +15582 -0
- data/MultiMarkdown-4/parser.h +186 -0
- data/MultiMarkdown-4/rng.c +117 -0
- data/MultiMarkdown-4/rtf.c +648 -0
- data/MultiMarkdown-4/rtf.h +17 -0
- data/MultiMarkdown-4/strtok.c +56 -0
- data/MultiMarkdown-4/strtok.h +9 -0
- data/MultiMarkdown-4/text.c +53 -0
- data/MultiMarkdown-4/text.h +11 -0
- data/MultiMarkdown-4/transclude.c +213 -0
- data/MultiMarkdown-4/transclude.h +26 -0
- data/MultiMarkdown-4/writer.c +576 -0
- data/MultiMarkdown-4/writer.h +34 -0
- data/README.md +70 -0
- data/Rakefile +85 -0
- data/bin/ruby_multi_markdown +128 -0
- data/ext/extconf.h +3 -0
- data/ext/extconf.rb +17 -0
- data/ext/multi_markdown.c +100 -0
- data/lib/multi_markdown.bundle +0 -0
- data/lib/multi_markdown.rb +88 -0
- data/lib/multi_markdown/version.rb +6 -0
- data/lib/multimarkdown.rb +1 -0
- data/multi_markdown.gemspec +37 -0
- data/test/multi_markdown_test.rb +64 -0
- metadata +119 -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,53 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
test.c -- plain text writer function as an example.
|
4
|
+
Recreates the input source.
|
5
|
+
|
6
|
+
(c) 2013 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
|
+
|
19
|
+
#include "text.h"
|
20
|
+
|
21
|
+
|
22
|
+
/* print_text_node_tree -- convert node tree to plain text */
|
23
|
+
void print_text_node_tree(GString *out, node *list, scratch_pad *scratch) {
|
24
|
+
while (list != NULL) {
|
25
|
+
print_text_node(out, list, scratch);
|
26
|
+
list = list->next;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
/* print_text_node -- convert given node to plain text and append */
|
31
|
+
void print_text_node(GString *out, node *n, scratch_pad *scratch) {
|
32
|
+
switch (n->key) {
|
33
|
+
case STR:
|
34
|
+
g_string_append_printf(out,"%s",n->str);
|
35
|
+
break;
|
36
|
+
case METADATA:
|
37
|
+
print_text_node_tree(out,n->children,scratch);
|
38
|
+
break;
|
39
|
+
case METAKEY:
|
40
|
+
g_string_append_printf(out,"%s:\t",n->str);
|
41
|
+
print_text_node(out,n->children,scratch);
|
42
|
+
break;
|
43
|
+
case METAVALUE:
|
44
|
+
g_string_append_printf(out,"%s",n->str);
|
45
|
+
pad(out,1, scratch);
|
46
|
+
break;
|
47
|
+
case FOOTER:
|
48
|
+
break;
|
49
|
+
default:
|
50
|
+
fprintf(stderr, "print_text_node encountered unknown node key = %d\n",n->key);
|
51
|
+
exit(EXIT_FAILURE);
|
52
|
+
}
|
53
|
+
}
|
@@ -0,0 +1,213 @@
|
|
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
|
+
|
21
|
+
|
22
|
+
/* Combine directory and filename to create a full path */
|
23
|
+
char * path_from_dir_base(char *dir, char *base) {
|
24
|
+
#if defined(__WIN32)
|
25
|
+
char sep = '\\';
|
26
|
+
#else
|
27
|
+
char sep = '/';
|
28
|
+
#endif
|
29
|
+
GString *path = NULL;
|
30
|
+
char *result;
|
31
|
+
|
32
|
+
if ((base != NULL) && (base[0] == sep)) {
|
33
|
+
path = g_string_new(base);
|
34
|
+
} else {
|
35
|
+
path = g_string_new(dir);
|
36
|
+
|
37
|
+
/* Ensure that folder ends in "/" */
|
38
|
+
if (!(path->str[strlen(path->str)-1] == sep) ) {
|
39
|
+
g_string_append_c(path, sep);
|
40
|
+
}
|
41
|
+
|
42
|
+
g_string_append_printf(path, "%s", base);
|
43
|
+
}
|
44
|
+
|
45
|
+
result = path->str;
|
46
|
+
g_string_free(path, false);
|
47
|
+
|
48
|
+
return result;
|
49
|
+
}
|
50
|
+
|
51
|
+
/* Return pointer to beginning of text without metadata */
|
52
|
+
char * source_without_metadata(char * source, unsigned long extensions ) {
|
53
|
+
char *result;
|
54
|
+
|
55
|
+
if (has_metadata(source, extensions)) {
|
56
|
+
/* If we have metadata, then return just the body */
|
57
|
+
result = strstr(source, "\n\n");
|
58
|
+
|
59
|
+
if (result != NULL)
|
60
|
+
return result+2;
|
61
|
+
}
|
62
|
+
|
63
|
+
/* No metadata, so return original pointer */
|
64
|
+
return source;
|
65
|
+
}
|
66
|
+
|
67
|
+
/* Given a GString containing MMD source, and optional base directory,
|
68
|
+
substitute transclusion references in the source
|
69
|
+
|
70
|
+
Pass the path to the current folder if available -- should be a full path.
|
71
|
+
|
72
|
+
Keep track of what we're parsing to prevent recursion using stack. */
|
73
|
+
void transclude_source(GString *source, char *basedir, char *stack, int output_format) {
|
74
|
+
char *base = strdup(basedir);
|
75
|
+
char *path = strdup(base);
|
76
|
+
char *start;
|
77
|
+
char *stop;
|
78
|
+
char *temp;
|
79
|
+
int curchar;
|
80
|
+
size_t pos;
|
81
|
+
char real[1000];
|
82
|
+
FILE *input;
|
83
|
+
|
84
|
+
GString *folder = NULL;
|
85
|
+
GString *filename = NULL;
|
86
|
+
GString *filebuffer = NULL;
|
87
|
+
GString *stackstring = NULL;
|
88
|
+
|
89
|
+
/* Change to file directory */
|
90
|
+
if (base == NULL) {
|
91
|
+
base = strdup("");
|
92
|
+
path = strdup(base);
|
93
|
+
}
|
94
|
+
|
95
|
+
/* Look for override folder inside document */
|
96
|
+
if (has_metadata(source->str, 0x000000)) {
|
97
|
+
char *meta = extract_metadata_value(source->str, 0x000000, "transcludebase");
|
98
|
+
if (meta != NULL)
|
99
|
+
path = path_from_dir_base(base, meta);
|
100
|
+
}
|
101
|
+
|
102
|
+
if (path == NULL) {
|
103
|
+
/* We have nowhere to look, so nothing to do */
|
104
|
+
free(path);
|
105
|
+
free(base);
|
106
|
+
return;
|
107
|
+
}
|
108
|
+
|
109
|
+
folder = g_string_new(path);
|
110
|
+
|
111
|
+
/* Ensure that folder ends in "/" */
|
112
|
+
/* TODO: adjust for windows */
|
113
|
+
if (!(folder->str[strlen(folder->str)-1] == '/') ) {
|
114
|
+
g_string_append_c(folder, '/');
|
115
|
+
}
|
116
|
+
|
117
|
+
//fprintf(stderr, "Transclude using '%s'\n", folder->str);
|
118
|
+
|
119
|
+
/* Iterate through {{foo.txt}} and substitute contents of file without metadata */
|
120
|
+
|
121
|
+
start = strstr(source->str,"{{");
|
122
|
+
|
123
|
+
while (start != NULL) {
|
124
|
+
stop = strstr(start,"}}");
|
125
|
+
if (stop == NULL)
|
126
|
+
break;
|
127
|
+
|
128
|
+
// TODO: Need to check that we found something reasonable
|
129
|
+
|
130
|
+
strncpy(real,start+2,stop-start-2);
|
131
|
+
real[stop-start-2] = '\0';
|
132
|
+
|
133
|
+
filename = g_string_new(folder->str);
|
134
|
+
g_string_append_printf(filename, "%s",real);
|
135
|
+
|
136
|
+
/* Adjust for wildcard extensions */
|
137
|
+
if (strncmp(&filename->str[strlen(filename->str) - 2],".*",2) == 0) {
|
138
|
+
g_string_erase(filename, strlen(filename->str) - 2, 2);
|
139
|
+
if (output_format == TEXT_FORMAT) {
|
140
|
+
g_string_append(filename,".txt");
|
141
|
+
} else if (output_format == HTML_FORMAT) {
|
142
|
+
g_string_append(filename,".html");
|
143
|
+
} else if (output_format == LATEX_FORMAT) {
|
144
|
+
g_string_append(filename,".tex");
|
145
|
+
} else if (output_format == BEAMER_FORMAT) {
|
146
|
+
g_string_append(filename,".tex");
|
147
|
+
} else if (output_format == MEMOIR_FORMAT) {
|
148
|
+
g_string_append(filename,".tex");
|
149
|
+
} else if (output_format == ODF_FORMAT) {
|
150
|
+
g_string_append(filename,".fodt");
|
151
|
+
} else if (output_format == OPML_FORMAT) {
|
152
|
+
g_string_append(filename,".opml");
|
153
|
+
} else if (output_format == LYX_FORMAT) {
|
154
|
+
g_string_append(filename,".lyx");
|
155
|
+
} else if (output_format == RTF_FORMAT) {
|
156
|
+
g_string_append(filename,".rtf");
|
157
|
+
} else {
|
158
|
+
/* default extension -- in this case we only have 1 */
|
159
|
+
g_string_append(filename,".txt");
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
pos = stop - source->str;
|
164
|
+
|
165
|
+
/* Don't reparse ourselves */
|
166
|
+
if (stack != NULL) {
|
167
|
+
temp = strstr(stack,filename->str);
|
168
|
+
|
169
|
+
if ((temp != NULL) && (temp[strlen(filename->str)] == '\n')){
|
170
|
+
start = strstr(source->str + pos,"{{");
|
171
|
+
g_string_free(filename, true);
|
172
|
+
continue;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
/* Read file */
|
177
|
+
if ((input = fopen(filename->str, "r")) != NULL ) {
|
178
|
+
filebuffer = g_string_new("");
|
179
|
+
|
180
|
+
while ((curchar = fgetc(input)) != EOF)
|
181
|
+
g_string_append_c(filebuffer, curchar);
|
182
|
+
|
183
|
+
fclose(input);
|
184
|
+
|
185
|
+
pos = start - source->str;
|
186
|
+
|
187
|
+
g_string_erase(source, pos, 2 + stop - start);
|
188
|
+
|
189
|
+
/* Update stack list */
|
190
|
+
stackstring = g_string_new(stack);
|
191
|
+
g_string_append_printf(stackstring,"%s\n",filename->str);
|
192
|
+
|
193
|
+
|
194
|
+
/* Recursively transclude files */
|
195
|
+
transclude_source(filebuffer, folder->str, stackstring->str, output_format);
|
196
|
+
|
197
|
+
temp = source_without_metadata(filebuffer->str, 0x000000);
|
198
|
+
|
199
|
+
g_string_insert(source, pos, temp);
|
200
|
+
|
201
|
+
pos += strlen(temp);
|
202
|
+
g_string_free(filebuffer, true);
|
203
|
+
g_string_free(stackstring, true);
|
204
|
+
}
|
205
|
+
|
206
|
+
start = strstr(source->str + pos,"{{");
|
207
|
+
g_string_free(filename, true);
|
208
|
+
}
|
209
|
+
|
210
|
+
g_string_free(folder, true);
|
211
|
+
free(path);
|
212
|
+
free(base);
|
213
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
transclude.h -- 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 <stdio.h>
|
19
|
+
#include <string.h>
|
20
|
+
#include <stdlib.h>
|
21
|
+
#include <stdbool.h>
|
22
|
+
#include <libgen.h>
|
23
|
+
#include "GLibFacade.h"
|
24
|
+
|
25
|
+
char * source_without_metadata(char * source, unsigned long extensions);
|
26
|
+
void transclude_source(GString *source, char *basedir, char *stack, int format);
|
@@ -0,0 +1,576 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
writer.c -- General routines for converting parse structure to various
|
4
|
+
output formats.
|
5
|
+
|
6
|
+
(c) 2013 Fletcher T. Penney (http://fletcherpenney.net/).
|
7
|
+
|
8
|
+
Derived from peg-multimarkdown, which was forked from peg-markdown,
|
9
|
+
which is (c) 2008 John MacFarlane (jgm at berkeley dot edu), and
|
10
|
+
licensed under GNU GPL or MIT.
|
11
|
+
|
12
|
+
This program is free software; you can redistribute it and/or modify
|
13
|
+
it under the terms of the GNU General Public License or the MIT
|
14
|
+
license. See LICENSE for details.
|
15
|
+
|
16
|
+
This program is distributed in the hope that it will be useful,
|
17
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
19
|
+
GNU General Public License for more details.
|
20
|
+
|
21
|
+
*/
|
22
|
+
|
23
|
+
#include "writer.h"
|
24
|
+
|
25
|
+
/* export_node_tree -- given a tree, export as specified format */
|
26
|
+
char * export_node_tree(node *list, int format, unsigned long extensions) {
|
27
|
+
char *output;
|
28
|
+
GString *out = g_string_new("");
|
29
|
+
scratch_pad *scratch = mk_scratch_pad(extensions);
|
30
|
+
scratch->result_tree = list; /* Pointer to result tree to use later */
|
31
|
+
|
32
|
+
#ifdef DEBUG_ON
|
33
|
+
fprintf(stderr, "export_node_tree\n");
|
34
|
+
#endif
|
35
|
+
|
36
|
+
#ifdef DEBUG_ON
|
37
|
+
fprintf(stderr, "extract_references\n");
|
38
|
+
#endif
|
39
|
+
/* Parse for link, images, etc reference definitions */
|
40
|
+
if ((format != OPML_FORMAT) &&
|
41
|
+
(format != CRITIC_ACCEPT_FORMAT) &&
|
42
|
+
(format != CRITIC_REJECT_FORMAT) &&
|
43
|
+
(format != CRITIC_HTML_HIGHLIGHT_FORMAT))
|
44
|
+
extract_references(list, scratch);
|
45
|
+
|
46
|
+
/* Change our desired format based on metadata */
|
47
|
+
if (format == LATEX_FORMAT)
|
48
|
+
format = find_latex_mode(format, list);
|
49
|
+
|
50
|
+
switch (format) {
|
51
|
+
case TEXT_FORMAT:
|
52
|
+
print_text_node_tree(out, list, scratch);
|
53
|
+
break;
|
54
|
+
case HTML_FORMAT:
|
55
|
+
if (scratch->extensions & EXT_COMPLETE) {
|
56
|
+
g_string_append_printf(out,
|
57
|
+
"<!DOCTYPE html>\n<html>\n<head>\n\t<meta charset=\"utf-8\"/>\n");
|
58
|
+
}
|
59
|
+
#ifdef DEBUG_ON
|
60
|
+
fprintf(stderr, "print_html output\n");
|
61
|
+
#endif
|
62
|
+
print_html_node_tree(out, list, scratch);
|
63
|
+
#ifdef DEBUG_ON
|
64
|
+
fprintf(stderr, "print html endnotes\n");
|
65
|
+
#endif
|
66
|
+
print_html_endnotes(out, scratch);
|
67
|
+
#ifdef DEBUG_ON
|
68
|
+
fprintf(stderr, "finished printing html endnotes\n");
|
69
|
+
#endif
|
70
|
+
if (scratch->extensions & EXT_COMPLETE) {
|
71
|
+
pad(out,2, scratch);
|
72
|
+
g_string_append_printf(out, "</body>\n</html>");
|
73
|
+
}
|
74
|
+
#ifdef DEBUG_ON
|
75
|
+
fprintf(stderr, "closed HTML document\n");
|
76
|
+
#endif
|
77
|
+
break;
|
78
|
+
case LATEX_FORMAT:
|
79
|
+
print_latex_node_tree(out, list, scratch);
|
80
|
+
break;
|
81
|
+
case MEMOIR_FORMAT:
|
82
|
+
print_memoir_node_tree(out, list, scratch);
|
83
|
+
break;
|
84
|
+
case BEAMER_FORMAT:
|
85
|
+
print_beamer_node_tree(out, list, scratch);
|
86
|
+
break;
|
87
|
+
case LYX_FORMAT:
|
88
|
+
perform_lyx_output(out,list,scratch);
|
89
|
+
break;
|
90
|
+
case OPML_FORMAT:
|
91
|
+
#ifdef DEBUG_ON
|
92
|
+
fprintf(stderr, "export OPML\n");
|
93
|
+
#endif
|
94
|
+
begin_opml_output(out, list, scratch);
|
95
|
+
print_opml_node_tree(out, list, scratch);
|
96
|
+
end_opml_output(out, list, scratch);
|
97
|
+
break;
|
98
|
+
case ODF_FORMAT:
|
99
|
+
#ifdef DEBUG_ON
|
100
|
+
fprintf(stderr, "export ODF\n");
|
101
|
+
#endif
|
102
|
+
begin_odf_output(out, list, scratch);
|
103
|
+
print_odf_node_tree(out, list, scratch);
|
104
|
+
end_odf_output(out, list, scratch);
|
105
|
+
break;
|
106
|
+
case RTF_FORMAT:
|
107
|
+
#ifdef DEBUG_ON
|
108
|
+
fprintf(stderr, "export RTF\n");
|
109
|
+
#endif
|
110
|
+
if (!(scratch->extensions & EXT_SNIPPET))
|
111
|
+
begin_rtf_output(out, list, scratch);
|
112
|
+
print_rtf_node_tree(out, list, scratch);
|
113
|
+
if (!(scratch->extensions & EXT_SNIPPET))
|
114
|
+
end_rtf_output(out, list, scratch);
|
115
|
+
break;
|
116
|
+
case CRITIC_ACCEPT_FORMAT:
|
117
|
+
print_critic_accept_node_tree(out, list, scratch);
|
118
|
+
break;
|
119
|
+
case CRITIC_REJECT_FORMAT:
|
120
|
+
print_critic_reject_node_tree(out, list, scratch);
|
121
|
+
break;
|
122
|
+
case CRITIC_HTML_HIGHLIGHT_FORMAT:
|
123
|
+
print_critic_html_highlight_node_tree(out, list, scratch);
|
124
|
+
break;
|
125
|
+
default:
|
126
|
+
fprintf(stderr, "Unknown export format = %d\n",format);
|
127
|
+
exit(EXIT_FAILURE);
|
128
|
+
}
|
129
|
+
|
130
|
+
output = out->str;
|
131
|
+
g_string_free(out, false);
|
132
|
+
free_scratch_pad(scratch);
|
133
|
+
|
134
|
+
#ifdef DEBUG_ON
|
135
|
+
fprintf(stderr, "finish export_node_tree\n");
|
136
|
+
#endif
|
137
|
+
return output;
|
138
|
+
}
|
139
|
+
|
140
|
+
/* extract_references -- go through node tree and find elements we need to reference;
|
141
|
+
e.g. links, images, citations, footnotes
|
142
|
+
Copy them from main parse tree */
|
143
|
+
void extract_references(node *list, scratch_pad *scratch) {
|
144
|
+
node *temp;
|
145
|
+
link_data *l;
|
146
|
+
|
147
|
+
while (list != NULL) {
|
148
|
+
switch (list->key) {
|
149
|
+
case LINKREFERENCE:
|
150
|
+
l = list->link_data;
|
151
|
+
temp = mk_link(list->children, l->label, l->source, l->title, NULL);
|
152
|
+
temp->link_data->attr = copy_node_tree(l->attr);
|
153
|
+
|
154
|
+
/* store copy of link reference */
|
155
|
+
scratch->links = cons(temp, scratch->links);
|
156
|
+
|
157
|
+
break;
|
158
|
+
case NOTESOURCE:
|
159
|
+
case GLOSSARYSOURCE:
|
160
|
+
temp = copy_node(list);
|
161
|
+
scratch->notes = cons(temp, scratch->notes);
|
162
|
+
break;
|
163
|
+
case H1: case H2: case H3: case H4: case H5: case H6:
|
164
|
+
if ((list->children->key != AUTOLABEL) && !(scratch->extensions & EXT_NO_LABELS)
|
165
|
+
&& !(scratch->extensions & EXT_COMPATIBILITY)) {
|
166
|
+
char *label = label_from_node_tree(list->children);
|
167
|
+
|
168
|
+
/* create a label from header */
|
169
|
+
temp = mk_autolink(label);
|
170
|
+
scratch->links = cons(temp, scratch->links);
|
171
|
+
free(label);
|
172
|
+
}
|
173
|
+
break;
|
174
|
+
case TABLE:
|
175
|
+
if (list->children->key != TABLELABEL) {
|
176
|
+
char *label = label_from_node(list->children);
|
177
|
+
|
178
|
+
/* create a label from header */
|
179
|
+
temp = mk_autolink(label);
|
180
|
+
scratch->links = cons(temp, scratch->links);
|
181
|
+
free(label);
|
182
|
+
}
|
183
|
+
|
184
|
+
break;
|
185
|
+
case HEADINGSECTION:
|
186
|
+
case RAW:
|
187
|
+
case LIST:
|
188
|
+
extract_references(list->children, scratch);
|
189
|
+
break;
|
190
|
+
default:
|
191
|
+
break;
|
192
|
+
}
|
193
|
+
list = list->next;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
/* extract_link_data -- given a label, parse the link data and return */
|
198
|
+
link_data * extract_link_data(char *label, scratch_pad *scratch) {
|
199
|
+
char *temp;
|
200
|
+
link_data *d;
|
201
|
+
node *ref = scratch->links;
|
202
|
+
bool debug = 0;
|
203
|
+
|
204
|
+
if (debug)
|
205
|
+
fprintf(stderr, "try to extract link for '%s'\n",label);
|
206
|
+
|
207
|
+
if ((label == NULL) || (strlen(label) == 0))
|
208
|
+
return NULL;
|
209
|
+
|
210
|
+
temp = clean_string(label);
|
211
|
+
|
212
|
+
/* look for label string as is */
|
213
|
+
while (ref != NULL) {
|
214
|
+
if (ref->key == KEY_COUNTER) {
|
215
|
+
ref = ref->next;
|
216
|
+
|
217
|
+
continue;
|
218
|
+
}
|
219
|
+
if (strcmp(ref->link_data->label, temp) == 0) {
|
220
|
+
if (debug)
|
221
|
+
fprintf(stderr,"a:matched %s to %s\n",ref->link_data->label, label);
|
222
|
+
/* matched */
|
223
|
+
d = ref->link_data;
|
224
|
+
d = mk_link_data(d->label, d->source, d->title, d->attr);
|
225
|
+
free(temp);
|
226
|
+
return d;
|
227
|
+
} else {
|
228
|
+
if (debug)
|
229
|
+
fprintf(stderr,"a:did not match %s to %s\n",ref->link_data->label, label);
|
230
|
+
}
|
231
|
+
ref = ref->next;
|
232
|
+
}
|
233
|
+
free(temp);
|
234
|
+
|
235
|
+
/* No match. Check for label()version */
|
236
|
+
|
237
|
+
if (scratch->extensions & EXT_COMPATIBILITY) {
|
238
|
+
/* not in compat mode */
|
239
|
+
return NULL;
|
240
|
+
}
|
241
|
+
temp = label_from_string(label);
|
242
|
+
|
243
|
+
ref = scratch->links;
|
244
|
+
|
245
|
+
while (ref != NULL) {
|
246
|
+
if (ref->key == KEY_COUNTER) {
|
247
|
+
ref = ref->next;
|
248
|
+
|
249
|
+
continue;
|
250
|
+
}
|
251
|
+
if (strcmp(ref->link_data->label, temp) == 0) {
|
252
|
+
if (debug)
|
253
|
+
fprintf(stderr,"b:matched %s to %s\n",ref->link_data->label, label);
|
254
|
+
/* matched */
|
255
|
+
d = ref->link_data;
|
256
|
+
d = mk_link_data(d->label, d->source, d->title, d->attr);
|
257
|
+
free(temp);
|
258
|
+
return d;
|
259
|
+
} else {
|
260
|
+
if (debug)
|
261
|
+
fprintf(stderr,"b:did not match %s to %s\n",ref->link_data->label, label);
|
262
|
+
}
|
263
|
+
ref = ref->next;
|
264
|
+
}
|
265
|
+
free(temp);
|
266
|
+
|
267
|
+
if (debug)
|
268
|
+
fprintf(stderr, "finish extract\n");
|
269
|
+
return NULL;
|
270
|
+
}
|
271
|
+
|
272
|
+
/* pad -- ensure that at least 'x' newlines are at end of output */
|
273
|
+
void pad(GString *out, int num, scratch_pad *scratch) {
|
274
|
+
while (num-- > scratch->padded)
|
275
|
+
g_string_append_c(out, '\n');
|
276
|
+
|
277
|
+
scratch->padded = num;
|
278
|
+
}
|
279
|
+
|
280
|
+
/* note_number_for_label -- given a label to match, determine number to be used*/
|
281
|
+
int note_number_for_label(char *text, scratch_pad *scratch) {
|
282
|
+
node *n = NULL;
|
283
|
+
char *clean;
|
284
|
+
char *label;
|
285
|
+
#ifdef DEBUG_ON
|
286
|
+
fprintf(stderr, "find note number for: %s\n",text);
|
287
|
+
#endif
|
288
|
+
|
289
|
+
if ((text == NULL) || (strlen(text) == 0))
|
290
|
+
return 0; /* Nothing to find */
|
291
|
+
|
292
|
+
clean = clean_string(text);
|
293
|
+
label = label_from_string(clean);
|
294
|
+
|
295
|
+
/* have we used this note already? */
|
296
|
+
|
297
|
+
/* look for label string as is */
|
298
|
+
n = node_matching_label(clean, scratch->used_notes);
|
299
|
+
|
300
|
+
/* if not, look in reserve queue */
|
301
|
+
if (n == NULL) {
|
302
|
+
n = node_matching_label(clean, scratch->notes);
|
303
|
+
|
304
|
+
if (n != NULL) {
|
305
|
+
/* move to used queue */
|
306
|
+
move_note_to_used(n, scratch);
|
307
|
+
}
|
308
|
+
}
|
309
|
+
|
310
|
+
/* Check label version */
|
311
|
+
if (n == NULL)
|
312
|
+
n = node_matching_label(label, scratch->used_notes);
|
313
|
+
|
314
|
+
if (n == NULL) {
|
315
|
+
n = node_matching_label(label, scratch->notes);
|
316
|
+
|
317
|
+
if (n != NULL) {
|
318
|
+
/* move to used queue */
|
319
|
+
move_note_to_used(n, scratch);
|
320
|
+
}
|
321
|
+
}
|
322
|
+
|
323
|
+
/* CAN recursively drill down to start counter at 0 and ++ */
|
324
|
+
/* if found, move to used queue and return the number */
|
325
|
+
|
326
|
+
free(label);
|
327
|
+
free(clean);
|
328
|
+
if (n != NULL)
|
329
|
+
return count_node_from_end(n);
|
330
|
+
else
|
331
|
+
return 0;
|
332
|
+
}
|
333
|
+
|
334
|
+
/* note_number_for_node -- given a note reference to match, determine number to be used*/
|
335
|
+
int note_number_for_node(node *ref, scratch_pad *scratch) {
|
336
|
+
char *label = ref->str;
|
337
|
+
node *n = NULL;
|
338
|
+
int num = 0;
|
339
|
+
|
340
|
+
num = note_number_for_label(label, scratch);
|
341
|
+
|
342
|
+
if (num > 0)
|
343
|
+
return num;
|
344
|
+
|
345
|
+
/* None found, so treat as inline note */
|
346
|
+
n = ref->children;
|
347
|
+
use_inline_footnote(ref, scratch);
|
348
|
+
|
349
|
+
return count_node_from_end(n);
|
350
|
+
}
|
351
|
+
|
352
|
+
|
353
|
+
/* node_matching_label -- given a string, return the node matching the string */
|
354
|
+
node * node_matching_label(char *label, node *n) {
|
355
|
+
while (n != NULL) {
|
356
|
+
if (n->key == KEY_COUNTER) {
|
357
|
+
n = n->next;
|
358
|
+
continue;
|
359
|
+
}
|
360
|
+
if (strcmp(n->str, label) == 0) {
|
361
|
+
return n;
|
362
|
+
}
|
363
|
+
n = n->next;
|
364
|
+
}
|
365
|
+
|
366
|
+
return NULL;
|
367
|
+
}
|
368
|
+
|
369
|
+
/* since lists are stored in reverse order, need to count from end */
|
370
|
+
int count_node_from_end(node *n) {
|
371
|
+
if (n->next == NULL) {
|
372
|
+
if (n->key == KEY_COUNTER)
|
373
|
+
return 0;
|
374
|
+
return 1; /* reserve 0 for not found */
|
375
|
+
}
|
376
|
+
return (count_node_from_end(n->next) + 1);
|
377
|
+
}
|
378
|
+
|
379
|
+
/* since lists are stored in reverse order, need to count from end
|
380
|
+
Only count cites (not footnotes) */
|
381
|
+
int cite_count_node_from_end(node *n) {
|
382
|
+
if (n->next == NULL) {
|
383
|
+
/* we're the last node */
|
384
|
+
if (n->key == CITATIONSOURCE)
|
385
|
+
return 1;
|
386
|
+
return 0; /* reserve 0 for not found */
|
387
|
+
}
|
388
|
+
if (n->key == CITATIONSOURCE) {
|
389
|
+
return (cite_count_node_from_end(n->next) + 1);
|
390
|
+
} else {
|
391
|
+
return (cite_count_node_from_end(n->next));
|
392
|
+
}
|
393
|
+
}
|
394
|
+
|
395
|
+
/* node_for_count -- given a number, get that node */
|
396
|
+
node * node_for_count(node *n, int count) {
|
397
|
+
if (n == NULL)
|
398
|
+
return NULL;
|
399
|
+
|
400
|
+
int total = count_node_from_end(n);
|
401
|
+
|
402
|
+
if (count > total)
|
403
|
+
return NULL;
|
404
|
+
|
405
|
+
if (count == total)
|
406
|
+
return n;
|
407
|
+
|
408
|
+
while (total > count) {
|
409
|
+
n = n->next;
|
410
|
+
if (n == NULL)
|
411
|
+
return NULL;
|
412
|
+
total--;
|
413
|
+
}
|
414
|
+
|
415
|
+
return n;
|
416
|
+
}
|
417
|
+
|
418
|
+
/* move_note_to_used -- snip note from ->notes and move to used_notes */
|
419
|
+
void move_note_to_used(node *list, scratch_pad *scratch) {
|
420
|
+
node * n = scratch->notes;
|
421
|
+
node * last = NULL;
|
422
|
+
|
423
|
+
while (n != NULL) {
|
424
|
+
if (n == list) {
|
425
|
+
if (last != NULL) {
|
426
|
+
last->next = n->next;
|
427
|
+
} else {
|
428
|
+
scratch->notes = n->next;
|
429
|
+
}
|
430
|
+
scratch->used_notes = cons(n, scratch->used_notes);
|
431
|
+
return;
|
432
|
+
}
|
433
|
+
last = n;
|
434
|
+
n = n->next;
|
435
|
+
}
|
436
|
+
}
|
437
|
+
|
438
|
+
/* use_inline_footnote -- create a new note definition from inline footnote */
|
439
|
+
void use_inline_footnote(node *ref, scratch_pad *scratch) {
|
440
|
+
scratch->used_notes = cons(ref->children, scratch->used_notes);
|
441
|
+
ref->children = NULL;
|
442
|
+
}
|
443
|
+
|
444
|
+
/* find attribute, if present */
|
445
|
+
node * node_for_attribute(char *querystring, node *list) {
|
446
|
+
#ifdef DEBUG_ON
|
447
|
+
fprintf(stderr, "start node_for_attribute\n");
|
448
|
+
#endif
|
449
|
+
node *step = NULL;
|
450
|
+
step = list;
|
451
|
+
char *query;
|
452
|
+
|
453
|
+
if (querystring == NULL)
|
454
|
+
return NULL;
|
455
|
+
|
456
|
+
query = label_from_string(querystring);
|
457
|
+
#ifdef DEBUG_ON
|
458
|
+
fprintf(stderr, "node_for_attribute 2: '%s'\n",query);
|
459
|
+
#endif
|
460
|
+
|
461
|
+
while (step != NULL) {
|
462
|
+
if ((step->str != NULL) && (strcmp(step->str,query) == 0)) {
|
463
|
+
free(query);
|
464
|
+
#ifdef DEBUG_ON
|
465
|
+
fprintf(stderr, "matched node_for_attribute\n");
|
466
|
+
#endif
|
467
|
+
return step;
|
468
|
+
}
|
469
|
+
#ifdef DEBUG_ON
|
470
|
+
fprintf(stderr, "'%s' doesn't match '%s'\n",query,step->str);
|
471
|
+
if (step->next == NULL)
|
472
|
+
fprintf(stderr, "no next node\n");
|
473
|
+
#endif
|
474
|
+
step = step->next;
|
475
|
+
}
|
476
|
+
free(query);
|
477
|
+
#ifdef DEBUG_ON
|
478
|
+
fprintf(stderr, "stop node_for_attribute\n");
|
479
|
+
#endif
|
480
|
+
return NULL;
|
481
|
+
}
|
482
|
+
|
483
|
+
|
484
|
+
/* convert attribute to dimensions suitable for LaTeX or ODF */
|
485
|
+
/* returns c string that needs to be freed */
|
486
|
+
char * dimension_for_attribute(char *querystring, node *list) {
|
487
|
+
#ifdef DEBUG_ON
|
488
|
+
fprintf(stderr, "start dimension_for_attribute\n");
|
489
|
+
#endif
|
490
|
+
node *attribute;
|
491
|
+
char *dimension;
|
492
|
+
char *ptr;
|
493
|
+
int i;
|
494
|
+
char *upper;
|
495
|
+
GString *result;
|
496
|
+
|
497
|
+
attribute = node_for_attribute(querystring, list);
|
498
|
+
if (attribute == NULL) return NULL;
|
499
|
+
#ifdef DEBUG_ON
|
500
|
+
fprintf(stderr, "a\n");
|
501
|
+
#endif
|
502
|
+
|
503
|
+
dimension = strdup(attribute->children->str);
|
504
|
+
upper = strdup(attribute->children->str);
|
505
|
+
|
506
|
+
for(i = 0; dimension[ i ]; i++)
|
507
|
+
dimension[i] = tolower(dimension[ i ]);
|
508
|
+
|
509
|
+
for(i = 0; upper[ i ]; i++)
|
510
|
+
upper[i] = toupper(upper[ i ]);
|
511
|
+
#ifdef DEBUG_ON
|
512
|
+
fprintf(stderr, "b\n");
|
513
|
+
#endif
|
514
|
+
|
515
|
+
if (strstr(dimension, "px")) {
|
516
|
+
ptr = strstr(dimension,"px");
|
517
|
+
ptr[0] = '\0';
|
518
|
+
strcat(ptr,"pt");
|
519
|
+
}
|
520
|
+
|
521
|
+
result = g_string_new(dimension);
|
522
|
+
|
523
|
+
if ((strcmp(dimension,upper) == 0) && (dimension[strlen(dimension) -1] != '%')) {
|
524
|
+
/* no units */
|
525
|
+
g_string_append_printf(result, "pt");
|
526
|
+
}
|
527
|
+
|
528
|
+
free(upper);
|
529
|
+
free(dimension);
|
530
|
+
|
531
|
+
dimension = result->str;
|
532
|
+
g_string_free(result, false);
|
533
|
+
#ifdef DEBUG_ON
|
534
|
+
fprintf(stderr, "finish dimension_for_attribute\n");
|
535
|
+
#endif
|
536
|
+
return(dimension);
|
537
|
+
}
|
538
|
+
|
539
|
+
|
540
|
+
/* Load available info for a link */
|
541
|
+
link_data * load_link_data(node *n, scratch_pad *scratch) {
|
542
|
+
link_data *r = NULL;
|
543
|
+
GString *temp_str = NULL;
|
544
|
+
char *temp;
|
545
|
+
|
546
|
+
r = mk_link_data(n->link_data->label, n->link_data->source, n->link_data->title, n->link_data->attr);
|
547
|
+
|
548
|
+
/* Do we have proper info? */
|
549
|
+
if ((r->label == NULL) &&
|
550
|
+
(r->source == NULL)) {
|
551
|
+
/* we seem to be a [foo][] style link */
|
552
|
+
/* so load a label */
|
553
|
+
temp_str = g_string_new("");
|
554
|
+
print_raw_node_tree(temp_str, n->children);
|
555
|
+
r->label = temp_str->str;
|
556
|
+
g_string_free(temp_str, FALSE);
|
557
|
+
}
|
558
|
+
/* Load data by reference */
|
559
|
+
if (r->label != NULL) {
|
560
|
+
temp = strdup(r->label);
|
561
|
+
|
562
|
+
r->attr = NULL;
|
563
|
+
free_link_data(r);
|
564
|
+
|
565
|
+
r = extract_link_data(temp, scratch);
|
566
|
+
if (r == NULL) {
|
567
|
+
/* return NULL since no definition found */
|
568
|
+
|
569
|
+
free(temp);
|
570
|
+
return NULL;
|
571
|
+
}
|
572
|
+
free(temp);
|
573
|
+
}
|
574
|
+
|
575
|
+
return r;
|
576
|
+
}
|