diff --git a/markdown.c b/markdown.c index db0e0b98..8a45a593 100644 --- a/markdown.c +++ b/markdown.c @@ -102,7 +102,7 @@ int main(int argc, char * argv[]) { g_option_group_add_entries (ext_group, ext_entries); g_option_context_add_group (context, ext_group); g_option_context_set_description (context, "Converts text in specified files (or stdin) from markdown to FORMAT.\n" - "Available FORMATs: html, latex, groff-mm"); + "Available FORMATs: html, latex, groff-mm, odf"); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_print ("option parsing failed: %s\n", error->message); exit (1); @@ -136,6 +136,8 @@ int main(int argc, char * argv[]) { output_format = LATEX_FORMAT; else if (strcmp(opt_to, "groff-mm") == 0) output_format = GROFF_MM_FORMAT; + else if (strcmp(opt_to, "odf") == 0) + output_format = ODF_FORMAT; else { fprintf(stderr, "%s: Unknown output format '%s'\n", progname, opt_to); exit(EXIT_FAILURE); diff --git a/markdown_lib.h b/markdown_lib.h index f1845d3a..bcd6e43c 100644 --- a/markdown_lib.h +++ b/markdown_lib.h @@ -12,7 +12,8 @@ enum markdown_extensions { enum markdown_formats { HTML_FORMAT, LATEX_FORMAT, - GROFF_MM_FORMAT + GROFF_MM_FORMAT, + ODF_FORMAT }; GString * markdown_to_g_string(char *text, int extensions, int output_format); diff --git a/markdown_output.c b/markdown_output.c index f4a43701..b814a4ec 100644 --- a/markdown_output.c +++ b/markdown_output.c @@ -22,8 +22,10 @@ #include #include #include "markdown_peg.h" +#include "odf.c" static int extensions; +static int odf_type = 0; static void print_html_string(GString *out, char *str, bool obfuscate); static void print_html_element_list(GString *out, element *list, bool obfuscate); @@ -34,6 +36,11 @@ static void print_latex_element(GString *out, element *elt); static void print_groff_string(GString *out, char *str); static void print_groff_mm_element_list(GString *out, element *list); static void print_groff_mm_element(GString *out, element *elt, int count); +static void print_odf_code_string(GString *out, char *str); +static void print_odf_string(GString *out, char *str); +static void print_odf_element_list(GString *out, element *list); +static void print_odf_element(GString *out, element *elt); +static bool list_contains_key(element *list, int key); /********************************************************************** @@ -55,6 +62,25 @@ static void pad(GString *out, int num) { padded = num; } +/* determine whether a certain element is contained within a given list */ +bool list_contains_key(element *list, int key) { + element *step = NULL; + + step = list; + while ( step != NULL ) { + if (step->key == key) { + return TRUE; + } + if (step->children != NULL) { + if (list_contains_key(step->children, key)) { + return TRUE; + } + } + step = step->next; + } + return FALSE; +} + /********************************************************************** Functions for printing Elements as HTML @@ -726,6 +752,335 @@ static void print_groff_mm_element(GString *out, element *elt, int count) { } } +/********************************************************************** + + Functions for printing Elements as ODF + + ***********************************************************************/ + +/* print_odf_code_string - print string, escaping for HTML and saving newlines +*/ +static void print_odf_code_string(GString *out, char *str) { + char *tmp; + while (*str != '\0') { + switch (*str) { + case '&': + g_string_append_printf(out, "&"); + break; + case '<': + g_string_append_printf(out, "<"); + break; + case '>': + g_string_append_printf(out, ">"); + break; + case '"': + g_string_append_printf(out, """); + break; + case '\n': + g_string_append_printf(out, ""); + break; + case ' ': + tmp = str; + tmp++; + if (*tmp == ' ') { + tmp++; + if (*tmp == ' ') { + tmp++; + if (*tmp == ' ') { + g_string_append_printf(out, ""); + str = tmp; + } else { + g_string_append_printf(out, " "); + } + } else { + g_string_append_printf(out, " "); + } + } else { + g_string_append_printf(out, " "); + } + break; + default: + g_string_append_c(out, *str); + } + str++; + } +} + +/* print_odf_string - print string, escaping for HTML and saving newlines */ +static void print_odf_string(GString *out, char *str) { + char *tmp; + while (*str != '\0') { + switch (*str) { + case '&': + g_string_append_printf(out, "&"); + break; + case '<': + g_string_append_printf(out, "<"); + break; + case '>': + g_string_append_printf(out, ">"); + break; + case '"': + g_string_append_printf(out, """); + break; + case '\n': + tmp = str; + tmp--; + if (*tmp == ' ') { + tmp--; + if (*tmp == ' ') { + g_string_append_printf(out, ""); + } else { + g_string_append_printf(out, "\n"); + } + } else { + g_string_append_printf(out, "\n"); + } + break; + case ' ': + tmp = str; + tmp++; + if (*tmp == ' ') { + tmp++; + if (*tmp == ' ') { + tmp++; + if (*tmp == ' ') { + g_string_append_printf(out, ""); + str = tmp; + } else { + g_string_append_printf(out, " "); + } + } else { + g_string_append_printf(out, " "); + } + } else { + g_string_append_printf(out, " "); + } + break; + default: + g_string_append_c(out, *str); + } + str++; + } +} + +/* print_odf_element_list - print an element list as ODF */ +void print_odf_element_list(GString *out, element *list) { + while (list != NULL) { + print_odf_element(out, list); + list = list->next; + } +} + +/* print_odf_element - print an element as ODF */ +void print_odf_element(GString *out, element *elt) { + int lev; + int old_type = 0; + switch (elt->key) { + case SPACE: + g_string_append_printf(out, "%s", elt->contents.str); + break; + case LINEBREAK: + g_string_append_printf(out, ""); + break; + case STR: + print_html_string(out, elt->contents.str, 0); + break; + case ELLIPSIS: + g_string_append_printf(out, "…"); + break; + case EMDASH: + g_string_append_printf(out, "—"); + break; + case ENDASH: + g_string_append_printf(out, "–"); + break; + case APOSTROPHE: + g_string_append_printf(out, "’"); + break; + case SINGLEQUOTED: + g_string_append_printf(out, "‘"); + print_odf_element_list(out, elt->children); + g_string_append_printf(out, "’"); + break; + case DOUBLEQUOTED: + g_string_append_printf(out, "“"); + print_odf_element_list(out, elt->children); + g_string_append_printf(out, "”"); + break; + case CODE: + g_string_append_printf(out, ""); + print_html_string(out, elt->contents.str, 0); + g_string_append_printf(out, ""); + break; + case HTML: + break; + case LINK: + g_string_append_printf(out, "contents.link->url, 0); + g_string_append_printf(out, "\""); + if (strlen(elt->contents.link->title) > 0) { + g_string_append_printf(out, " office:name=\""); + print_html_string(out, elt->contents.link->title, 0); + g_string_append_printf(out, "\""); + } + g_string_append_printf(out, ">"); + print_odf_element_list(out, elt->contents.link->label); + g_string_append_printf(out, ""); + break; + case IMAGE: + g_string_append_printf(out, "\ncontents.link->url); + g_string_append_printf(out,"\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\" draw:filter-name=\"<All formats>\"/>\n"); + g_string_append_printf(out, "\n"); + break; + case EMPH: + g_string_append_printf(out, + ""); + print_odf_element_list(out, elt->children); + g_string_append_printf(out, ""); + break; + case STRONG: + g_string_append_printf(out, + ""); + print_odf_element_list(out, elt->children); + g_string_append_printf(out, ""); + break; + case LIST: + print_odf_element_list(out, elt->children); + break; + case RAW: + /* Shouldn't occur - these are handled by process_raw_blocks() */ + assert(elt->key != RAW); + break; + case H1: case H2: case H3: case H4: case H5: case H6: + lev = elt->key - H1 + 1; /* assumes H1 ... H6 are in order */ + g_string_append_printf(out, "", lev); + print_odf_element_list(out, elt->children); + g_string_append_printf(out, "\n"); + padded = 0; + break; + case PLAIN: + print_odf_element_list(out, elt->children); + padded = 0; + break; + case PARA: + g_string_append_printf(out, ""); + print_odf_element_list(out, elt->children); + g_string_append_printf(out, "\n"); + break; + case HRULE: + g_string_append_printf(out,"\n"); + break; + case HTMLBLOCK: + /* don't print HTML block */ + /* but do print HTML comments for raw ODF */ + if (strncmp(elt->contents.str,"" from end */ + elt->contents.str[strlen(elt->contents.str)-3] = '\0'; + g_string_append_printf(out, "%s", &elt->contents.str[4]); + } + break; + case VERBATIM: + old_type = odf_type; + odf_type = VERBATIM; + g_string_append_printf(out, ""); + print_odf_code_string(out, elt->contents.str); + g_string_append_printf(out, "\n"); + odf_type = old_type; + break; + case BULLETLIST: + if ((odf_type == BULLETLIST) || + (odf_type == ORDEREDLIST)) { + /* I think this was made unnecessary by another change. + Same for ORDEREDLIST below */ + /* g_string_append_printf(out, ""); */ + } + old_type = odf_type; + odf_type = BULLETLIST; + g_string_append_printf(out, "%s", ""); + print_odf_element_list(out, elt->children); + g_string_append_printf(out, "%s", ""); + odf_type = old_type; + break; + case ORDEREDLIST: + if ((odf_type == BULLETLIST) || + (odf_type == ORDEREDLIST)) { + /* g_string_append_printf(out, ""); */ + } + old_type = odf_type; + odf_type = ORDEREDLIST; + g_string_append_printf(out, "%s", "\n"); + print_odf_element_list(out, elt->children); + g_string_append_printf(out, "%s", "\n"); + odf_type = old_type; + break; + case LISTITEM: + g_string_append_printf(out, "\n"); + if (elt->children->children->key != PARA) { + g_string_append_printf(out, ""); + } + print_odf_element_list(out, elt->children); + + if ((list_contains_key(elt->children,BULLETLIST) || + (list_contains_key(elt->children,ORDEREDLIST)))) { + } else { + if (elt->children->children->key != PARA) { + g_string_append_printf(out, ""); + } + } + g_string_append_printf(out, "\n"); + break; + case BLOCKQUOTE: + old_type = odf_type; + odf_type = BLOCKQUOTE; + print_odf_element_list(out, elt->children); + odf_type = old_type; + break; + case REFERENCE: + break; + case NOTE: + old_type = odf_type; + odf_type = NOTE; + /* if contents.str == 0 then print; else ignore - like above */ + if (elt->contents.str == 0) { + g_string_append_printf(out, "\n"); + print_odf_element_list(out, elt->children); + g_string_append_printf(out, "\n\n"); + } + elt->children = NULL; + odf_type = old_type; + break; + break; default: + fprintf(stderr, "print_odf_element encountered unknown element key = %d\n", elt->key); + exit(EXIT_FAILURE); + } +} + /********************************************************************** Parameterized function for printing an Element. @@ -753,6 +1108,12 @@ void print_element_list(GString *out, element *elt, int format, int exts) { case GROFF_MM_FORMAT: print_groff_mm_element_list(out, elt); break; + case ODF_FORMAT: + print_odf_header(out); + g_string_append_printf(out, "\n\n"); + if (elt != NULL) print_odf_element_list(out,elt); + print_odf_footer(out); + break; default: fprintf(stderr, "print_element - unknown format = %d\n", format); exit(EXIT_FAILURE);