mirror of
https://github.com/fletcher/MultiMarkdown-6.git
synced 2024-10-04 10:37:08 +03:00
1947 lines
67 KiB
C
1947 lines
67 KiB
C
/**
|
||
|
||
MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
|
||
|
||
@file odf.c
|
||
|
||
@brief Convert token tree to Flat OpenDocument (ODF/FODT) output
|
||
|
||
|
||
@author Fletcher T. Penney
|
||
@bug
|
||
|
||
**/
|
||
|
||
/*
|
||
|
||
Copyright © 2016 - 2017 Fletcher T. Penney.
|
||
|
||
|
||
The `MultiMarkdown 6` project is released under the MIT License..
|
||
|
||
GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
|
||
|
||
https://github.com/fletcher/MultiMarkdown-4/
|
||
|
||
MMD 4 is released under both the MIT License and GPL.
|
||
|
||
|
||
CuTest is released under the zlib/libpng license. See CuTest.c for the
|
||
text of the license.
|
||
|
||
|
||
## The MIT License ##
|
||
|
||
Permission is hereby granted, free of charge, to any person obtaining
|
||
a copy of this software and associated documentation files (the
|
||
"Software"), to deal in the Software without restriction, including
|
||
without limitation the rights to use, copy, modify, merge, publish,
|
||
distribute, sublicense, and/or sell copies of the Software, and to
|
||
permit persons to whom the Software is furnished to do so, subject to
|
||
the following conditions:
|
||
|
||
The above copyright notice and this permission notice shall be
|
||
included in all copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
||
|
||
*/
|
||
|
||
|
||
#include <ctype.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
#include "char.h"
|
||
#include "i18n.h"
|
||
#include "odf.h"
|
||
#include "parser.h"
|
||
#include "scanners.h"
|
||
|
||
#define print(x) d_string_append(out, x)
|
||
#define print_const(x) d_string_append_c_array(out, x, sizeof(x) - 1)
|
||
#define print_char(x) d_string_append_c(out, x)
|
||
#define printf(...) d_string_append_printf(out, __VA_ARGS__)
|
||
#define print_token(t) d_string_append_c_array(out, &(source[t->start]), t->len)
|
||
#define print_localized(x) mmd_print_localized_char_odf(out, x, scratch)
|
||
|
||
|
||
void mmd_print_char_odf(DString * out, char c) {
|
||
switch (c) {
|
||
case '"':
|
||
print_const(""");
|
||
break;
|
||
case '&':
|
||
print_const("&");
|
||
break;
|
||
case '<':
|
||
print_const("<");
|
||
break;
|
||
case '>':
|
||
print_const(">");
|
||
break;
|
||
case '\t':
|
||
print_const("<text:tab/>");
|
||
default:
|
||
print_char(c);
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
void mmd_print_string_odf(DString * out, const char * str) {
|
||
if (str == NULL)
|
||
return;
|
||
|
||
while (*str != '\0') {
|
||
mmd_print_char_odf(out, *str);
|
||
str++;
|
||
}
|
||
}
|
||
|
||
|
||
void mmd_print_localized_char_odf(DString * out, unsigned short type, scratch_pad * scratch) {
|
||
switch (type) {
|
||
case DASH_N:
|
||
print_const("–");
|
||
break;
|
||
case DASH_M:
|
||
print_const("—");
|
||
break;
|
||
case ELLIPSIS:
|
||
print_const("…");
|
||
break;
|
||
case APOSTROPHE:
|
||
print_const("’");
|
||
break;
|
||
case QUOTE_LEFT_SINGLE:
|
||
switch (scratch->quotes_lang) {
|
||
case SWEDISH:
|
||
print( "’");
|
||
break;
|
||
case FRENCH:
|
||
print_const("'");
|
||
break;
|
||
case GERMAN:
|
||
print_const("‚");
|
||
break;
|
||
case GERMANGUILL:
|
||
print_const("›");
|
||
break;
|
||
default:
|
||
print_const("‘");
|
||
}
|
||
break;
|
||
case QUOTE_RIGHT_SINGLE:
|
||
switch (scratch->quotes_lang) {
|
||
case GERMAN:
|
||
print_const("‘");
|
||
break;
|
||
case GERMANGUILL:
|
||
print_const("‹");
|
||
break;
|
||
default:
|
||
print_const("’");
|
||
}
|
||
break;
|
||
case QUOTE_LEFT_DOUBLE:
|
||
switch (scratch->quotes_lang) {
|
||
case DUTCH:
|
||
case GERMAN:
|
||
print_const("„");
|
||
break;
|
||
case GERMANGUILL:
|
||
print_const("»");
|
||
break;
|
||
case FRENCH:
|
||
print_const("«");
|
||
break;
|
||
case SWEDISH:
|
||
print( "”");
|
||
break;
|
||
default:
|
||
print_const("“");
|
||
}
|
||
break;
|
||
case QUOTE_RIGHT_DOUBLE:
|
||
switch (scratch->quotes_lang) {
|
||
case GERMAN:
|
||
print_const("“");
|
||
break;
|
||
case GERMANGUILL:
|
||
print_const("«");
|
||
break;
|
||
case FRENCH:
|
||
print_const("»");
|
||
break;
|
||
case SWEDISH:
|
||
case DUTCH:
|
||
default:
|
||
print_const("”");
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
void mmd_export_link_odf(DString * out, const char * source, token * text, link * link, scratch_pad * scratch) {
|
||
if (link->url) {
|
||
print_const("<text:a xlink:type=\"simple\" xlink:href=\"");
|
||
mmd_print_string_odf(out, link->url);
|
||
print_const("\"");
|
||
} else
|
||
print_const("<a xlink:type=\"simple\" xlink:href=\"\"");
|
||
|
||
if (link->title && link->title[0] != '\0') {
|
||
print_const(" office:name=\"");
|
||
mmd_print_string_odf(out, link->title);
|
||
print_const("\"");
|
||
}
|
||
|
||
print_const(">");
|
||
|
||
// If we're printing contents of bracket as text, then ensure we include it all
|
||
if (text && text->child && text->child->len > 1) {
|
||
text->child->next->start--;
|
||
text->child->next->len++;
|
||
}
|
||
|
||
mmd_export_token_tree_odf(out, source, text->child, scratch);
|
||
|
||
print_const("</text:a>");
|
||
}
|
||
|
||
|
||
static char * correct_dimension_units(char *original) {
|
||
char *result;
|
||
int i;
|
||
|
||
result = strdup(original);
|
||
|
||
for (i = 0; result[i]; i++)
|
||
result[i] = tolower(result[i]);
|
||
|
||
if (strstr(&result[strlen(result)-2],"px")) {
|
||
result[strlen(result)-2] = '\0';
|
||
strcat(result, "pt");
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
void mmd_export_image_odf(DString * out, const char * source, token * text, link * link, scratch_pad * scratch, bool is_figure) {
|
||
attr * a = link->attributes;
|
||
char * height = NULL;
|
||
char * width = NULL;
|
||
|
||
print_const("<draw:frame text:anchor-type=\"as-char\"\ndraw:z-index=\"0\" draw:style-name=\"fr1\"");
|
||
|
||
// Check attributes for dimensions
|
||
while (a) {
|
||
if (strcmp("height", a->key) == 0) {
|
||
height = correct_dimension_units(a->value);
|
||
} else if (strcmp("width", a->key) == 0) {
|
||
width = correct_dimension_units(a->value);
|
||
}
|
||
|
||
a = a->next;
|
||
}
|
||
|
||
if (width) {
|
||
printf(" svg:width=\"%s\">\n", width);
|
||
} else {
|
||
print_const(" svg:width=\"95%\">\n");
|
||
}
|
||
|
||
print_const("<draw:text-box><text:p><draw:frame text:anchor-type=\"as-char\" draw:z-index=\"1\" ");
|
||
|
||
if (height && width) {
|
||
printf("svg:height=\"%s\" ", height);
|
||
printf("svg:width=\"%s\" ", width);
|
||
}
|
||
|
||
if (height)
|
||
free(height);
|
||
|
||
if (width)
|
||
free(width);
|
||
|
||
if (link->url)
|
||
printf(">\n<draw:image xlink:href=\"%s\"", link->url);
|
||
|
||
print_const(" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\" draw:filter-name=\"<All formats>\"/>\n</draw:frame></text:p>");
|
||
|
||
if (is_figure) {
|
||
if (text) {
|
||
print_const("\n<text:p>Figure <text:sequence text:name=\"Figure\" text:formula=\"ooow:Figure+1\" style:num-format=\"1\"> Update Fields to calculate numbers</text:sequence>: ");
|
||
mmd_export_token_tree_odf(out, source, text->child, scratch);
|
||
print_const("</text:p>");
|
||
}
|
||
}
|
||
|
||
print_const("\n</draw:text-box></draw:frame>\n");
|
||
|
||
scratch->padded = 1;
|
||
}
|
||
|
||
|
||
|
||
void mmd_export_toc_entry_odf(DString * out, const char * source, scratch_pad * scratch, size_t * counter, short level) {
|
||
token * entry, * next;
|
||
short entry_level, next_level;
|
||
char * temp_char;
|
||
|
||
// Iterate over tokens
|
||
while (*counter < scratch->header_stack->size) {
|
||
// Get token for header
|
||
entry = stack_peek_index(scratch->header_stack, *counter);
|
||
entry_level = raw_level_for_header(entry);
|
||
|
||
if (entry_level >= level) {
|
||
// This entry is a direct descendant of the parent
|
||
temp_char = label_from_header(source, entry);
|
||
printf("<text:p text:style-name=\"TOC_Item\"><text:a xlink:type=\"simple\" xlink:href=\"#%s\" text:style-name=\"Index_20_Link\" text:visited-style-name=\"Index_20_Link\">", temp_char);
|
||
mmd_export_token_tree_odf(out, source, entry->child, scratch);
|
||
print_const(" <text:tab/>1</text:a></text:p>\n");
|
||
|
||
if (*counter < scratch->header_stack->size - 1) {
|
||
next = stack_peek_index(scratch->header_stack, *counter + 1);
|
||
next_level = next->type - BLOCK_H1 + 1;
|
||
if (next_level > entry_level) {
|
||
// This entry has children
|
||
(*counter)++;
|
||
mmd_export_toc_entry_odf(out, source, scratch, counter, entry_level + 1);
|
||
}
|
||
}
|
||
|
||
free(temp_char);
|
||
} else if (entry_level < level ) {
|
||
// If entry < level, exit this level
|
||
// Decrement counter first, so that we can test it again later
|
||
(*counter)--;
|
||
break;
|
||
}
|
||
|
||
// Increment counter
|
||
(*counter)++;
|
||
}
|
||
}
|
||
|
||
void mmd_export_toc_odf(DString * out, const char * source, scratch_pad * scratch) {
|
||
size_t counter = 0;
|
||
|
||
// TODO: Could use LC to internationalize this
|
||
print_const("<text:table-of-content text:style-name=\"Sect1\" text:protected=\"true\" text:name=\"Table of Contents1\">\n");
|
||
print_const("<text:table-of-content-source text:outline-level=\"10\">\n");
|
||
print_const("<text:index-title-template text:style-name=\"Contents_20_Heading\">Table of Contents</text:index-title-template>\n");
|
||
print_const("</text:table-of-content-source>\n<text:index-body>\n");
|
||
print_const("<text:index-title text:style-name=\"Sect1\" text:name=\"Table of Contents1_Head\">\n");
|
||
print_const("<text:p text:style-name=\"Contents_20_Heading\">Table of Contents</text:p>\n");
|
||
print_const("</text:index-title>\n");
|
||
|
||
mmd_export_toc_entry_odf(out, source, scratch, &counter, 0);
|
||
|
||
print_const("</text:index-body>\n</text:table-of-content>\n\n");
|
||
}
|
||
|
||
|
||
void mmd_export_token_odf(DString * out, const char * source, token * t, scratch_pad * scratch) {
|
||
if (t == NULL)
|
||
return;
|
||
|
||
short temp_short;
|
||
short temp_short2;
|
||
short temp_short3;
|
||
link * temp_link = NULL;
|
||
char * temp_char = NULL;
|
||
char * temp_char2 = NULL;
|
||
char * temp_char3 = NULL;
|
||
bool temp_bool = 0;
|
||
token * temp_token = NULL;
|
||
footnote * temp_note = NULL;
|
||
|
||
switch (t->type) {
|
||
case DOC_START_TOKEN:
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
break;
|
||
case AMPERSAND:
|
||
case AMPERSAND_LONG:
|
||
print_const("&");
|
||
break;
|
||
case ANGLE_LEFT:
|
||
print_const("<");
|
||
break;
|
||
case ANGLE_RIGHT:
|
||
print_const(">");
|
||
break;
|
||
case APOSTROPHE:
|
||
if (!(scratch->extensions & EXT_SMART)) {
|
||
print_token(t);
|
||
} else {
|
||
print_localized(APOSTROPHE);
|
||
}
|
||
break;
|
||
case BACKTICK:
|
||
if (t->mate == NULL)
|
||
print_token(t);
|
||
else if (t->mate->type == QUOTE_RIGHT_ALT)
|
||
if (!(scratch->extensions & EXT_SMART)) {
|
||
print_token(t);
|
||
} else {
|
||
print_localized(QUOTE_LEFT_DOUBLE);
|
||
}
|
||
else if (t->start < t->mate->start) {
|
||
print_const("<text:span text:style-name=\"Source_20_Text\">");
|
||
} else {
|
||
print_const("</text:span>");
|
||
}
|
||
break;
|
||
case BLOCK_BLOCKQUOTE:
|
||
pad(out, 2, scratch);
|
||
scratch->padded = 2;
|
||
temp_short2 = scratch->odf_para_type;
|
||
|
||
scratch->odf_para_type = BLOCK_BLOCKQUOTE;
|
||
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
scratch->padded = 0;
|
||
scratch->odf_para_type = temp_short2;
|
||
break;
|
||
case BLOCK_CODE_FENCED:
|
||
pad(out, 2, scratch);
|
||
print_const("<text:p text:style-name=\"Preformatted Text\">");
|
||
mmd_export_token_tree_odf_raw(out, source, t->child->next, scratch);
|
||
print_const("</text:p>");
|
||
scratch->padded = 0;
|
||
break;
|
||
case BLOCK_CODE_INDENTED:
|
||
pad(out, 2, scratch);
|
||
print_const("<text:p text:style-name=\"Preformatted Text\">");
|
||
mmd_export_token_tree_odf_raw(out, source, t->child, scratch);
|
||
print_const("</text:p>");
|
||
scratch->padded = 0;
|
||
break;
|
||
case BLOCK_DEFINITION:
|
||
pad(out, 2, scratch);
|
||
temp_short2 = scratch->odf_para_type;
|
||
scratch->odf_para_type = BLOCK_DEFINITION;
|
||
|
||
temp_short = scratch->list_is_tight;
|
||
if (!(t->child->next && (t->child->next->type == BLOCK_EMPTY) && t->child->next->next))
|
||
scratch->list_is_tight = true;
|
||
|
||
if (t->child && t->child->type != BLOCK_PARA) {
|
||
print_const("<text:p text:style-name=\"Quotations\">");
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
print_const("</text:p>");
|
||
} else {
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
}
|
||
scratch->padded = 0;
|
||
|
||
scratch->list_is_tight = temp_short;
|
||
scratch->odf_para_type = temp_short2;
|
||
break;
|
||
case BLOCK_DEFLIST:
|
||
pad(out, 2, scratch);
|
||
|
||
// Group consecutive definition lists into a single list.
|
||
// lemon's LALR(1) parser can't properly handle this (to my understanding).
|
||
|
||
// if (!(t->prev && (t->prev->type == BLOCK_DEFLIST)))
|
||
// print_const("<dl>\n");
|
||
|
||
scratch->padded = 2;
|
||
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
pad(out, 1, scratch);
|
||
|
||
// if (!(t->next && (t->next->type == BLOCK_DEFLIST)))
|
||
// print_const("</dl>\n");
|
||
|
||
scratch->padded = 1;
|
||
break;
|
||
case BLOCK_EMPTY:
|
||
break;
|
||
case BLOCK_H1:
|
||
case BLOCK_H2:
|
||
case BLOCK_H3:
|
||
case BLOCK_H4:
|
||
case BLOCK_H5:
|
||
case BLOCK_H6:
|
||
case BLOCK_SETEXT_1:
|
||
case BLOCK_SETEXT_2:
|
||
pad(out, 2, scratch);
|
||
switch (t->type) {
|
||
case BLOCK_SETEXT_1:
|
||
temp_short = 1;
|
||
break;
|
||
case BLOCK_SETEXT_2:
|
||
temp_short = 2;
|
||
break;
|
||
default:
|
||
temp_short = t->type - BLOCK_H1 + 1;
|
||
}
|
||
|
||
printf("<text:h text:outline-level=\"%d\">", temp_short + scratch->base_header_level - 1);
|
||
|
||
if (scratch->extensions & EXT_NO_LABELS) {
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
} else {
|
||
temp_char = label_from_header(source, t);
|
||
printf("<text:bookmark text:name=\"%s\"/>", temp_char);
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
//printf("<text:bookmark-end text:name=\"%s\"/>", temp_char);
|
||
free(temp_char);
|
||
}
|
||
|
||
print_const("</text:h>");
|
||
scratch->padded = 0;
|
||
break;
|
||
case BLOCK_HR:
|
||
pad(out, 2, scratch);
|
||
print_const("<text:p text:style-name=\"Horizontal_20_Line\"/>");
|
||
scratch->padded = 0;
|
||
break;
|
||
case BLOCK_HTML:
|
||
// Don't print HTML
|
||
break;
|
||
case BLOCK_LIST_BULLETED_LOOSE:
|
||
case BLOCK_LIST_BULLETED:
|
||
temp_short = scratch->list_is_tight;
|
||
switch (t->type) {
|
||
case BLOCK_LIST_BULLETED_LOOSE:
|
||
scratch->list_is_tight = false;
|
||
break;
|
||
case BLOCK_LIST_BULLETED:
|
||
scratch->list_is_tight = true;
|
||
break;
|
||
}
|
||
pad(out, 2, scratch);
|
||
print_const("<text:list text:style-name=\"L1\">");
|
||
scratch->padded = 1;
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
pad(out, 2, scratch);
|
||
print_const("</text:list>");
|
||
scratch->padded = 0;
|
||
scratch->list_is_tight = temp_short;
|
||
break;
|
||
case BLOCK_LIST_ENUMERATED_LOOSE:
|
||
case BLOCK_LIST_ENUMERATED:
|
||
temp_short = scratch->list_is_tight;
|
||
switch (t->type) {
|
||
case BLOCK_LIST_ENUMERATED_LOOSE:
|
||
scratch->list_is_tight = false;
|
||
break;
|
||
case BLOCK_LIST_ENUMERATED:
|
||
scratch->list_is_tight = true;
|
||
break;
|
||
}
|
||
pad(out, 2, scratch);
|
||
print_const("<text:list text:style-name=\"L2\">");
|
||
scratch->padded = 1;
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
pad(out, 2, scratch);
|
||
print_const("</text:list>");
|
||
scratch->padded = 0;
|
||
scratch->list_is_tight = temp_short;
|
||
break;
|
||
case BLOCK_LIST_ITEM:
|
||
pad(out, 2, scratch);
|
||
print_const("<text:list-item>\n");
|
||
scratch->padded = 2;
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
print_const("</text:list-item>");
|
||
scratch->padded = 0;
|
||
break;
|
||
case BLOCK_LIST_ITEM_TIGHT:
|
||
pad(out, 2, scratch);
|
||
print_const("<text:list-item>\n");
|
||
|
||
if (t->child && t->child->type != BLOCK_PARA)
|
||
print_const("<text:p text:style-name=\"P1\">\n");
|
||
|
||
scratch->padded = 2;
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
|
||
if (t->child && t->child->type != BLOCK_PARA)
|
||
print_const("</text:p>");
|
||
|
||
print_const("</text:list-item>");
|
||
scratch->padded = 0;
|
||
break;
|
||
case BLOCK_META:
|
||
break;
|
||
case BLOCK_PARA:
|
||
pad(out, 2, scratch);
|
||
print_const("<text:p");
|
||
|
||
switch (scratch->odf_para_type) {
|
||
case BLOCK_BLOCKQUOTE:
|
||
case BLOCK_DEFINITION:
|
||
print_const(" text:style-name=\"Quotations\">");
|
||
break;
|
||
case PAIR_BRACKET_ABBREVIATION:
|
||
case PAIR_BRACKET_CITATION:
|
||
case PAIR_BRACKET_FOOTNOTE:
|
||
case PAIR_BRACKET_GLOSSARY:
|
||
print_const(" text:style-name=\"Footnote\">");
|
||
break;
|
||
default:
|
||
print_const(" text:style-name=\"Standard\">");
|
||
break;
|
||
}
|
||
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
|
||
print_const("</text:p>");
|
||
scratch->padded = 0;
|
||
break;
|
||
case BLOCK_TABLE:
|
||
pad(out, 2, scratch);
|
||
print_const("<table:table>\n");
|
||
|
||
scratch->padded = 2;
|
||
read_table_column_alignments(source, t, scratch);
|
||
|
||
for (int i = 0; i < scratch->table_column_count; ++i)
|
||
{
|
||
print_const("<table:table-column/>\n");
|
||
// switch (scratch->table_alignment[i]) {
|
||
// case 'l':
|
||
// print_const("<col style=\"text-align:left;\"/>\n");
|
||
// break;
|
||
// case 'L':
|
||
// print_const("<col style=\"text-align:left;\" class=\"extended\"/>\n");
|
||
// break;
|
||
// case 'r':
|
||
// print_const("<col style=\"text-align:right;\"/>\n");
|
||
// break;
|
||
// case 'R':
|
||
// print_const("<col style=\"text-align:right;\" class=\"extended\"/>\n");
|
||
// break;
|
||
// case 'c':
|
||
// print_const("<col style=\"text-align:center;\"/>\n");
|
||
// break;
|
||
// case 'C':
|
||
// print_const("<col style=\"text-align:center;\" class=\"extended\"/>\n");
|
||
// break;
|
||
// default:
|
||
// print_const("<col />\n");
|
||
// break;
|
||
// }
|
||
}
|
||
scratch->padded = 1;
|
||
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
pad(out, 1, scratch);
|
||
print_const("</table:table>\n");
|
||
|
||
// Are we followed by a caption?
|
||
if (table_has_caption(t)) {
|
||
temp_token = t->next->child;
|
||
|
||
if (temp_token->next &&
|
||
temp_token->next->type == PAIR_BRACKET) {
|
||
temp_token = temp_token->next;
|
||
}
|
||
|
||
temp_char = label_from_token(source, temp_token);
|
||
printf("<text:p><text:bookmark text:name=\"%s\"/>Table <text:sequence text:name=\"Table\" text:formula=\"ooow:Table+1\" style:num-format=\"1\"> Update Fields to calculate numbers</text:sequence>:", temp_char);
|
||
|
||
t->next->child->child->type = TEXT_EMPTY;
|
||
t->next->child->child->mate->type = TEXT_EMPTY;
|
||
mmd_export_token_tree_odf(out, source, t->next->child->child, scratch);
|
||
|
||
printf("<text:bookmark-end text:name=\"%s\"/></text:p>\n", temp_char);
|
||
|
||
free(temp_char);
|
||
temp_short = 1;
|
||
} else {
|
||
temp_short = 0;
|
||
}
|
||
|
||
scratch->padded = 0;
|
||
scratch->skip_token = temp_short;
|
||
|
||
break;
|
||
case BLOCK_TABLE_HEADER:
|
||
pad(out, 2, scratch);
|
||
scratch->in_table_header = 1;
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
scratch->in_table_header = 0;
|
||
scratch->padded = 1;
|
||
break;
|
||
case BLOCK_TABLE_SECTION:
|
||
pad(out, 2, scratch);
|
||
scratch->padded = 2;
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
scratch->padded = 0;
|
||
break;
|
||
case BLOCK_TOC:
|
||
pad(out, 2, scratch);
|
||
|
||
mmd_export_toc_odf(out, source, scratch);
|
||
|
||
scratch->padded = 1;
|
||
break;
|
||
case BLOCK_TERM:
|
||
pad(out, 2, scratch);
|
||
print_const("<text:p><text:span text:style-name=\"MMD-Bold\">");
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
print_const("</text:span></text:p>\n");
|
||
scratch->padded = 2;
|
||
break;
|
||
case BRACE_DOUBLE_LEFT:
|
||
print_const("{{");
|
||
break;
|
||
case BRACE_DOUBLE_RIGHT:
|
||
print_const("}}");
|
||
break;
|
||
case BRACKET_ABBREVIATION_LEFT:
|
||
print_const("[>");
|
||
break;
|
||
case BRACKET_CITATION_LEFT:
|
||
print_const("[#");
|
||
break;
|
||
case BRACKET_LEFT:
|
||
print_const("[");
|
||
break;
|
||
case BRACKET_RIGHT:
|
||
print_const("]");
|
||
break;
|
||
case BRACKET_VARIABLE_LEFT:
|
||
print_const("[\%");
|
||
break;
|
||
case COLON:
|
||
print_char(':');
|
||
break;
|
||
case CRITIC_ADD_OPEN:
|
||
print_const("{++");
|
||
break;
|
||
case CRITIC_ADD_CLOSE:
|
||
print_const("++}");
|
||
break;
|
||
case CRITIC_COM_OPEN:
|
||
print_const("{>>");
|
||
break;
|
||
case CRITIC_COM_CLOSE:
|
||
print_const("<<}");
|
||
break;
|
||
case CRITIC_DEL_OPEN:
|
||
print_const("{--");
|
||
break;
|
||
case CRITIC_DEL_CLOSE:
|
||
print_const("--}");
|
||
break;
|
||
case CRITIC_HI_OPEN:
|
||
print_const("{==");
|
||
break;
|
||
case CRITIC_HI_CLOSE:
|
||
print_const("==}");
|
||
break;
|
||
case CRITIC_SUB_OPEN:
|
||
print_const("{~~");
|
||
break;
|
||
case CRITIC_SUB_DIV:
|
||
print_const("~>");
|
||
break;
|
||
case CRITIC_SUB_CLOSE:
|
||
print_const("~~}");
|
||
break;
|
||
case DASH_M:
|
||
if (!(scratch->extensions & EXT_SMART)) {
|
||
print_token(t);
|
||
} else {
|
||
print_localized(DASH_M);
|
||
}
|
||
break;
|
||
case DASH_N:
|
||
if (!(scratch->extensions & EXT_SMART)) {
|
||
print_token(t);
|
||
} else {
|
||
print_localized(DASH_N);
|
||
}
|
||
break;
|
||
case ELLIPSIS:
|
||
if (!(scratch->extensions & EXT_SMART)) {
|
||
print_token(t);
|
||
} else {
|
||
print_localized(ELLIPSIS);
|
||
}
|
||
break;
|
||
case EMPH_START:
|
||
print_const("<text:span text:style-name=\"MMD-Italic\">");
|
||
break;
|
||
case EMPH_STOP:
|
||
print_const("</text:span>");
|
||
break;
|
||
case EQUAL:
|
||
print_char('=');
|
||
break;
|
||
case ESCAPED_CHARACTER:
|
||
if (!(scratch->extensions & EXT_COMPATIBILITY) &&
|
||
(source[t->start + 1] == ' ')) {
|
||
print_const(" "); // This is a non-breaking space character
|
||
} else {
|
||
mmd_print_char_odf(out, source[t->start + 1]);
|
||
}
|
||
break;
|
||
case HASH1:
|
||
case HASH2:
|
||
case HASH3:
|
||
case HASH4:
|
||
case HASH5:
|
||
case HASH6:
|
||
print_token(t);
|
||
break;
|
||
case INDENT_SPACE:
|
||
print_char(' ');
|
||
break;
|
||
case INDENT_TAB:
|
||
print_const("<text:tab/>");
|
||
break;
|
||
case LINE_LIST_BULLETED:
|
||
case LINE_LIST_ENUMERATED:
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
break;
|
||
case MANUAL_LABEL:
|
||
case MARKER_BLOCKQUOTE:
|
||
case MARKER_H1:
|
||
case MARKER_H2:
|
||
case MARKER_H3:
|
||
case MARKER_H4:
|
||
case MARKER_H5:
|
||
case MARKER_H6:
|
||
case MARKER_LIST_BULLET:
|
||
case MARKER_LIST_ENUMERATOR:
|
||
break;
|
||
case MATH_BRACKET_OPEN:
|
||
if (t->mate) {
|
||
print_const("<text:span text:style-name=\"math\">\\[");
|
||
} else
|
||
print_const("\\[");
|
||
break;
|
||
case MATH_BRACKET_CLOSE:
|
||
if (t->mate) {
|
||
print_const("\\]</text:span>");
|
||
} else
|
||
print_const("\\]");
|
||
break;
|
||
case MATH_DOLLAR_SINGLE:
|
||
if (t->mate) {
|
||
(t->start < t->mate->start) ? ( print_const("<text:span text:style-name=\"math\">\\(") ) : ( print_const("\\)</text:span>") );
|
||
} else {
|
||
print_const("$");
|
||
}
|
||
break;
|
||
case MATH_DOLLAR_DOUBLE:
|
||
if (t->mate) {
|
||
(t->start < t->mate->start) ? ( print_const("<text:span text:style-name=\"math\">\\[") ) : ( print_const("\\]</text:span>") );
|
||
} else {
|
||
print_const("$$");
|
||
}
|
||
break;
|
||
case MATH_PAREN_OPEN:
|
||
if (t->mate) {
|
||
print_const("<text:span text:style-name=\"math\">\\(");
|
||
} else
|
||
print_const("\\(");
|
||
break;
|
||
case MATH_PAREN_CLOSE:
|
||
if (t->mate) {
|
||
print_const("\\)</text:span>");
|
||
} else
|
||
print_const("\\)");
|
||
break;
|
||
case NON_INDENT_SPACE:
|
||
print_char(' ');
|
||
break;
|
||
case PAIR_ANGLE:
|
||
temp_char = url_accept(source, t->start + 1, t->len - 2, NULL, true);
|
||
|
||
if (temp_char) {
|
||
print_const("<text:a xlink:type=\"simple\" xlink:href=\"");
|
||
|
||
if (scan_email(temp_char)) {
|
||
temp_bool = true;
|
||
|
||
if (strncmp("mailto:", temp_char, 7) != 0) {
|
||
print_const("mailto:");
|
||
}
|
||
} else {
|
||
temp_bool = false;
|
||
}
|
||
|
||
mmd_print_string_odf(out, temp_char);
|
||
print_const("\">");
|
||
mmd_print_string_odf(out, temp_char);
|
||
print_const("</text:a>");
|
||
} else if (scan_html(&source[t->start])) {
|
||
// We ignore HTML blocks
|
||
if (scan_html_comment(&source[t->start])) {
|
||
// But allow HTML comments as raw LaTeX
|
||
d_string_append_c_array(out, &source[t->start + 4], t->len - 4 - 3);
|
||
}
|
||
} else {
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
}
|
||
|
||
free(temp_char);
|
||
break;
|
||
case PAIR_BACKTICK:
|
||
// Strip leading whitespace
|
||
switch (t->child->next->type) {
|
||
case TEXT_NL:
|
||
case INDENT_TAB:
|
||
case INDENT_SPACE:
|
||
case NON_INDENT_SPACE:
|
||
t->child->next->type = TEXT_EMPTY;
|
||
break;
|
||
case TEXT_PLAIN:
|
||
while (t->child->next->len && char_is_whitespace(source[t->child->next->start])) {
|
||
t->child->next->start++;
|
||
t->child->next->len--;
|
||
}
|
||
break;
|
||
}
|
||
|
||
// Strip trailing whitespace
|
||
switch (t->child->mate->prev->type) {
|
||
case TEXT_NL:
|
||
case INDENT_TAB:
|
||
case INDENT_SPACE:
|
||
case NON_INDENT_SPACE:
|
||
t->child->mate->prev->type = TEXT_EMPTY;
|
||
break;
|
||
case TEXT_PLAIN:
|
||
while (t->child->mate->prev->len && char_is_whitespace(source[t->child->mate->prev->start + t->child->mate->prev->len - 1])) {
|
||
t->child->mate->prev->len--;
|
||
}
|
||
break;
|
||
}
|
||
t->child->type = TEXT_EMPTY;
|
||
t->child->mate->type = TEXT_EMPTY;
|
||
print_const("<text:span text:style-name=\"Source_20_Text\">");
|
||
mmd_export_token_tree_odf_raw(out, source, t->child, scratch);
|
||
print_const("</text:span>");
|
||
break;
|
||
case PAIR_BRACES:
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
break;
|
||
case PAIR_BRACKET:
|
||
if ((scratch->extensions & EXT_NOTES) &&
|
||
(t->next && t->next->type == PAIR_BRACKET_CITATION)) {
|
||
goto parse_citation;
|
||
}
|
||
|
||
case PAIR_BRACKET_IMAGE:
|
||
parse_brackets(source, scratch, t, &temp_link, &temp_short, &temp_bool);
|
||
|
||
if (temp_link) {
|
||
if (t->type == PAIR_BRACKET) {
|
||
// Link
|
||
mmd_export_link_odf(out, source, t, temp_link, scratch);
|
||
} else {
|
||
// Image -- should it be a figure (e.g. image is only thing in paragraph)?
|
||
temp_token = t->next;
|
||
|
||
if (temp_token &&
|
||
((temp_token->type == PAIR_BRACKET) ||
|
||
(temp_token->type == PAIR_PAREN))) {
|
||
temp_token = temp_token->next;
|
||
}
|
||
|
||
if (temp_token && temp_token->type == TEXT_NL)
|
||
temp_token = temp_token->next;
|
||
|
||
if (temp_token && temp_token->type == TEXT_LINEBREAK)
|
||
temp_token = temp_token->next;
|
||
|
||
if (t->prev || temp_token) {
|
||
mmd_export_image_odf(out, source, t, temp_link, scratch, false);
|
||
} else {
|
||
mmd_export_image_odf(out, source, t, temp_link, scratch, true);
|
||
}
|
||
}
|
||
|
||
if (temp_bool) {
|
||
link_free(temp_link);
|
||
}
|
||
|
||
scratch->skip_token = temp_short;
|
||
|
||
return;
|
||
}
|
||
|
||
// No links exist, so treat as normal
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
break;
|
||
case PAIR_BRACKET_CITATION:
|
||
parse_citation:
|
||
temp_bool = true; // Track whether this is regular vs 'not cited'
|
||
temp_token = t; // Remember whether we need to skip ahead
|
||
|
||
if (scratch->extensions & EXT_NOTES) {
|
||
// Note-based syntax enabled
|
||
|
||
if (t->type == PAIR_BRACKET) {
|
||
// This is a locator for a subsequent citation (e.g. `[foo][#bar]`)
|
||
temp_char = text_inside_pair(source, t);
|
||
temp_char2 = label_from_string(temp_char);
|
||
|
||
if (strcmp(temp_char2, "notcited") == 0) {
|
||
free(temp_char);
|
||
temp_char = strdup("");
|
||
temp_bool = false;
|
||
}
|
||
|
||
free(temp_char2);
|
||
|
||
// Move ahead to actual citation
|
||
t = t->next;
|
||
} else {
|
||
// This is the actual citation (e.g. `[#foo]`)
|
||
// No locator
|
||
temp_char = strdup("");
|
||
}
|
||
|
||
// Classify this use
|
||
temp_short2 = scratch->used_citations->size;
|
||
citation_from_bracket(source, scratch, t, &temp_short);
|
||
|
||
if (temp_short == -1) {
|
||
// This instance is not properly formed
|
||
print_const("[#");
|
||
mmd_export_token_tree_odf(out, source, t->child->next, scratch);
|
||
print_const("]");
|
||
|
||
free(temp_char);
|
||
break;
|
||
}
|
||
|
||
|
||
temp_short3 = scratch->odf_para_type;
|
||
scratch->odf_para_type = PAIR_BRACKET_FOOTNOTE;
|
||
|
||
if (temp_bool) {
|
||
// This is a regular citation
|
||
|
||
if (temp_char[0] == '\0') {
|
||
// No locator
|
||
|
||
if (temp_short2 == scratch->used_citations->size) {
|
||
// This is a re-use of a previously used note
|
||
print_const("<text:span text:style-name=\"Footnote_20_anchor\"><text:note-ref text:note-class=\"endnote\" text:reference-format=\"text\" ");
|
||
printf("text:ref-name=\"cite%d\">%d</text:note-ref></text:span>", temp_short, temp_short);
|
||
} else {
|
||
// This is the first time this note was used
|
||
printf("<text:note text:id=\"cite%d\" text:note-class=\"endnote\"><text:note-body>", temp_short);
|
||
temp_note = stack_peek_index(scratch->used_citations, temp_short - 1);
|
||
|
||
mmd_export_token_tree_odf(out, source, temp_note->content, scratch);
|
||
print_const("</text:note-body></text:note>");
|
||
}
|
||
} else {
|
||
// Locator present
|
||
|
||
if (temp_short2 == scratch->used_citations->size) {
|
||
// This is a re-use of a previously used note
|
||
print_const("<text:span text:style-name=\"Footnote_20_anchor\"><text:note-ref text:note-class=\"endnote\" text:reference-format=\"text\" ");
|
||
printf("text:ref-name=\"cite%d\">%d</text:note-ref></text:span>", temp_short, temp_short);
|
||
} else {
|
||
// This is the first time this note was used
|
||
printf("<text:note text:id=\"cite%d\" text:note-class=\"endnote\"><text:note-body>", temp_short);
|
||
temp_note = stack_peek_index(scratch->used_citations, temp_short - 1);
|
||
|
||
mmd_export_token_tree_odf(out, source, temp_note->content, scratch);
|
||
print_const("</text:note-body></text:note>");
|
||
}
|
||
}
|
||
} else {
|
||
if (temp_short2 == scratch->used_citations->size) {
|
||
// This is a re-use of a previously used note
|
||
} else {
|
||
// This is the first time this note was used
|
||
// TODO: Not sure how to add an endnote without inserting a marker in the text
|
||
printf("<text:note text:id=\"cite%d\" text:note-class=\"endnote\"><text:note-body>", temp_short);
|
||
temp_note = stack_peek_index(scratch->used_citations, temp_short - 1);
|
||
|
||
mmd_export_token_tree_odf(out, source, temp_note->content, scratch);
|
||
print_const("</text:note-body></text:note>");
|
||
}
|
||
}
|
||
|
||
if (temp_token != t) {
|
||
// Skip citation on next pass
|
||
scratch->skip_token = 1;
|
||
}
|
||
|
||
scratch->odf_para_type = temp_short3;
|
||
|
||
free(temp_char);
|
||
} else {
|
||
// Note-based syntax disabled
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
}
|
||
break;
|
||
case PAIR_BRACKET_FOOTNOTE:
|
||
if (scratch->extensions & EXT_NOTES) {
|
||
// Note-based syntax enabled
|
||
|
||
// Classify this use
|
||
temp_short2 = scratch->used_footnotes->size;
|
||
footnote_from_bracket(source, scratch, t, &temp_short);
|
||
|
||
if (temp_short == -1) {
|
||
// This instance is not properly formed
|
||
print_const("[?");
|
||
mmd_export_token_tree_odf(out, source, t->child->next, scratch);
|
||
print_const("]");
|
||
break;
|
||
}
|
||
|
||
temp_short3 = scratch->odf_para_type;
|
||
scratch->odf_para_type = PAIR_BRACKET_FOOTNOTE;
|
||
|
||
if (temp_short2 == scratch->used_footnotes->size) {
|
||
// This is a re-use of a previously used note
|
||
|
||
printf("<text:note text:id=\"fn%d\" text:note-class=\"footnote\"><text:note-body>", temp_short);
|
||
temp_note = stack_peek_index(scratch->used_footnotes, temp_short - 1);
|
||
|
||
mmd_export_token_tree_odf(out, source, temp_note->content, scratch);
|
||
print_const("</text:note-body></text:note>");
|
||
} else {
|
||
// This is the first time this note was used
|
||
|
||
// This is a new footnote
|
||
printf("<text:note text:id=\"fn%d\" text:note-class=\"footnote\"><text:note-body>", temp_short);
|
||
temp_note = stack_peek_index(scratch->used_footnotes, temp_short - 1);
|
||
|
||
mmd_export_token_tree_odf(out, source, temp_note->content, scratch);
|
||
print_const("</text:note-body></text:note>");
|
||
}
|
||
|
||
scratch->odf_para_type = temp_short3;
|
||
} else {
|
||
// Note-based syntax disabled
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
}
|
||
break;
|
||
case PAIR_BRACKET_ABBREVIATION:
|
||
// Which might also be an "auto-tagged" abbreviation
|
||
if (scratch->extensions & EXT_NOTES) {
|
||
// Note-based syntax enabled
|
||
|
||
// Classify this use
|
||
temp_short2 = scratch->used_abbreviations->size;
|
||
temp_short3 = scratch->inline_abbreviations_to_free->size;
|
||
abbreviation_from_bracket(source, scratch, t, &temp_short);
|
||
|
||
if (temp_short == -1) {
|
||
// This instance is not properly formed
|
||
print_const("[>");
|
||
mmd_export_token_tree_odf(out, source, t->child->next, scratch);
|
||
print_const("]");
|
||
break;
|
||
}
|
||
|
||
// Get instance of the note used
|
||
temp_note = stack_peek_index(scratch->used_abbreviations, temp_short - 1);
|
||
|
||
if (t->child) {
|
||
t->child->type = TEXT_EMPTY;
|
||
t->child->mate->type = TEXT_EMPTY;
|
||
}
|
||
|
||
if (temp_short2 == scratch->used_abbreviations->size) {
|
||
// This is a re-use of a previously used note
|
||
|
||
if (temp_short3 == scratch->inline_abbreviations_to_free->size) {
|
||
// This is a reference definition
|
||
mmd_print_string_odf(out, temp_note->label_text);
|
||
// mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
} else {
|
||
// This is an inline definition
|
||
mmd_print_string_odf(out, temp_note->label_text);
|
||
// mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
}
|
||
} else {
|
||
// This is the first time this note was used
|
||
temp_short2 = scratch->odf_para_type;
|
||
scratch->odf_para_type = PAIR_BRACKET_ABBREVIATION;
|
||
|
||
if (temp_short3 == scratch->inline_abbreviations_to_free->size) {
|
||
// This is a reference definition
|
||
mmd_print_string_odf(out, temp_note->clean_text);
|
||
print_const(" (");
|
||
mmd_print_string_odf(out, temp_note->label_text);
|
||
print_const(")");
|
||
} else {
|
||
// This is an inline definition
|
||
mmd_print_string_odf(out, temp_note->clean_text);
|
||
print_const(" (");
|
||
mmd_print_string_odf(out, temp_note->label_text);
|
||
print_const(")");
|
||
}
|
||
|
||
scratch->odf_para_type = temp_short2;
|
||
}
|
||
} else {
|
||
// Note-based syntax disabled
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
}
|
||
break;
|
||
case PAIR_BRACKET_GLOSSARY:
|
||
// Which might also be an "auto-tagged" glossary
|
||
if (scratch->extensions & EXT_NOTES) {
|
||
// Note-based syntax enabled
|
||
|
||
// Classify this use
|
||
temp_short2 = scratch->used_glossaries->size;
|
||
glossary_from_bracket(source, scratch, t, &temp_short);
|
||
|
||
if (temp_short == -1) {
|
||
// This instance is not properly formed
|
||
print_const("[?");
|
||
mmd_export_token_tree_odf(out, source, t->child->next, scratch);
|
||
print_const("]");
|
||
break;
|
||
}
|
||
|
||
// Get instance of the note used
|
||
temp_note = stack_peek_index(scratch->used_glossaries, temp_short - 1);
|
||
|
||
temp_short3 = scratch->odf_para_type;
|
||
scratch->odf_para_type = PAIR_BRACKET_GLOSSARY;
|
||
|
||
if (temp_short2 == scratch->used_glossaries->size) {
|
||
// This is a re-use of a previously used note
|
||
|
||
mmd_print_string_odf(out, temp_note->clean_text);
|
||
} else {
|
||
// This is the first time this note was used
|
||
|
||
mmd_print_string_odf(out, temp_note->clean_text);
|
||
|
||
printf("<text:note text:id=\"gn%d\" text:note-class=\"glossary\"><text:note-body>", temp_short);
|
||
mmd_export_token_tree_odf(out, source, temp_note->content, scratch);
|
||
print_const("</text:note-body></text:note>");
|
||
}
|
||
|
||
scratch->odf_para_type = temp_short3;
|
||
} else {
|
||
// Note-based syntax disabled
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
}
|
||
break;
|
||
case PAIR_BRACKET_VARIABLE:
|
||
temp_char = text_inside_pair(source, t);
|
||
temp_char2 = extract_metadata(scratch, temp_char);
|
||
|
||
if (temp_char2)
|
||
mmd_print_string_odf(out, temp_char2);
|
||
else
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
|
||
// Don't free temp_char2 (it belongs to meta *)
|
||
free(temp_char);
|
||
break;
|
||
case PAIR_CRITIC_ADD:
|
||
// Ignore if we're rejecting
|
||
if (scratch->extensions & EXT_CRITIC_REJECT)
|
||
break;
|
||
if (scratch->extensions & EXT_CRITIC) {
|
||
t->child->type = TEXT_EMPTY;
|
||
t->child->mate->type = TEXT_EMPTY;
|
||
if (scratch->extensions & EXT_CRITIC_ACCEPT) {
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
} else {
|
||
print_const("<text:span text:style-name=\"Underline\">");
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
print_const("</text:span>");
|
||
}
|
||
} else {
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
}
|
||
break;
|
||
case PAIR_CRITIC_DEL:
|
||
// Ignore if we're accepting
|
||
if (scratch->extensions & EXT_CRITIC_ACCEPT)
|
||
break;
|
||
if (scratch->extensions & EXT_CRITIC) {
|
||
t->child->type = TEXT_EMPTY;
|
||
t->child->mate->type = TEXT_EMPTY;
|
||
if (scratch->extensions & EXT_CRITIC_REJECT) {
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
} else {
|
||
print_const("<text:span text:style-name=\"Strike\">");
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
print_const("</text:span>");
|
||
}
|
||
} else {
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
}
|
||
break;
|
||
case PAIR_CRITIC_COM:
|
||
// Ignore if we're rejecting or accepting
|
||
if ((scratch->extensions & EXT_CRITIC_REJECT) ||
|
||
(scratch->extensions & EXT_CRITIC_ACCEPT))
|
||
break;
|
||
if (scratch->extensions & EXT_CRITIC) {
|
||
t->child->type = TEXT_EMPTY;
|
||
t->child->mate->type = TEXT_EMPTY;
|
||
print_const("<text:span text:style-name=\"Comment\">");
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
print_const("</text:span>");
|
||
} else {
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
}
|
||
break;
|
||
case PAIR_CRITIC_HI:
|
||
// Ignore if we're rejecting or accepting
|
||
if ((scratch->extensions & EXT_CRITIC_REJECT) ||
|
||
(scratch->extensions & EXT_CRITIC_ACCEPT))
|
||
break;
|
||
if (scratch->extensions & EXT_CRITIC) {
|
||
t->child->type = TEXT_EMPTY;
|
||
t->child->mate->type = TEXT_EMPTY;
|
||
print_const("<text:span text:style-name=\"Highlight\">");
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
print_const("</text:span>");
|
||
} else {
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
}
|
||
break;
|
||
case CRITIC_SUB_DIV_A:
|
||
print_const("~");
|
||
break;
|
||
case CRITIC_SUB_DIV_B:
|
||
print_const(">");
|
||
break;
|
||
case PAIR_CRITIC_SUB_DEL:
|
||
if ((scratch->extensions & EXT_CRITIC) &&
|
||
(t->next) &&
|
||
(t->next->type == PAIR_CRITIC_SUB_ADD)) {
|
||
t->child->type = TEXT_EMPTY;
|
||
t->child->mate->type = TEXT_EMPTY;
|
||
if (scratch->extensions & EXT_CRITIC_ACCEPT) {
|
||
|
||
} else if (scratch->extensions & EXT_CRITIC_REJECT) {
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
} else {
|
||
print_const("<text:span text:style-name=\"Strike\">");
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
print_const("</text:span>");
|
||
}
|
||
} else {
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
}
|
||
break;
|
||
case PAIR_CRITIC_SUB_ADD:
|
||
if ((scratch->extensions & EXT_CRITIC) &&
|
||
(t->prev) &&
|
||
(t->prev->type == PAIR_CRITIC_SUB_DEL)) {
|
||
t->child->type = TEXT_EMPTY;
|
||
t->child->mate->type = TEXT_EMPTY;
|
||
if (scratch->extensions & EXT_CRITIC_REJECT) {
|
||
|
||
} else if (scratch->extensions & EXT_CRITIC_ACCEPT) {
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
} else {
|
||
print_const("<text:span text:style-name=\"Underline\">");
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
print_const("</text:span>");
|
||
}
|
||
} else {
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
}
|
||
break;
|
||
case PAIR_MATH:
|
||
case PAIR_PAREN:
|
||
case PAIR_QUOTE_DOUBLE:
|
||
case PAIR_QUOTE_SINGLE:
|
||
case PAIR_STAR:
|
||
case PAIR_UL:
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
break;
|
||
case PAREN_LEFT:
|
||
print_char('(');
|
||
break;
|
||
case PAREN_RIGHT:
|
||
print_char(')');
|
||
break;
|
||
case PIPE:
|
||
print_token(t);
|
||
break;
|
||
case PLUS:
|
||
print_char('+');
|
||
break;
|
||
case QUOTE_SINGLE:
|
||
if ((t->mate == NULL) || (!(scratch->extensions & EXT_SMART)))
|
||
print_const("'");
|
||
else
|
||
(t->start < t->mate->start) ? ( print_localized(QUOTE_LEFT_SINGLE) ) : ( print_localized(QUOTE_RIGHT_SINGLE) );
|
||
break;
|
||
case QUOTE_DOUBLE:
|
||
if ((t->mate == NULL) || (!(scratch->extensions & EXT_SMART)))
|
||
print_const(""");
|
||
else
|
||
(t->start < t->mate->start) ? ( print_localized(QUOTE_LEFT_DOUBLE) ) : ( print_localized(QUOTE_RIGHT_DOUBLE) );
|
||
break;
|
||
case QUOTE_RIGHT_ALT:
|
||
if ((t->mate == NULL) || (!(scratch->extensions & EXT_SMART)))
|
||
print_const("''");
|
||
else
|
||
print_localized(QUOTE_RIGHT_DOUBLE);
|
||
break;
|
||
case SLASH:
|
||
print_char('/');
|
||
break;
|
||
case STAR:
|
||
print_char('*');
|
||
break;
|
||
case STRONG_START:
|
||
print_const("<text:span text:style-name=\"MMD-Bold\">");
|
||
break;
|
||
case STRONG_STOP:
|
||
print_const("</text:span>");
|
||
break;
|
||
case SUBSCRIPT:
|
||
if (t->mate) {
|
||
(t->start < t->mate->start) ? (print_const("<text:span text:style-name=\"MMD-Subscript\">")) : (print_const("</text:span>"));
|
||
} else if (t->len != 1) {
|
||
print_const("<text:span text:style-name=\"MMD-Subscript\">");
|
||
mmd_export_token_odf(out, source, t->child, scratch);
|
||
print_const("</text:span>");
|
||
} else {
|
||
print_const("~");
|
||
}
|
||
break;
|
||
case SUPERSCRIPT:
|
||
if (t->mate) {
|
||
(t->start < t->mate->start) ? (print_const("<text:span text:style-name=\"MMD-Superscript\">")) : (print_const("</text:span>"));
|
||
} else if (t->len != 1) {
|
||
print_const("<text:span text:style-name=\"MMD-Superscript\">");
|
||
mmd_export_token_odf(out, source, t->child, scratch);
|
||
print_const("</text:span>");
|
||
} else {
|
||
print_const("^");
|
||
}
|
||
break;
|
||
case TABLE_CELL:
|
||
print_const("<table:table-cell");
|
||
|
||
if (t->next && t->next->type == TABLE_DIVIDER) {
|
||
if (t->next->len > 1) {
|
||
printf(" table:number-columns-spanned=\"%d\"", t->next->len);
|
||
}
|
||
}
|
||
|
||
if (scratch->in_table_header) {
|
||
print_const(">\n<text:p text:style-name=\"Table_20_Heading\"");
|
||
} else {
|
||
print_const(">\n<text:p");
|
||
switch (scratch->table_alignment[scratch->table_cell_count]) {
|
||
case 'l':
|
||
case 'L':
|
||
default:
|
||
print_const(" text:style-name=\"MMD-Table\"");
|
||
break;
|
||
case 'r':
|
||
case 'R':
|
||
print_const(" text:style-name=\"MMD-Table-Right\"");
|
||
break;
|
||
case 'c':
|
||
case 'C':
|
||
print_const(" text:style-name=\"MMD-Table-Center\"");
|
||
break;
|
||
}
|
||
}
|
||
|
||
print_const(">");
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
|
||
print_const("</text:p>\n</table:table-cell>\n");
|
||
|
||
if (t->next)
|
||
scratch->table_cell_count += t->next->len;
|
||
else
|
||
scratch->table_cell_count++;
|
||
|
||
break;
|
||
case TABLE_DIVIDER:
|
||
break;
|
||
case TABLE_ROW:
|
||
print_const("<table:table-row>\n");
|
||
scratch->table_cell_count = 0;
|
||
mmd_export_token_tree_odf(out, source, t->child, scratch);
|
||
print_const("</table:table-row>\n");
|
||
break;
|
||
case TEXT_EMPTY:
|
||
break;
|
||
case TEXT_LINEBREAK:
|
||
if (t->next) {
|
||
print_const("<text:line-break/>\n");
|
||
scratch->padded = 0;
|
||
}
|
||
break;
|
||
case TEXT_NL:
|
||
if (t->next)
|
||
print_char('\n');
|
||
break;
|
||
case TEXT_BACKSLASH:
|
||
case TEXT_BRACE_LEFT:
|
||
case TEXT_BRACE_RIGHT:
|
||
case TEXT_HASH:
|
||
case TEXT_NUMBER_POSS_LIST:
|
||
case TEXT_PERCENT:
|
||
case TEXT_PERIOD:
|
||
case TEXT_PLAIN:
|
||
case TOC:
|
||
case UL:
|
||
print_token(t);
|
||
break;
|
||
default:
|
||
fprintf(stderr, "Unknown token type: %d\n", t->type);
|
||
token_describe(t, source);
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
void mmd_export_token_tree_odf(DString * out, const char * source, token * t, scratch_pad * scratch) {
|
||
|
||
// Prevent stack overflow with "dangerous" input causing extreme recursion
|
||
if (scratch->recurse_depth == kMaxExportRecursiveDepth) {
|
||
return;
|
||
}
|
||
|
||
scratch->recurse_depth++;
|
||
|
||
while (t != NULL) {
|
||
if (scratch->skip_token) {
|
||
scratch->skip_token--;
|
||
} else {
|
||
mmd_export_token_odf(out, source, t, scratch);
|
||
}
|
||
|
||
t = t->next;
|
||
}
|
||
|
||
scratch->recurse_depth--;
|
||
}
|
||
|
||
|
||
void mmd_export_token_odf_raw(DString * out, const char * source, token * t, scratch_pad * scratch) {
|
||
if (t == NULL)
|
||
return;
|
||
|
||
switch (t->type) {
|
||
case AMPERSAND:
|
||
print_const("&");
|
||
break;
|
||
case AMPERSAND_LONG:
|
||
print_const("&amp;");
|
||
break;
|
||
case ANGLE_RIGHT:
|
||
print_const(">");
|
||
break;
|
||
case ANGLE_LEFT:
|
||
print_const("<");
|
||
break;
|
||
case ESCAPED_CHARACTER:
|
||
print_const("\\");
|
||
mmd_print_char_odf(out, source[t->start + 1]);
|
||
break;
|
||
case INDENT_TAB:
|
||
print_const("<text:tab/>");
|
||
break;
|
||
case QUOTE_DOUBLE:
|
||
print_const(""");
|
||
break;
|
||
case CODE_FENCE:
|
||
if (t->next)
|
||
t->next->type = TEXT_EMPTY;
|
||
case TEXT_EMPTY:
|
||
break;
|
||
case TEXT_NL:
|
||
print_const("<text:line-break/>");
|
||
break;
|
||
default:
|
||
if (t->child)
|
||
mmd_export_token_tree_odf_raw(out, source, t->child, scratch);
|
||
else
|
||
print_token(t);
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
void mmd_export_token_tree_odf_raw(DString * out, const char * source, token * t, scratch_pad * scratch) {
|
||
while (t != NULL) {
|
||
if (scratch->skip_token) {
|
||
scratch->skip_token--;
|
||
} else {
|
||
mmd_export_token_odf_raw(out, source, t, scratch);
|
||
}
|
||
|
||
t = t->next;
|
||
}
|
||
}
|
||
|
||
|
||
void mmd_start_complete_odf(DString * out, const char * source, scratch_pad * scratch) {
|
||
print_const("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
|
||
"<office:document xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n" \
|
||
" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n" \
|
||
" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n" \
|
||
" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n" \
|
||
" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n" \
|
||
" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n" \
|
||
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n" \
|
||
" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n" \
|
||
" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n" \
|
||
" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n" \
|
||
" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n" \
|
||
" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n" \
|
||
" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n" \
|
||
" xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n" \
|
||
" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n" \
|
||
" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n" \
|
||
" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\"\n" \
|
||
" xmlns:ooo=\"http://openoffice.org/2004/office\"\n" \
|
||
" xmlns:ooow=\"http://openoffice.org/2004/writer\"\n" \
|
||
" xmlns:oooc=\"http://openoffice.org/2004/calc\"\n" \
|
||
" xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n" \
|
||
" xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n" \
|
||
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" \
|
||
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" \
|
||
" xmlns:rpt=\"http://openoffice.org/2005/report\"\n" \
|
||
" xmlns:of=\"urn:oasis:names:tc:opendocument:xmlns:of:1.2\"\n" \
|
||
" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"\n" \
|
||
" xmlns:grddl=\"http://www.w3.org/2003/g/data-view#\"\n" \
|
||
" xmlns:tableooo=\"http://openoffice.org/2009/table\"\n" \
|
||
" xmlns:field=\"urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0\"\n" \
|
||
" xmlns:formx=\"urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0\"\n" \
|
||
" xmlns:css3t=\"http://www.w3.org/TR/css3-text/\"\n" \
|
||
" office:version=\"1.2\"\n" \
|
||
" grddl:transformation=\"http://docs.oasis-open.org/office/1.2/xslt/odf2rdf.xsl\"\n" \
|
||
" office:mimetype=\"application/vnd.oasis.opendocument.text\">\n");
|
||
|
||
/* Font Declarations */
|
||
print_const("<office:font-face-decls>\n" \
|
||
" <style:font-face style:name=\"Courier New\" svg:font-family=\"'Courier New'\"\n" \
|
||
" style:font-adornments=\"Regular\"\n" \
|
||
" style:font-family-generic=\"modern\"\n" \
|
||
" style:font-pitch=\"fixed\"/>\n" \
|
||
"</office:font-face-decls>\n");
|
||
|
||
/* Append basic style information */
|
||
print_const("<office:styles>\n" \
|
||
"<style:style style:name=\"Standard\" style:family=\"paragraph\" style:class=\"text\">\n" \
|
||
" <style:paragraph-properties fo:margin-top=\"0in\" fo:margin-bottom=\"0.15in\"" \
|
||
" fo:text-align=\"justify\" style:justify-single-word=\"false\"/>\n" \
|
||
" </style:style>\n" \
|
||
"<style:style style:name=\"Preformatted_20_Text\" style:display-name=\"Preformatted Text\"\n" \
|
||
" style:family=\"paragraph\"\n" \
|
||
" style:parent-style-name=\"Standard\"\n" \
|
||
" style:class=\"html\">\n" \
|
||
" <style:paragraph-properties fo:margin-top=\"0in\" fo:margin-bottom=\"0in\" fo:text-align=\"start\"\n" \
|
||
" style:justify-single-word=\"false\"/>\n" \
|
||
" <style:text-properties style:font-name=\"Courier New\" fo:font-size=\"11pt\"\n" \
|
||
" style:font-name-asian=\"Courier New\"\n" \
|
||
" style:font-size-asian=\"11pt\"\n" \
|
||
" style:font-name-complex=\"Courier New\"\n" \
|
||
" style:font-size-complex=\"11pt\"/>\n" \
|
||
"</style:style>\n" \
|
||
"<style:style style:name=\"Source_20_Text\" style:display-name=\"Source Text\"\n" \
|
||
" style:family=\"text\">\n" \
|
||
" <style:text-properties style:font-name=\"Courier New\" style:font-name-asian=\"Courier New\"\n" \
|
||
" style:font-name-complex=\"Courier New\"\n" \
|
||
" fo:font-size=\"11pt\"/>\n" \
|
||
"</style:style>\n" \
|
||
"<style:style style:name=\"List\" style:family=\"paragraph\"\n" \
|
||
" style:parent-style-name=\"Standard\"\n" \
|
||
" style:class=\"list\">\n" \
|
||
" <style:paragraph-properties fo:text-align=\"start\" style:justify-single-word=\"false\"/>\n" \
|
||
" <style:text-properties style:font-size-asian=\"12pt\"/>\n" \
|
||
"</style:style>\n" \
|
||
"<style:style style:name=\"Quotations\" style:family=\"paragraph\"\n" \
|
||
" style:parent-style-name=\"Standard\"\n" \
|
||
" style:class=\"html\">\n" \
|
||
" <style:paragraph-properties fo:margin-left=\"0.3937in\" fo:margin-right=\"0.3937in\" fo:margin-top=\"0in\"\n" \
|
||
" fo:margin-bottom=\"0.1965in\"\n" \
|
||
" fo:text-align=\"justify\"" \
|
||
" style:justify-single-word=\"false\"" \
|
||
" fo:text-indent=\"0in\"\n" \
|
||
" style:auto-text-indent=\"false\"/>\n" \
|
||
"</style:style>\n" \
|
||
"<style:style style:name=\"Table_20_Heading\" style:display-name=\"Table Heading\"\n" \
|
||
" style:family=\"paragraph\"\n" \
|
||
" style:parent-style-name=\"Table_20_Contents\"\n" \
|
||
" style:class=\"extra\">\n" \
|
||
" <style:paragraph-properties fo:text-align=\"center\" style:justify-single-word=\"false\"\n" \
|
||
" text:number-lines=\"false\"\n" \
|
||
" text:line-number=\"0\"/>\n" \
|
||
" <style:text-properties fo:font-weight=\"bold\" style:font-weight-asian=\"bold\"\n" \
|
||
" style:font-weight-complex=\"bold\"/>\n" \
|
||
"</style:style>\n" \
|
||
"<style:style style:name=\"Horizontal_20_Line\" style:display-name=\"Horizontal Line\"\n" \
|
||
" style:family=\"paragraph\"\n" \
|
||
" style:parent-style-name=\"Standard\"\n" \
|
||
" style:class=\"html\">\n" \
|
||
" <style:paragraph-properties fo:margin-top=\"0in\" fo:margin-bottom=\"0.1965in\"\n" \
|
||
" style:border-line-width-bottom=\"0.0008in 0.0138in 0.0008in\"\n" \
|
||
" fo:padding=\"0in\"\n" \
|
||
" fo:border-left=\"none\"\n" \
|
||
" fo:border-right=\"none\"\n" \
|
||
" fo:border-top=\"none\"\n" \
|
||
" fo:border-bottom=\"0.0154in double #808080\"\n" \
|
||
" text:number-lines=\"false\"\n" \
|
||
" text:line-number=\"0\"\n" \
|
||
" style:join-border=\"false\"/>\n" \
|
||
" <style:text-properties fo:font-size=\"6pt\" style:font-size-asian=\"6pt\" style:font-size-complex=\"6pt\"/>\n" \
|
||
"</style:style>\n" \
|
||
"<style:style style:name=\"Footnote_20_anchor\" style:display-name=\"Footnote anchor\"" \
|
||
" style:family=\"text\">" \
|
||
" <style:text-properties style:text-position=\"super 58%\"/>" \
|
||
" </style:style>\n" \
|
||
"<style:style style:name=\"TOC_Item\" style:family=\"paragraph\" style:parent-style-name=\"Standard\">\n" \
|
||
" <style:paragraph-properties>\n" \
|
||
" <style:tab-stops>\n" \
|
||
" <style:tab-stop style:position=\"6.7283in\" style:type=\"right\" style:leader-style=\"dotted\" style:leader-text=\".\"/>\n" \
|
||
" </style:tab-stops>\n" \
|
||
" </style:paragraph-properties>\n" \
|
||
"</style:style>\n" \
|
||
" <text:notes-configuration text:note-class=\"footnote\" text:default-style-name=\"Footnote\" text:citation-style-name=\"Footnote_20_Symbol\" text:citation-body-style-name=\"Footnote_20_anchor\" text:master-page-name=\"Footnote\" style:num-format=\"a\" text:start-value=\"0\" text:footnotes-position=\"page\" text:start-numbering-at=\"page\"/>\n" \
|
||
" <text:notes-configuration text:note-class=\"endnote\" text:default-style-name=\"Endnote\" text:citation-style-name=\"Endnote_20_Symbol\" text:citation-body-style-name=\"Endnote_20_anchor\" text:master-page-name=\"Endnote\" style:num-format=\"1\" text:start-value=\"0\"/>\n" \
|
||
"</office:styles>\n");
|
||
|
||
/* Automatic style information */
|
||
print_const("<office:automatic-styles>" \
|
||
" <style:style style:name=\"MMD-Italic\" style:family=\"text\">\n" \
|
||
" <style:text-properties fo:font-style=\"italic\" style:font-style-asian=\"italic\"\n" \
|
||
" style:font-style-complex=\"italic\"/>\n" \
|
||
" </style:style>\n" \
|
||
" <style:style style:name=\"MMD-Bold\" style:family=\"text\">\n" \
|
||
" <style:text-properties fo:font-weight=\"bold\" style:font-weight-asian=\"bold\"\n" \
|
||
" style:font-weight-complex=\"bold\"/>\n" \
|
||
" </style:style>\n" \
|
||
" <style:style style:name=\"MMD-Superscript\" style:family=\"text\">\n" \
|
||
" <style:text-properties style:text-position=\"super 58%\"/>\n" \
|
||
" </style:style>\n" \
|
||
" <style:style style:name=\"MMD-Subscript\" style:family=\"text\">\n" \
|
||
" <style:text-properties style:text-position=\"sub 58%\"/>\n" \
|
||
" </style:style>\n" \
|
||
" <style:style style:name=\"Strike\" style:family=\"text\">\n" \
|
||
" <style:text-properties style:text-line-through-style=\"solid\" />\n" \
|
||
" </style:style>\n" \
|
||
" <style:style style:name=\"Underline\" style:family=\"text\">\n" \
|
||
" <style:text-properties style:text-underline-style=\"solid\" style:text-underline-color=\"font-color\"/>\n" \
|
||
" </style:style>\n" \
|
||
" <style:style style:name=\"Highlight\" style:family=\"text\">\n" \
|
||
" <style:text-properties fo:background-color=\"#FFFF00\" />\n" \
|
||
" </style:style>\n" \
|
||
" <style:style style:name=\"Comment\" style:family=\"text\">\n" \
|
||
" <style:text-properties fo:color=\"#0000BB\" />\n" \
|
||
" </style:style>\n" \
|
||
"<style:style style:name=\"MMD-Table\" style:family=\"paragraph\" style:parent-style-name=\"Standard\">\n" \
|
||
" <style:paragraph-properties fo:margin-top=\"0in\" fo:margin-bottom=\"0.05in\"/>\n" \
|
||
"</style:style>\n" \
|
||
"<style:style style:name=\"MMD-Table-Center\" style:family=\"paragraph\" style:parent-style-name=\"MMD-Table\">\n" \
|
||
" <style:paragraph-properties fo:text-align=\"center\" style:justify-single-word=\"false\"/>\n" \
|
||
"</style:style>\n" \
|
||
"<style:style style:name=\"MMD-Table-Right\" style:family=\"paragraph\" style:parent-style-name=\"MMD-Table\">\n" \
|
||
" <style:paragraph-properties fo:text-align=\"right\" style:justify-single-word=\"false\"/>\n" \
|
||
"</style:style>\n" \
|
||
"<style:style style:name=\"P2\" style:family=\"paragraph\" style:parent-style-name=\"Standard\"\n" \
|
||
" style:list-style-name=\"L2\">\n" \
|
||
"<style:paragraph-properties fo:text-align=\"start\" style:justify-single-word=\"false\"/>\n" \
|
||
"</style:style>\n" \
|
||
"<style:style style:name=\"fr1\" style:family=\"graphic\" style:parent-style-name=\"Frame\">\n" \
|
||
" <style:graphic-properties style:print-content=\"true\" style:vertical-pos=\"top\"\n" \
|
||
" style:vertical-rel=\"baseline\"\n" \
|
||
" fo:padding=\"0in\"\n" \
|
||
" fo:border=\"none\"\n" \
|
||
" style:shadow=\"none\"/>\n" \
|
||
"</style:style>\n" \
|
||
"<style:style style:name=\"P1\" style:family=\"paragraph\" style:parent-style-name=\"Standard\"\n" \
|
||
" style:list-style-name=\"L1\"/>\n" \
|
||
"<text:list-style style:name=\"L1\">\n" \
|
||
" <text:list-level-style-bullet text:level=\"1\" text:style-name=\"Numbering_20_Symbols\" style:num-suffix=\".\" text:bullet-char=\"•\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"0.5in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"0.5in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-bullet>\n" \
|
||
" <text:list-level-style-bullet text:level=\"2\" text:style-name=\"Numbering_20_Symbols\" style:num-suffix=\".\" text:bullet-char=\"◦\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"0.75in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"0.75in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-bullet>\n" \
|
||
" <text:list-level-style-bullet text:level=\"3\" text:style-name=\"Numbering_20_Symbols\" style:num-suffix=\".\" text:bullet-char=\"▪\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"1in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"1in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-bullet>\n" \
|
||
" <text:list-level-style-number text:level=\"4\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"1.25in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"1.25in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"5\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"1.5in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"1.5in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"6\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"1.75in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"1.75in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"7\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"2in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"2in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"8\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"2.25in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"2.25in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"9\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"2.5in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"2.5in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"10\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"2.75in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"2.75in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
"</text:list-style>\n" \
|
||
"<text:list-style style:name=\"L2\">\n" \
|
||
" <text:list-level-style-number text:level=\"1\" text:style-name=\"Standard\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"0.5in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"0.5in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"2\" text:style-name=\"Standard\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"0.75in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"0.75in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"3\" text:style-name=\"Standard\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"1in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"1in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"4\" text:style-name=\"Standard\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"1.25in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"1.25in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"5\" text:style-name=\"Standard\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"1.5in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"1.5in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"6\" text:style-name=\"Standard\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"1.75in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"1.75in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"7\" text:style-name=\"Standard\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"2in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"2in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"8\" text:style-name=\"Standard\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"2.25in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"2.25in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"9\" text:style-name=\"Standard\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"2.5in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"2.5in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
" <text:list-level-style-number text:level=\"10\" text:style-name=\"Standard\" style:num-suffix=\".\" style:num-format=\"1\">\n" \
|
||
" <style:list-level-properties text:list-level-position-and-space-mode=\"label-alignment\">\n" \
|
||
" <style:list-level-label-alignment text:label-followed-by=\"listtab\" text:list-tab-stop-position=\"2.75in\" fo:text-indent=\"-0.25in\" fo:margin-left=\"2.75in\"/>\n" \
|
||
" </style:list-level-properties>\n" \
|
||
" </text:list-level-style-number>\n" \
|
||
"</text:list-style>\n" \
|
||
"</office:automatic-styles>\n" \
|
||
" <office:master-styles>\n" \
|
||
" <style:master-page style:name=\"Endnote\" >\n" \
|
||
" <style:header><text:h text:outline-level=\"2\">Bibliography</text:h></style:header></style:master-page>\n" \
|
||
" <style:master-page style:name=\"Footnote\" style:page-layout-name=\"pm2\"/>\n" \
|
||
" </office:master-styles>\n");
|
||
|
||
// Iterate over metadata keys
|
||
meta * m;
|
||
|
||
if (scratch->meta_hash)
|
||
print_const("<office:meta>\n");
|
||
|
||
for (m = scratch->meta_hash; m != NULL; m = m->hh.next) {
|
||
if (strcmp(m->key, "baseheaderlevel") == 0) {
|
||
} else if (strcmp(m->key, "bibtex") == 0) {
|
||
} else if (strcmp(m->key, "css") == 0) {
|
||
} else if (strcmp(m->key, "htmlfooter") == 0) {
|
||
} else if (strcmp(m->key, "htmlheader") == 0) {
|
||
} else if (strcmp(m->key, "htmlheaderlevel") == 0) {
|
||
} else if (strcmp(m->key, "lang") == 0) {
|
||
} else if (strcmp(m->key, "language") == 0) {
|
||
} else if (strcmp(m->key, "latexbegin") == 0) {
|
||
} else if (strcmp(m->key, "latexconfig") == 0) {
|
||
} else if (strcmp(m->key, "latexfooter") == 0) {
|
||
} else if (strcmp(m->key, "latexheaderlevel") == 0) {
|
||
} else if (strcmp(m->key, "latexinput") == 0) {
|
||
} else if (strcmp(m->key, "latexleader") == 0) {
|
||
} else if (strcmp(m->key, "latexmode") == 0) {
|
||
} else if (strcmp(m->key, "mmdfooter") == 0) {
|
||
} else if (strcmp(m->key, "mmdheader") == 0) {
|
||
} else if (strcmp(m->key, "quoteslanguage") == 0) {
|
||
} else if (strcmp(m->key, "title") == 0) {
|
||
print_const("\t<dc:title>");
|
||
mmd_print_string_odf(out, m->value);
|
||
print_const("</dc:title>\n");
|
||
} else if (strcmp(m->key, "transcludebase") == 0) {
|
||
} else if (strcmp(m->key, "xhtmlheader") == 0) {
|
||
print(m->value);
|
||
print_char('\n');
|
||
} else if (strcmp(m->key, "xhtmlheaderlevel") == 0) {
|
||
} else {
|
||
print_const("\t<meta:user-defined meta:name=\"");
|
||
mmd_print_string_odf(out, m->key);
|
||
print_const("\">");
|
||
mmd_print_string_odf(out, m->value);
|
||
print_const("</meta:user-defined>\n");
|
||
}
|
||
}
|
||
|
||
if (scratch->meta_hash)
|
||
print_const("</office:meta>\n");
|
||
|
||
print_const("<office:body>\n<office:text>\n");
|
||
}
|
||
|
||
|
||
void mmd_end_complete_odf(DString * out, const char * source, scratch_pad * scratch) {
|
||
pad(out, 1, scratch);
|
||
print_const("</office:text>\n</office:body>\n</office:document>");
|
||
}
|
||
|