multimarkdown 4.5.0.r1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }