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,17 @@
1
+ #ifndef RTF_PARSER_H
2
+ #define RTF_PARSER_H
3
+
4
+ #include "parser.h"
5
+ #include "writer.h"
6
+
7
+ void begin_rtf_output(GString *out, node* list, scratch_pad *scratch);
8
+ void end_rtf_output(GString *out, node* list, scratch_pad *scratch);
9
+ void print_rtf_node_tree(GString *out, node *list, scratch_pad *scratch);
10
+ void print_rtf_node(GString *out, node *n, scratch_pad *scratch);
11
+ void print_rtf_localized_typography(GString *out, int character, scratch_pad *scratch);
12
+ void print_rtf_string(GString *out, char *str, scratch_pad *scratch);
13
+ void print_rtf_code_string(GString *out, char *str, scratch_pad *scratch);
14
+ void print_rtf_endnotes(GString *out, scratch_pad *scratch);
15
+ void pad_rtf(GString *out, int pad, scratch_pad *scratch);
16
+
17
+ #endif
@@ -0,0 +1,56 @@
1
+ /*
2
+ * public domain strtok_r() by Charlie Gordon
3
+ *
4
+ * from comp.lang.c 9/14/2007
5
+ *
6
+ * http://groups.google.com/group/comp.lang.c/msg/2ab1ecbb86646684
7
+ *
8
+ * (Declaration that it's public domain):
9
+ * http://groups.google.com/group/comp.lang.c/msg/7c7b39328fefab9c
10
+ */
11
+
12
+ /* This file is only included since MINGW doesn't have strtok_r, so I can't
13
+ compile for Windows without this */
14
+
15
+ /* Also, fixed by Fletcher T. Penney --- added the "return NULL" when *nextp == NULL */
16
+
17
+ /* This fix is also in the public domain */
18
+
19
+ #include "strtok.h"
20
+
21
+ char* strtok_r(
22
+ char *str,
23
+ const char *delim,
24
+ char **nextp)
25
+ {
26
+ char *ret;
27
+
28
+ if (str == NULL)
29
+ {
30
+ str = *nextp;
31
+ }
32
+
33
+ if (str == NULL) {
34
+ return NULL;
35
+ }
36
+
37
+ str += strspn(str, delim);
38
+
39
+ if (*str == '\0')
40
+ {
41
+ return NULL;
42
+ }
43
+
44
+ ret = str;
45
+
46
+ str += strcspn(str, delim);
47
+
48
+ if (*str)
49
+ {
50
+ *str++ = '\0';
51
+ }
52
+
53
+ *nextp = str;
54
+
55
+ return ret;
56
+ }
@@ -0,0 +1,9 @@
1
+ /* This file is only included since MINGW doesn't have strtok_r, so I can't
2
+ compile for Windows without this */
3
+
4
+ #include <string.h>
5
+
6
+ char* strtok_r(
7
+ char *str,
8
+ const char *delim,
9
+ char **nextp);
@@ -0,0 +1,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,11 @@
1
+ #ifndef TEXT_PARSER_H
2
+ #define TEXT_PARSER_H
3
+
4
+ #include "parser.h"
5
+ #include "writer.h"
6
+
7
+ void print_text_node_tree(GString *out, node *list, scratch_pad *scratch);
8
+ void print_text_node(GString *out, node *n, scratch_pad *scratch);
9
+
10
+
11
+ #endif
@@ -0,0 +1,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
+ }