diff --git a/CMakeLists.txt b/CMakeLists.txt index 436a193..72b4111 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,15 +148,12 @@ endif () # Need to build parser.c via greg -add_custom_target( - greg - COMMAND make - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/submodules/greg +add_subdirectory (${PROJECT_SOURCE_DIR}/submodules/greg ) add_custom_command ( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/parser.c - COMMAND ${PROJECT_SOURCE_DIR}/submodules/greg/greg -o ${CMAKE_CURRENT_BINARY_DIR}/parser.c ${PROJECT_SOURCE_DIR}/src/parser.leg + COMMAND $ -o ${CMAKE_CURRENT_BINARY_DIR}/parser.c ${PROJECT_SOURCE_DIR}/src/parser.leg DEPENDS greg ) @@ -419,6 +416,14 @@ set_target_properties(multimarkdown PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH # Link the library to the app target_link_libraries(multimarkdown libMultiMarkdown) +if (WIN32) + find_library (GETOPT wingetopt + ) + target_link_libraries (multimarkdown wingetopt + ) + include_directories (${PROJECT_SOURCE_DIR}/submodules/greg/MSVC + ) +endif() # ========================== # Build Installer with CPack diff --git a/src/GLibFacade.c b/src/GLibFacade.c index e56a71e..b4cd0cb 100644 --- a/src/GLibFacade.c +++ b/src/GLibFacade.c @@ -49,25 +49,25 @@ */ /* Solaris and Windows do not provide vasprintf() or asprintf(). */ -#if defined(__WIN32) || (defined(__SVR4) && defined(__sun)) -int vasprintf( char **sptr, char *fmt, va_list argv ) -{ - int wanted = vsnprintf( *sptr = NULL, 0, fmt, argv ); - if( (wanted > 0) && ((*sptr = malloc( 1 + wanted )) != NULL) ) - return vsprintf( *sptr, fmt, argv ); - - return wanted; -} - -int asprintf( char **sptr, char *fmt, ... ) -{ - int retval; - va_list argv; - va_start( argv, fmt ); - retval = vasprintf( sptr, fmt, argv ); - va_end( argv ); - return retval; -} +#if defined(__WIN32) || defined(_WIN32) || (defined(__SVR4) && defined(__sun)) +int vasprintf( char **sptr, char *fmt, va_list argv ) +{ + int wanted = vsnprintf( *sptr = NULL, 0, fmt, argv ); + if( (wanted > 0) && ((*sptr = malloc( 1 + wanted )) != NULL) ) + return vsprintf( *sptr, fmt, argv ); + + return wanted; +} + +int asprintf( char **sptr, char *fmt, ... ) +{ + int retval; + va_list argv; + va_start( argv, fmt ); + retval = vasprintf( sptr, fmt, argv ); + va_end( argv ); + return retval; +} #endif diff --git a/src/GLibFacade.h b/src/GLibFacade.h index 352010a..b299a2e 100644 --- a/src/GLibFacade.h +++ b/src/GLibFacade.h @@ -32,13 +32,9 @@ #ifndef __MARKDOWN_GLIB_FACADE__ #define __MARKDOWN_GLIB_FACADE__ -/* peg_markdown uses the link symbol for its own purposes */ -#define link MARKDOWN_LINK_IGNORED -#include -#undef link - #include #include +#include typedef int gboolean; typedef char gchar; @@ -51,15 +47,21 @@ typedef char gchar; #define TRUE true #endif -/* WE implement minimal mirror implementations of GLib's GString and GSList +#ifdef _WIN32 +#define DllExport __declspec( dllexport ) +#else +#define DllExport +#endif + +/* WE implement minimal mirror implementations of GLib's GString and GSList * sufficient to cover the functionality required by MultiMarkdown. * * NOTE: THese are 100% clean, from-scratch implementations using only the * GLib function prototype as guide for behavior. */ -typedef struct -{ +typedef struct DllExport +{ /* Current UTF8 byte stream this string represents */ char* str; @@ -69,21 +71,21 @@ typedef struct unsigned long currentStringLength; } GString; -GString* g_string_new(const char *startingString); -char* g_string_free(GString* ripString, bool freeCharacterData); +DllExport GString* g_string_new(const char *startingString); +DllExport char* g_string_free(GString* ripString, bool freeCharacterData); -void g_string_append_c(GString* baseString, char appendedCharacter); -void g_string_append(GString* baseString, char *appendedString); +DllExport void g_string_append_c(GString* baseString, char appendedCharacter); +DllExport void g_string_append(GString* baseString, char *appendedString); -void g_string_prepend(GString* baseString, char* prependedString); +DllExport void g_string_prepend(GString* baseString, char* prependedString); -void g_string_append_printf(GString* baseString, char* format, ...); +DllExport void g_string_append_printf(GString* baseString, char* format, ...); -void g_string_insert(GString* baseString, size_t pos, char * insertedString); -void g_string_insert_c(GString* baseString, size_t pos, char insertedCharacter); -void g_string_insert_printf(GString* baseString, size_t pos, char* format, ...); +DllExport void g_string_insert(GString* baseString, size_t pos, char * insertedString); +DllExport void g_string_insert_c(GString* baseString, size_t pos, char insertedCharacter); +DllExport void g_string_insert_printf(GString* baseString, size_t pos, char* format, ...); -void g_string_erase(GString* baseString, size_t pos, size_t len); +DllExport void g_string_erase(GString* baseString, size_t pos, size_t len); /* Just implement a very simple singly linked list. */ diff --git a/src/libMultiMarkdown.h b/src/libMultiMarkdown.h index 24f0547..e304c09 100644 --- a/src/libMultiMarkdown.h +++ b/src/libMultiMarkdown.h @@ -61,6 +61,12 @@ #ifndef LIB_MULTIMARKDOWN_H #define LIB_MULTIMARKDOWN_H +#ifdef _WIN32 +#define DllExport __declspec( dllexport ) +#else +#define DllExport +#endif + #include /* Main API commands */ @@ -68,7 +74,7 @@ /// Convert source string to output string, based on provided `parser_extensions` /// and requested `export_format`. /// The returned `char *` will need to be freed after it is no longer needed. -char * markdown_to_string( +DllExport char * markdown_to_string( const char * source, //!< Pointer to c-string of the source text unsigned long extensions, //!< Bit field of parser_extensions int format //!< Specify export_format to be used @@ -76,21 +82,21 @@ char * markdown_to_string( /// Does the source string have metadata, using provided `parser_extensions`? /// -bool has_metadata( +DllExport bool has_metadata( const char *source, //!< Pointer to c-string of the source text unsigned long extensions //!< Bit field of parser_extensions ); /// List all metadata keys, using provided `parser_extensions`. /// The returned `char *` will need to be freed after it is no longer needed. -char * extract_metadata_keys( +DllExport char * extract_metadata_keys( const char *source, //!< Pointer to c-string of the source text unsigned long extensions //!< Bit field of parser_extensions ); /// Extract the value for the specified metadata key, using provided `parser_extensions`. /// The returned `char *` will need to be freed after it is no longer needed. -char * extract_metadata_value( +DllExport char * extract_metadata_value( const char *source, //!< Pointer to c-string of the source text unsigned long extensions, //!< Bit field of parser_extensions char *key //!< C-string of the key we need to find @@ -98,7 +104,7 @@ char * extract_metadata_value( /// Return the version string for this build of libMultiMarkdown /// The returned `char *` will need to be freed after it is no longer needed. -char * mmd_version(void); +DllExport char * mmd_version(void); /// These are the basic extensions that enable or disable MultiMarkdown features diff --git a/src/multimarkdown.c b/src/multimarkdown.c index 506be63..49c7134 100644 --- a/src/multimarkdown.c +++ b/src/multimarkdown.c @@ -59,11 +59,29 @@ #include -#include #include "parser.h" #include "transclude.h" #include "version.h" +#ifndef _WIN32 + +#include + +#else + +#define strdup _strdup +#define setmode _setmode +#define fileno _fileno + +static char* dirname(char* path) +{ + static char dir[512]; + _splitpath(path, NULL, dir, NULL, NULL); + return dir; +} + +#endif + /// main() int main(int argc, char **argv) { diff --git a/src/parse_utilities.c b/src/parse_utilities.c index ee94d81..3ab79f3 100644 --- a/src/parse_utilities.c +++ b/src/parse_utilities.c @@ -21,7 +21,6 @@ #include "parser.h" #include "version.h" -#include #pragma mark - Parse Tree diff --git a/src/parser.leg b/src/parser.leg index 816c97d..9f899ae 100644 --- a/src/parser.leg +++ b/src/parser.leg @@ -3,17 +3,17 @@ parser.leg -> parser.c -- Parse (Multi)Markdown plain text for conversion into other formats - + (c) 2013-2016 Fletcher T. Penney (http://fletcherpenney.net/). Derived from peg-multimarkdown, which was forked from peg-markdown, - which is (c) 2008 John MacFarlane (jgm at berkeley dot edu), and + which is (c) 2008 John MacFarlane (jgm at berkeley dot edu), and licensed under GNU GPL or MIT. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License or the MIT license. See LICENSE for details. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -23,6 +23,10 @@ #include "parser.h" #include "writer.h" +#if _WIN32 +#define strtok_r strtok_s +#endif + /* Define shortcuts to adding nodes, etc. */ #define node(x) mk_node(x) @@ -33,7 +37,7 @@ #define YY_INPUT(buf, result, max_size, D) yy_input_func(buf, &result, max_size, (parser_data *)G->data) -/* redefine input buffer so that we draw from the specified source string +/* redefine input buffer so that we draw from the specified source string to make it thread/reentrant safe */ void yy_input_func(char *buf, int *result, int max_size, parser_data *data) { \ @@ -353,7 +357,7 @@ NormalEndline = Sp Newline !BlankLine !'>' !AtxStart !(RawLine ('='+ | '-'+) Newline) { $$ = str("\n"); - $$->key = SPACE; + $$->key = SPACE; } TerminalEndline = Sp Newline Eof @@ -496,7 +500,7 @@ EmphUl = EmphUlOpen &OneTwoStar ( StrongStar | EmphStar ) | - BracketedText | + BracketedText | MathText | (!'_' !(BlankLine BlankLine) .) )* @@ -528,8 +532,8 @@ StrongStar = StrongStarOpen &OneStar ( EmphStar ) | - BracketedText | - MathText | + BracketedText | + MathText | (!'*' !Whitespace .) | (!'*' !(BlankLine BlankLine) !(Whitespace '*') .) )* @@ -549,8 +553,8 @@ StrongUl = StrongUlOpen &OneTwoStar ( StrongStar | EmphStar ) | - BracketedText | - MathText | + BracketedText | + MathText | (!'_' !(BlankLine BlankLine) .) )* StrongUlClose @@ -576,14 +580,14 @@ ReferenceLinkSingle = ( a:Label < (Spnl "[]")? > ) } CitationReference = CitationReferenceDouble | CitationReferenceSingle - + CitationReferenceDouble = !"[]" !"[#" a:Label < Spnl > !"[]" b:RawCitationReference { char *label; label = label_from_node_tree(a); $$ = mk_link(a, b->str, NULL, NULL, NULL); $$->key = CITATION; - + if (strcmp(label,"notcited") == 0) $$->key = NOCITATION; free(label); @@ -647,13 +651,13 @@ LinkReference = a:StartList NonindentSpace !"[]" l:Label ':' Spnl s:RefSrc t:RefTitle ( &{ !ext(EXT_COMPATIBILITY) } BlankLine+ - { + { /* Get label for referencing */ GString *text = g_string_new(""); char *clean; print_raw_node_tree(text, l->children); clean = clean_string(text->str); - + if (a == NULL) { /* no attributes */ $$ = mk_link(NULL, clean, s->str, t->str, NULL); @@ -743,7 +747,7 @@ Image = '!' ( !AutoLink Link ) } Label = &( '[' ) - < BracketedText > + < BracketedText > { yytext[strlen(yytext) - 1] = '\0'; @@ -770,7 +774,7 @@ AutoLabel = '[' < (!Newline !'^' !'#' !'%' . )( !Newline !']' !'[' . )+ > ']' &( node *ref; $$ = str(yytext); $$->key = AUTOLABEL; - + /* And create a LINKREFERENCE so we can use it */ char *label = label_from_string(yytext); GString *anchor = g_string_new(label); @@ -795,13 +799,13 @@ NoteReference = &{ ext(EXT_NOTES) } ( "[^" ) < ( !(Newline BlankLine) !']' RawIn /* Create a note reference */ $$ = str(yytext); $$->key = NOTEREFERENCE; - + /* Include RAW version for parsing in case this is an inline footnote */ node *raw = str(original->str); raw->key = RAW; node *source = list(NOTESOURCE, raw); source->str = strdup(""); - + $$->children = source; g_string_free(original, true); @@ -810,7 +814,7 @@ NoteReference = &{ ext(EXT_NOTES) } ( "[^" ) < ( !(Newline BlankLine) !']' RawIn Glossary = &{ ext(EXT_NOTES) } a:StartList NonindentSpace ref:RawNoteReference ':' Sp - "glossary:" Sp (GlossaryTerm { a = cons($$, a); }) + "glossary:" Sp (GlossaryTerm { a = cons($$, a); }) (GlossarySortKey { a = cons($$, a); })? Newline ( RawNoteBlock { a = cons($$, a); } ) @@ -826,7 +830,7 @@ Glossary = &{ ext(EXT_NOTES) } } GlossaryTerm = < (!Newline !'(' .)+ > - { + { $$ = list(LIST, NULL); $$->str = 0; $$->children = str(yytext); @@ -968,10 +972,10 @@ Term = a:StartList !BlankLine !':' Definition = (a:StartList b:StartList (BlankLine { b = cons(str("\n"),b); } )? - ( NonindentSpace ':' Sp RawLine { a = cons(str(yytext), a);}) + ( NonindentSpace ':' Sp RawLine { a = cons(str(yytext), a);}) ( !':' !BlankLine RawLine { a = cons(str(yytext), a);})* ( BlankLine {a = cons(str("\n"),a);} - (IndentedLine { a = cons($$,a);})+ + (IndentedLine { a = cons($$,a);})+ { a = cons(str("\n"),a);} )* ) { @@ -1383,7 +1387,7 @@ StyleBlock = < InStyleTags > Table = a:StartList b:StartList (TableCaption { b = cons($$, b);})? (TableBody { $$->key = TABLEHEAD; a = cons($$, a); })? - (SeparatorLine { + (SeparatorLine { if (a == NULL) a = $$; else @@ -1435,7 +1439,7 @@ EmptyCell = CellDivider $$ = node(TABLECELL); } -SeparatorLine = a:StartList +SeparatorLine = a:StartList &(TableLine) CellDivider? ( &HeaderAlignmentCell AlignmentCell { a = cons(str("h"), a); a = cons($$, a);} @@ -1521,7 +1525,7 @@ Note = &{ ext(EXT_NOTES) } a = cons(label,a); $$ = list(NOTESOURCE, a); $$->str = strdup(ref->str); - + free_node(ref); } @@ -1533,7 +1537,7 @@ RawNoteBlock = a:StartList $$->key = RAW; } -DocForOPML = BOM? a:StartList +DocForOPML = BOM? a:StartList ( &{ !ext(EXT_COMPATIBILITY) } &( (YAMLStart)? MetaDataKey Sp ':' Sp (!Newline)) MetaData { a = cons($$, a); })? ( OPMLBlock { a = cons($$, a); } )* @@ -1548,8 +1552,8 @@ OPMLHeadingSection = a:StartList OPMLHeading { a = cons($$, a); } OPMLHeading = OPMLAtxHeading | OPMLSetextHeading -OPMLAtxHeading = &(Heading) s:AtxStart Sp - < (!Newline !(Sp '#'* Sp Newline) .)* > +OPMLAtxHeading = &(Heading) s:AtxStart Sp + < (!Newline !(Sp '#'* Sp Newline) .)* > (Sp '#'+)? Sp Newline { $$ = str(yytext); @@ -1559,7 +1563,7 @@ OPMLAtxHeading = &(Heading) s:AtxStart Sp OPMLSetextHeading = OPMLSetextHeading1 | OPMLSetextHeading2 -OPMLSetextHeading1 = < (!'\r' !'\n' .)* > Newline SetextBottom1 +OPMLSetextHeading1 = < (!'\r' !'\n' .)* > Newline SetextBottom1 { $$ = str(yytext); $$->key = H1; } OPMLSetextHeading2 = < (!'\r' !'\n' .)* > Newline SetextBottom2 @@ -1699,16 +1703,16 @@ node * process_raw_blocks(node * n, unsigned long extensions) { GREG g; current = n; - + while (current != NULL) { if (current->key == RAW) { /* Process this RAW block */ - + yyinit(&g); contents = strtok_r(current->str, "\001", &saveptr); current->key = LIST; g.data = mk_parser_data(contents, (extensions | EXT_NO_METADATA )); - + /* An endless loop was discovered by a user: @@ -1719,7 +1723,7 @@ node * process_raw_blocks(node * n, unsigned long extensions) { 1. \ - The parser repeatedly asks for yy_input_func, which returns 0. And the + The parser repeatedly asks for yy_input_func, which returns 0. And the parser then cycles through every possible match over and over and over. I haven't found the problem, but can institute a failsafe by ensuring that @@ -1733,18 +1737,18 @@ node * process_raw_blocks(node * n, unsigned long extensions) { //while (yyparse(&g)); while ((yyparse(&g)) && (*d->charbuf != '\0')); - + current->children = ((parser_data *)g.data)->result; - + free((parser_data *)g.data); /* we're not using free_parser_data to preserve result tree */ - + yydeinit(&g); - + last_child = current->children; while ((contents = strtok_r(NULL, "\001", &saveptr))) { - while (last_child->next != NULL) + while (last_child->next != NULL) last_child = last_child->next; - + yyinit(&g); g.data = mk_parser_data(contents, (extensions | EXT_NO_METADATA )); while (yyparse(&g)); @@ -1766,11 +1770,11 @@ node * process_raw_blocks(node * n, unsigned long extensions) { node * markdown_chunk_to_node(const char * source, unsigned long extensions) { - /* + /* Designed for parsing 'chunks' of markdown from inside a specific range, e.g. a label from '[' ... ']' that can have various markup inside - Prevents situations where the parser gets greedy and goes beyond the + Prevents situations where the parser gets greedy and goes beyond the intended boundaries. */ @@ -1809,7 +1813,7 @@ node * parse_markdown(const char * source, unsigned long extensions, int format) if (target_meta_key != NULL) { temp = label_from_string(target_meta_key); if (strcmp(temp, "beamer") == 0) { - extensions = extensions | EXT_HEADINGSECTION; + extensions = extensions | EXT_HEADINGSECTION; } free(temp); } @@ -1820,7 +1824,7 @@ node * parse_markdown(const char * source, unsigned long extensions, int format) g.data = mk_parser_data(source, extensions); while (yyparse_from(&g, yy_DocForCritic)); - + if (extensions & EXT_CRITIC_REJECT) { if ((extensions & EXT_CRITIC_ACCEPT)) { if(format == HTML_FORMAT) { @@ -1844,9 +1848,9 @@ node * parse_markdown(const char * source, unsigned long extensions, int format) } else { formatted = preformat_text(source); } - + g.data = mk_parser_data(formatted,extensions); - + if (format == OPML_FORMAT) { while (yyparse_from(&g, yy_DocForOPML)); /* We want simpler version */ } else if (format == TOC_FORMAT) { @@ -1864,9 +1868,9 @@ node * parse_markdown(const char * source, unsigned long extensions, int format) /* clean up */ free_parser_data((parser_data *)g.data); yydeinit(&g); - + free(formatted); - + return NULL; } @@ -1876,22 +1880,22 @@ node * parse_markdown(const char * source, unsigned long extensions, int format) if (((parser_data *)g.data)->autolabels != NULL) { // fprintf(stderr, "We have autolabels\n"); append_list(((parser_data *)g.data)->autolabels,refined); - ((parser_data *)g.data)->autolabels = NULL; + ((parser_data *)g.data)->autolabels = NULL; } else { // fprintf(stderr, "No autolabels\n"); } - + /* clean up */ free_parser_data_preserving_result((parser_data *)g.data); yydeinit(&g); - + free(formatted); return refined; } -char * markdown_to_string(const char * source, unsigned long extensions, int format) { +char * markdown_to_string(const char * source, unsigned long extensions, int format) { char * output; node * parse_tree; @@ -1918,10 +1922,10 @@ bool has_metadata(const char *source, unsigned long extensions) { yyinit(&g); node *result; bool answer = FALSE; - + formatted = preformat_text(source); g.data = mk_parser_data(formatted, extensions); - + while (yyparse_from(&g, yy_DocForMetaDataOnly)); /* We want simpler version */ result = ((parser_data *)g.data)->result; @@ -1932,7 +1936,7 @@ bool has_metadata(const char *source, unsigned long extensions) { free_parser_data((parser_data *)g.data); yydeinit(&g); - + free(formatted); return answer; } @@ -1944,11 +1948,11 @@ char * extract_metadata_keys(const char *source, unsigned long extensions) { char *formatted; GREG g; yyinit(&g); - + /* don't preformat if doing syntax highlighting */ formatted = preformat_text(source); g.data = mk_parser_data(formatted,extensions); - + while (yyparse_from(&g, yy_DocForMetaDataOnly)); /* We want simpler version */ if (((parser_data *)g.data)->parse_aborted) { @@ -1956,10 +1960,10 @@ char * extract_metadata_keys(const char *source, unsigned long extensions) { } else { out = metadata_keys(((parser_data *)g.data)->result); } - + free_parser_data((parser_data *)g.data); yydeinit(&g); - + free(formatted); return out; } @@ -1971,11 +1975,11 @@ char * extract_metadata_value(const char *source, unsigned long extensions, char char *formatted; GREG g; yyinit(&g); - + /* don't preformat if doing syntax highlighting */ formatted = preformat_text(source); g.data = mk_parser_data(formatted,extensions); - + while (yyparse_from(&g, yy_DocForMetaDataOnly)); /* We want simpler version */ if (((parser_data *)g.data)->parse_aborted) { @@ -1983,11 +1987,11 @@ char * extract_metadata_value(const char *source, unsigned long extensions, char } else { out = metavalue_for_key(key,((parser_data *)g.data)->result); } - - + + free_parser_data((parser_data *)g.data); yydeinit(&g); - + free(formatted); return out; } diff --git a/src/transclude.h b/src/transclude.h index 45b5b13..6bad818 100644 --- a/src/transclude.h +++ b/src/transclude.h @@ -19,10 +19,15 @@ #include #include #include -#include #include "GLibFacade.h" -char * source_without_metadata(char * source, unsigned long extensions); -void transclude_source(GString *source, char *basedir, char *stack, int format, GString *manifest); -void append_mmd_footer(GString *source); -void prepend_mmd_header(GString *source); +#ifdef _WIN32 +#define DllExport __declspec( dllexport ) +#else +#define DllExport +#endif + +DllExport char * source_without_metadata(char * source, unsigned long extensions); +DllExport void transclude_source(GString *source, char *basedir, char *stack, int format, GString *manifest); +DllExport void append_mmd_footer(GString *source); +DllExport void prepend_mmd_header(GString *source); diff --git a/src/writer.h b/src/writer.h index 2175cc3..559e17f 100644 --- a/src/writer.h +++ b/src/writer.h @@ -13,6 +13,12 @@ #include "critic.h" #include "toc.h" +# if _WIN32 +#define strdup _strdup +#define setmode _setmode +#define fileno _fileno +#endif + char * export_node_tree(node *list, int format, unsigned long extensions); void extract_references(node *list, scratch_pad *scratch); diff --git a/submodules/greg b/submodules/greg index 265003c..64d071c 160000 --- a/submodules/greg +++ b/submodules/greg @@ -1 +1 @@ -Subproject commit 265003c8cb3022183f48df3e2684336b788af39d +Subproject commit 64d071cabd225c1dd43cc9bab63827053c1b2cec