├── .gitignore ├── .gitmodules ├── Configuration ├── Common.xcconfig ├── Debug.xcconfig ├── Release.xcconfig └── Release10.6+.xcconfig ├── GLibFacade.c ├── GLibFacade.h ├── LICENSE ├── MMD-Compat.xcodeproj ├── fletcher.mode1v3 ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── fletcher.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── fletcher.xcuserdatad │ └── xcschemes │ ├── MakefileBuild.xcscheme │ ├── MultiMarkdown.xcscheme │ ├── Peg.xcscheme │ ├── Run Tests.xcscheme │ ├── libMultiMarkdown.xcscheme │ └── xcschememanagement.plist ├── Makefile ├── MarkdownMacPrefix.h ├── MultiMarkdown.xcodeproj └── project.pbxproj ├── README ├── README.markdown ├── TODO.txt ├── glib.h ├── mac_installer ├── Make OS X Installer.pmdoc │ ├── 01package-contents.xml │ ├── 01package.xml │ └── index.xml ├── Make Support Installer.pmdoc │ ├── 01library-contents.xml │ ├── 01library.xml │ └── index.xml ├── README.markdown └── Resources │ ├── Support_Welcome.txt │ └── Welcome.txt ├── markdown.c ├── markdown_lib.c ├── markdown_lib.h ├── markdown_output.c ├── markdown_parser.leg ├── markdown_peg.h ├── odf.c ├── odf.h ├── parsing_functions.c ├── parsing_functions.h ├── peg-0.1.9 ├── Makefile ├── compile.c ├── examples │ ├── Makefile │ ├── accept.c │ ├── accept.peg │ ├── accept.ref │ ├── basic.leg │ ├── basic.ref │ ├── bench.bas │ ├── calc.leg │ ├── calc.ref │ ├── dc.c │ ├── dc.peg │ ├── dc.ref │ ├── dcv.c │ ├── dcv.peg │ ├── dcv.ref │ ├── fibonacci.bas │ ├── left.c │ ├── left.peg │ ├── localctx.c │ ├── localctx.ref │ ├── rule.c │ ├── rule.peg │ ├── rule.ref │ ├── test.bas │ ├── test.c │ ├── test.peg │ ├── test.ref │ ├── username.leg │ ├── wc.leg │ └── wc.ref ├── leg.c ├── leg.leg ├── peg.1 ├── peg.c ├── peg.peg ├── peg.peg-c ├── tree.c ├── tree.h └── version.h ├── scripts ├── mmd ├── mmd2all ├── mmd2odf ├── mmd2opml ├── mmd2pdf └── mmd2tex ├── update_submodules.sh ├── utility_functions.c ├── utility_functions.h └── windows_installer ├── Installer support files └── logotype.png ├── install_multimarkdown.bat ├── mmd.bat ├── mmd2odf.bat ├── mmd2opml.bat ├── mmd2tex.bat └── multimarkdown.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | project.xcworkspace 3 | xcuserdata 4 | 5 | build/* 6 | speed/* 7 | 8 | test.* 9 | testing/* 10 | 11 | *.o 12 | markdown_parser.c 13 | /markdown 14 | /multimarkdown 15 | /multimarkdown.exe 16 | 17 | peg-0.1.4/peg 18 | peg-0.1.4/leg 19 | 20 | /mac_installer/Resources/*.html 21 | /mac_installer/Package_Root/usr/local/bin/multimarkdown 22 | 23 | /windows_installer/README.txt 24 | /windows_installer/*.zip 25 | /windows_installer/*.exe 26 | /windows_installer/*.xml.backup 27 | /windows_installer/License.html 28 | 29 | /old_zips/ 30 | 31 | /drag/ 32 | 33 | /manual/ 34 | 35 | *.pbxuser 36 | *.perspectivev3 37 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "MarkdownTest"] 2 | path = MarkdownTest 3 | url = https://github.com/fletcher/MMD-Test-Suite.git 4 | [submodule "Support"] 5 | path = Support 6 | url = https://github.com/fletcher/MMD-Support.git 7 | [submodule "documentation"] 8 | path = documentation 9 | url = https://github.com/fletcher/peg-multimarkdown.wiki.git 10 | [submodule "samples"] 11 | path = samples 12 | url = https://github.com/fletcher/MultiMarkdown-Gallery.git 13 | -------------------------------------------------------------------------------- /Configuration/Common.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Release10.6+.xcconfig 3 | // MultiMarkdown 4 | // 5 | // Created by Daniel Jalkut on 7/29/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator 10 | ARCHS[sdk=macosx*] = i386 x86_64 11 | ARCHS[sdk=iphoneos*] = armv6 armv7 12 | ARCHS[sdk=iphonesimulator*] = i386 13 | VALID_ARCHS[sdk=iphoneos*] = armv6 armv7 14 | VALID_ARCHS[sdk=iphonesimulator*] = i386 15 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 16 | GCC_VERSION = 17 | GCC_VERSION[arch=x86_64] = com.apple.compilers.llvm.clang.1_0 18 | DEPLOYMENT_POSTPROCESSING = YES 19 | MACOSX_DEPLOYMENT_TARGET = 10.4 20 | MACOSX_DEPLOYMENT_TARGET[arch=x86_64] = 10.6 21 | GCC_MODEL_TUNING = G5 22 | OTHER_CFLAGS = -DSTANDALONE_MAC_VERSION=1 23 | GCC_PREFIX_HEADER = MarkdownMacPrefix.h 24 | GCC_PRECOMPILE_PREFIX_HEADER = YES 25 | -------------------------------------------------------------------------------- /Configuration/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Release10.6+.xcconfig 3 | // MultiMarkdown 4 | // 5 | // Created by Daniel Jalkut on 7/29/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #include "Common.xcconfig" 10 | 11 | ARCHS = i386 ppc x86_64 12 | ONLY_ACTIVE_ARCH = YES 13 | GCC_OPTIMIZATION_LEVEL = 0 14 | DEPLOYMENT_POSTPROCESSING = NO 15 | -------------------------------------------------------------------------------- /Configuration/Release.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Release10.6+.xcconfig 3 | // MultiMarkdown 4 | // 5 | // Created by Daniel Jalkut on 7/29/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #include "Common.xcconfig" 10 | 11 | COPY_PHASE_STRIP = NO 12 | STRIP_INSTALLED_PRODUCT = YES 13 | SEPARATE_STRIP = YES 14 | -------------------------------------------------------------------------------- /Configuration/Release10.6+.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Release10.6+.xcconfig 3 | // MultiMarkdown 4 | // 5 | // Created by Daniel Jalkut on 7/29/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #include "Release.xcconfig" 10 | 11 | ARCHS = i386 x86_64 12 | GCC_VERSION = 13 | GCC_VERSION[arch=x86_64] = com.apple.compilers.llvm.clang.1_0 14 | DEPLOYMENT_POSTPROCESSING = YES 15 | MACOSX_DEPLOYMENT_TARGET = 10.6 16 | COPY_PHASE_STRIP = NO 17 | STRIP_INSTALLED_PRODUCT = YES 18 | SEPARATE_STRIP = YES 19 | GCC_MODEL_TUNING = G5 20 | OTHER_CFLAGS = -DSTANDALONE_MAC_VERSION=1 21 | GCC_PREFIX_HEADER = MarkdownMacPrefix.h 22 | GCC_PRECOMPILE_PREFIX_HEADER = YES 23 | -------------------------------------------------------------------------------- /GLibFacade.c: -------------------------------------------------------------------------------- 1 | /* 2 | * GLibFacade.c 3 | * MultiMarkdown 4 | * 5 | * Created by Daniel Jalkut on 7/26/11. 6 | * Modified by Fletcher T. Penney on 9/15/11. 7 | * Modified by Dan Lowe on 1/3/12. 8 | * Copyright 2011 __MyCompanyName__. All rights reserved. 9 | */ 10 | 11 | #include "GLibFacade.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | /* 19 | * The following section came from: 20 | * 21 | * http://lists-archives.org/mingw-users/12649-asprintf-missing-vsnprintf- 22 | * behaving-differently-and-_vsncprintf-undefined.html 23 | * 24 | * and 25 | * 26 | * http://groups.google.com/group/jansson-users/browse_thread/thread/ 27 | * 76a88d63d9519978/041a7d0570de2d48?lnk=raot 28 | */ 29 | 30 | /* Solaris and Windows do not provide vasprintf() or asprintf(). */ 31 | #if defined(__WIN32) || (defined(__SVR4) && defined(__sun)) 32 | int vasprintf( char **sptr, char *fmt, va_list argv ) 33 | { 34 | int wanted = vsnprintf( *sptr = NULL, 0, fmt, argv ); 35 | if( (wanted > 0) && ((*sptr = malloc( 1 + wanted )) != NULL) ) 36 | return vsprintf( *sptr, fmt, argv ); 37 | 38 | return wanted; 39 | } 40 | 41 | int asprintf( char **sptr, char *fmt, ... ) 42 | { 43 | int retval; 44 | va_list argv; 45 | va_start( argv, fmt ); 46 | retval = vasprintf( sptr, fmt, argv ); 47 | va_end( argv ); 48 | return retval; 49 | } 50 | #endif 51 | 52 | 53 | /* GString */ 54 | 55 | #define kStringBufferStartingSize 1024 56 | #define kStringBufferGrowthMultiplier 2 57 | 58 | GString* g_string_new(char *startingString) 59 | { 60 | GString* newString = malloc(sizeof(GString)); 61 | 62 | if (startingString == NULL) startingString = ""; 63 | 64 | size_t startingBufferSize = kStringBufferStartingSize; 65 | size_t startingStringSize = strlen(startingString); 66 | while (startingBufferSize < (startingStringSize + 1)) 67 | { 68 | startingBufferSize *= kStringBufferGrowthMultiplier; 69 | } 70 | 71 | newString->str = malloc(startingBufferSize); 72 | newString->currentStringBufferSize = startingBufferSize; 73 | strncpy(newString->str, startingString, startingStringSize); 74 | newString->str[startingStringSize] = '\0'; 75 | newString->currentStringLength = startingStringSize; 76 | 77 | return newString; 78 | } 79 | 80 | char* g_string_free(GString* ripString, bool freeCharacterData) 81 | { 82 | char* returnedString = ripString->str; 83 | if (freeCharacterData) 84 | { 85 | if (ripString->str != NULL) 86 | { 87 | free(ripString->str); 88 | } 89 | returnedString = NULL; 90 | } 91 | 92 | free(ripString); 93 | 94 | return returnedString; 95 | } 96 | 97 | static void ensureStringBufferCanHold(GString* baseString, size_t newStringSize) 98 | { 99 | size_t newBufferSizeNeeded = newStringSize + 1; 100 | if (newBufferSizeNeeded > baseString->currentStringBufferSize) 101 | { 102 | size_t newBufferSize = baseString->currentStringBufferSize; 103 | 104 | while (newBufferSizeNeeded > newBufferSize) 105 | { 106 | newBufferSize *= kStringBufferGrowthMultiplier; 107 | } 108 | 109 | baseString->str = realloc(baseString->str, newBufferSize); 110 | baseString->currentStringBufferSize = newBufferSize; 111 | } 112 | } 113 | 114 | void g_string_append(GString* baseString, char* appendedString) 115 | { 116 | if ((appendedString != NULL) && (strlen(appendedString) > 0)) 117 | { 118 | size_t appendedStringLength = strlen(appendedString); 119 | size_t newStringLength = baseString->currentStringLength + appendedStringLength; 120 | ensureStringBufferCanHold(baseString, newStringLength); 121 | 122 | /* We already know where the current string ends, so pass that as the starting address for strncat */ 123 | strncat(baseString->str + baseString->currentStringLength, appendedString, appendedStringLength); 124 | baseString->currentStringLength = newStringLength; 125 | } 126 | } 127 | 128 | void g_string_append_c(GString* baseString, char appendedCharacter) 129 | { 130 | size_t newSizeNeeded = baseString->currentStringLength + 1; 131 | ensureStringBufferCanHold(baseString, newSizeNeeded); 132 | 133 | baseString->str[baseString->currentStringLength] = appendedCharacter; 134 | baseString->currentStringLength++; 135 | baseString->str[baseString->currentStringLength] = '\0'; 136 | } 137 | 138 | void g_string_append_printf(GString* baseString, char* format, ...) 139 | { 140 | va_list args; 141 | va_start(args, format); 142 | 143 | char* formattedString = NULL; 144 | vasprintf(&formattedString, format, args); 145 | if (formattedString != NULL) 146 | { 147 | g_string_append(baseString, formattedString); 148 | free(formattedString); 149 | } 150 | va_end(args); 151 | } 152 | 153 | void g_string_prepend(GString* baseString, char* prependedString) 154 | { 155 | if ((prependedString != NULL) && (strlen(prependedString) > 0)) 156 | { 157 | size_t prependedStringLength = strlen(prependedString); 158 | size_t newStringLength = baseString->currentStringLength + prependedStringLength; 159 | ensureStringBufferCanHold(baseString, newStringLength); 160 | 161 | memmove(baseString->str + prependedStringLength, baseString->str, baseString->currentStringLength); 162 | strncpy(baseString->str, prependedString, prependedStringLength); 163 | baseString->currentStringLength = newStringLength; 164 | baseString->str[baseString->currentStringLength] = '\0'; 165 | } 166 | } 167 | 168 | /* GSList */ 169 | 170 | void g_slist_free(GSList* ripList) 171 | { 172 | GSList* thisListItem = ripList; 173 | while (thisListItem != NULL) 174 | { 175 | GSList* nextItem = thisListItem->next; 176 | 177 | /* I guess we don't release the data? Non-retained memory management is hard... let's figure it out later. */ 178 | free(thisListItem); 179 | 180 | thisListItem = nextItem; 181 | } 182 | } 183 | 184 | /* Currently only used for markdown_output.c endnotes printing */ 185 | GSList* g_slist_reverse(GSList* theList) 186 | { 187 | GSList* lastNodeSeen = NULL; 188 | 189 | /* Iterate the list items, tacking them on to our new reversed List as we find them */ 190 | GSList* listWalker = theList; 191 | while (listWalker != NULL) 192 | { 193 | GSList* nextNode = listWalker->next; 194 | listWalker->next = lastNodeSeen; 195 | lastNodeSeen = listWalker; 196 | listWalker = nextNode; 197 | } 198 | 199 | return lastNodeSeen; 200 | } 201 | 202 | GSList* g_slist_prepend(GSList* targetElement, void* newElementData) 203 | { 204 | GSList* newElement = malloc(sizeof(GSList)); 205 | newElement->data = newElementData; 206 | newElement->next = targetElement; 207 | return newElement; 208 | } 209 | 210 | -------------------------------------------------------------------------------- /GLibFacade.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GLibFacade.h 3 | * MultiMarkdown 4 | * 5 | * Created by Daniel Jalkut on 7/26/11. 6 | * Copyright 2011 __MyCompanyName__. All rights reserved. 7 | */ 8 | 9 | #ifndef __MARKDOWN_GLIB_FACADE__ 10 | #define __MARKDOWN_GLIB_FACADE__ 11 | 12 | /* peg_markdown uses the link symbol for its own purposes */ 13 | #define link MARKDOWN_LINK_IGNORED 14 | #include 15 | #undef link 16 | 17 | #include 18 | #include 19 | 20 | typedef int gboolean; 21 | typedef char gchar; 22 | 23 | /* This style of bool is used in shared source code */ 24 | #define FALSE false 25 | #define TRUE true 26 | 27 | /* WE implement minimal mirror implementations of GLib's GString and GSList 28 | * sufficient to cover the functionality required by MultiMarkdown. 29 | * 30 | * NOTE: THese are 100% clean, from-scratch implementations using only the 31 | * GLib function prototype as guide for behavior. 32 | */ 33 | 34 | typedef struct 35 | { 36 | /* Current UTF8 byte stream this string represents */ 37 | char* str; 38 | 39 | /* Where in the str buffer will we add new characters */ 40 | /* or append new strings? */ 41 | int currentStringBufferSize; 42 | int currentStringLength; 43 | } GString; 44 | 45 | GString* g_string_new(char *startingString); 46 | char* g_string_free(GString* ripString, bool freeCharacterData); 47 | 48 | void g_string_append_c(GString* baseString, char appendedCharacter); 49 | void g_string_append(GString* baseString, char *appendedString); 50 | 51 | void g_string_prepend(GString* baseString, char* prependedString); 52 | 53 | void g_string_append_printf(GString* baseString, char* format, ...); 54 | 55 | /* Just implement a very simple singly linked list. */ 56 | 57 | typedef struct _GSList 58 | { 59 | void* data; 60 | struct _GSList* next; 61 | } GSList; 62 | 63 | void g_slist_free(GSList* ripList); 64 | GSList* g_slist_prepend(GSList* targetElement, void* newElementData); 65 | GSList* g_slist_reverse(GSList* theList); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Title: License Agreement 2 | 3 | peg-multimarkdown 4 | portions Copyright (c) 2010-2013 Fletcher T. Penney 5 | 6 | based on: 7 | markdown in c, implemented using PEG grammar 8 | Copyright (c) 2008-2011 John MacFarlane 9 | ODF output code (c) 2011-2013 Fletcher T. Penney 10 | 11 | peg-markdown is released under both the GPL and MIT licenses. 12 | You may pick the license that best fits your needs. 13 | 14 | Additional MultiMarkdown files 15 | Copyright (c) 2005-2013 Fletcher T. Penney 16 | Copyright (c) 2011 Daniel Jalkut, licensed explicitly MIT. 17 | 18 | Modifications to remove reliance on Glib2 19 | Copyright (c) 2011 Daniel Jalkut, licensed explicitly MIT. 20 | 21 | 22 | The GPL 23 | 24 | This program is free software; you can redistribute it and/or modify 25 | it under the terms of the GNU General Public License as published by 26 | the Free Software Foundation; either version 2 of the License, or 27 | (at your option) any later version. 28 | 29 | This program is distributed in the hope that it will be useful, 30 | but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32 | GNU General Public License for more details. 33 | 34 | You should have received a copy of the GNU General Public License 35 | along with this program; if not, write to the Free Software 36 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 37 | 38 | The MIT License 39 | 40 | Permission is hereby granted, free of charge, to any person obtaining a copy 41 | of this software and associated documentation files (the "Software"), to deal 42 | in the Software without restriction, including without limitation the rights 43 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 44 | copies of the Software, and to permit persons to whom the Software is 45 | furnished to do so, subject to the following conditions: 46 | 47 | The above copyright notice and this permission notice shall be included in 48 | all copies or substantial portions of the Software. 49 | 50 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 51 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 52 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 53 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 54 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 55 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 56 | THE SOFTWARE. 57 | 58 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 59 | 60 | peg-0.1.4 (included for convenience - http://piumarta.com/software/peg/) 61 | 62 | Copyright (c) 2007 by Ian Piumarta 63 | All rights reserved. 64 | 65 | Permission is hereby granted, free of charge, to any person obtaining a 66 | copy of this software and associated documentation files (the 'Software'), 67 | to deal in the Software without restriction, including without limitation 68 | the rights to use, copy, modify, merge, publish, distribute, and/or sell 69 | copies of the Software, and to permit persons to whom the Software is 70 | furnished to do so, provided that the above copyright notice(s) and this 71 | permission notice appear in all copies of the Software. Acknowledgement 72 | of the use of this Software in supporting documentation would be 73 | appreciated but is not required. 74 | 75 | THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. 76 | -------------------------------------------------------------------------------- /MMD-Compat.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MMD-Compat.xcodeproj/xcuserdata/fletcher.xcuserdatad/xcschemes/MakefileBuild.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 14 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 40 | 41 | 42 | 43 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /MMD-Compat.xcodeproj/xcuserdata/fletcher.xcuserdatad/xcschemes/MultiMarkdown.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 14 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 40 | 41 | 47 | 48 | 49 | 50 | 51 | 52 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /MMD-Compat.xcodeproj/xcuserdata/fletcher.xcuserdatad/xcschemes/Peg.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 14 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 40 | 41 | 42 | 43 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /MMD-Compat.xcodeproj/xcuserdata/fletcher.xcuserdatad/xcschemes/Run Tests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 14 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 40 | 41 | 42 | 43 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /MMD-Compat.xcodeproj/xcuserdata/fletcher.xcuserdatad/xcschemes/libMultiMarkdown.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 14 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 40 | 41 | 42 | 43 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /MMD-Compat.xcodeproj/xcuserdata/fletcher.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MakefileBuild.xcscheme 8 | 9 | orderHint 10 | 4 11 | 12 | MultiMarkdown.xcscheme 13 | 14 | orderHint 15 | 0 16 | 17 | Peg.xcscheme 18 | 19 | orderHint 20 | 2 21 | 22 | Run Tests.xcscheme 23 | 24 | orderHint 25 | 1 26 | 27 | libMultiMarkdown.xcscheme 28 | 29 | orderHint 30 | 3 31 | 32 | 33 | SuppressBuildableAutocreation 34 | 35 | 4AFA466113E3624F00CFA132 36 | 37 | primary 38 | 39 | 40 | 65BDF4D813E6D0A100E8C5B3 41 | 42 | primary 43 | 44 | 45 | 65F0B88813DF6C0D00D0980C 46 | 47 | primary 48 | 49 | 50 | 65F0B8EA13DF714E00D0980C 51 | 52 | primary 53 | 54 | 55 | 8DD76FA90486AB0100D96B5E 56 | 57 | primary 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION=3.7 2 | PROGRAM=multimarkdown 3 | 4 | UNAME=$(shell uname) 5 | 6 | ifeq ($(UNAME), Darwin) 7 | define FINALNOTES 8 | ***\n\ 9 | *** WARNING: Since you are on Darwin, you probably meant to use the Xcode\n\ 10 | *** version instead.\n\ 11 | *** It produces a version of the binary that is capable of running on\n\ 12 | *** multiple versions of Mac OS X and on PPC, i386, or x86_64 machines.\n\ 13 | *** 14 | endef 15 | else 16 | FINALNOTES=Build complete. 17 | endif 18 | 19 | CFLAGS ?= -Wall -O3 -include GLibFacade.h -I ./ -D MD_USE_GET_OPT=1 -D_GNU_SOURCE 20 | ifeq ($(UNAME), SunOS) 21 | CC = gcc 22 | # Use of is valid only in a c99 compilation environment 23 | CFLAGS += --std=c99 24 | else 25 | CFLAGS += -ansi 26 | endif 27 | 28 | # make ARCH=ppc 29 | # build for ppc architecture - Only works on machines with PPC compilation support installed 30 | # probably only Snow Leopard machines with Xcode 3 installed 31 | ifeq ($(ARCH), ppc) 32 | CFLAGS += -arch ppc 33 | endif 34 | 35 | # make ARCH=i386 36 | # build for i386 architecture - useful with older machines or those running 10.4? 37 | ifeq ($(ARCH), i386) 38 | CFLAGS += -arch i386 39 | endif 40 | 41 | CFLAGS ?= -Wall -O3 -ansi -D_GNU_SOURCE # -flto for newer GCC versions 42 | OBJS=markdown_parser.o markdown_output.o markdown_lib.o GLibFacade.o utility_functions.o parsing_functions.o odf.o 43 | PEGDIR=peg-0.1.9 44 | LEG=$(PEGDIR)/leg$(X) 45 | PKG_CONFIG = pkg-config 46 | 47 | ALL : $(PROGRAM) 48 | 49 | $(LEG): $(PEGDIR) 50 | CC=gcc $(MAKE) -C $(PEGDIR) 51 | 52 | %.o : %.c markdown_peg.h 53 | $(CC) -c $(CFLAGS) -o $@ $< 54 | 55 | $(PROGRAM) : markdown.c $(OBJS) 56 | $(CC) $(CFLAGS) -o $@ $(OBJS) $< 57 | @echo "$(FINALNOTES)" 58 | 59 | markdown_parser.c : markdown_parser.leg $(LEG) markdown_peg.h parsing_functions.c utility_functions.c 60 | $(LEG) -o $@ $< 61 | 62 | .PHONY: clean test 63 | 64 | clean: 65 | rm -f markdown_parser.c $(PROGRAM) $(OBJS); \ 66 | rm -rf mac_installer/Package_Root/usr/local/bin; \ 67 | rm -rf mac_installer/Support_Root; \ 68 | rm mac_installer/Resources/*.html; \ 69 | rm windows_installer/README.txt; \ 70 | rm windows_installer/multimarkdown.exe; \ 71 | rm windows_installer/multimarkdown.xml.backup; \ 72 | rm windows_installer/LICENSE.html; \ 73 | rm -rf mac_installer/*.pkg 74 | 75 | distclean: clean 76 | $(MAKE) -C $(PEGDIR) clean 77 | 78 | test: $(PROGRAM) 79 | cd MarkdownTest; \ 80 | ./MarkdownTest.pl --Script=../$(PROGRAM) --Tidy --Flags="--compatibility" 81 | 82 | mmd-test: $(PROGRAM) 83 | cd MarkdownTest; \ 84 | ./MarkdownTest.pl --Script=../$(PROGRAM) --testdir=MultiMarkdownTests 85 | 86 | compat-test: $(PROGRAM) 87 | cd MarkdownTest; \ 88 | ./MarkdownTest.pl --Script=../$(PROGRAM) --testdir=CompatibilityTests --Flags="--compatibility" 89 | 90 | latex-test: $(PROGRAM) 91 | cd MarkdownTest; \ 92 | ./MarkdownTest.pl --Script=../$(PROGRAM) --testdir=MultiMarkdownTests --Flags="-t latex" --ext=".tex"; \ 93 | ./MarkdownTest.pl --Script=../$(PROGRAM) --testdir=BeamerTests --Flags="-t latex" --ext=".tex"; \ 94 | ./MarkdownTest.pl --Script=../$(PROGRAM) --testdir=MemoirTests --Flags="-t latex" --ext=".tex" 95 | 96 | xslt-test: $(PROGRAM) 97 | cd MarkdownTest; \ 98 | ./MarkdownTest.pl --Script=/bin/cat --testdir=MultiMarkdownTests \ 99 | --TrailFlags="| ../Support/bin/mmd2tex-xslt" --ext=".tex"; \ 100 | ./MarkdownTest.pl --Script=/bin/cat --testdir=BeamerTests \ 101 | --TrailFlags="| ../Support/bin/mmd2tex-xslt" --ext=".tex"; \ 102 | ./MarkdownTest.pl --Script=/bin/cat --testdir=MemoirTests \ 103 | --TrailFlags="| ../Support/bin/mmd2tex-xslt" --ext=".tex"; \ 104 | 105 | leak-check: $(PROGRAM) 106 | valgrind --leak-check=full ./multimarkdown TEST.markdown > TEST.html 107 | 108 | 109 | # Compile multimarkdown.exe and prep files necessary for installer 110 | 111 | windows: $(PROGRAM) 112 | rm *.o 113 | /usr/bin/i586-mingw32msvc-cc -c -Wall -O3 -ansi markdown*.c GLibFacade.c 114 | /usr/bin/i586-mingw32msvc-cc markdown*.o GLibFacade.o \ 115 | -Wl,--dy,--warn-unresolved-symbols,-lglib-2.0 -o multimarkdown.exe 116 | 117 | # Get readme and other files ready 118 | # This has to be run before BitRock can create the installer 119 | win-prep: 120 | mkdir -p windows_installer 121 | cp multimarkdown.exe windows_installer/ 122 | cp README.markdown windows_installer/README.txt 123 | ./multimarkdown LICENSE > windows_installer/LICENSE.html 124 | 125 | # After building the installer with BitRock, this creates a properly named 126 | # zipfile 127 | # You have to move the .exe from BitRock to the windows_installer folder 128 | # Also - create a portable mmd zipfile 129 | win-installer: 130 | zip -r windows_installer/MultiMarkdown-Windows-$(VERSION).zip windows_installer/MMD-windows-$(VERSION).exe -x windows_installer/MultiMarkdown*.zip 131 | cd windows_installer; zip -r MultiMarkdown-Windows-Portable-$(VERSION).zip *.bat multimarkdown.exe README.txt LICENSE.html -x install_multimarkdown.bat 132 | 133 | # Build Mac installer - requires that you first build multimarkdown itself, 134 | # either with "make" or with Xcode 135 | 136 | mac-installer: 137 | mkdir -p mac_installer/Package_Root/usr/local/bin 138 | mkdir -p mac_installer/Support_Root/Library/Application\ Support 139 | cp multimarkdown scripts/mmd* mac_installer/Package_Root/usr/local/bin/ 140 | ./multimarkdown README > mac_installer/Resources/README.html 141 | ./multimarkdown mac_installer/Resources/Welcome.txt > mac_installer/Resources/Welcome.html 142 | ./multimarkdown LICENSE > mac_installer/Resources/License.html 143 | ./multimarkdown mac_installer/Resources/Support_Welcome.txt > mac_installer/Resources/Support_Welcome.html 144 | git clone Support mac_installer/Support_Root/Library/Application\ Support/MultiMarkdown 145 | cd mac_installer; /Applications/PackageMaker.app/Contents/MacOS/PackageMaker \ 146 | --doc "Make Support Installer.pmdoc" \ 147 | --title "MultiMarkdown Support Files" \ 148 | --version $(VERSION) \ 149 | --filter "\.DS_Store" \ 150 | --filter "\.git" \ 151 | --id net.fletcherpenney.MMD-Support.pkg \ 152 | --domain user \ 153 | --out "MultiMarkdown-Support-Mac-$(VERSION).pkg" \ 154 | --no-relocate; \ 155 | /Applications/PackageMaker.app/Contents/MacOS/PackageMaker \ 156 | --doc "Make OS X Installer.pmdoc" \ 157 | --title "MultiMarkdown" \ 158 | --version $(VERSION) \ 159 | --filter "\.DS_Store" \ 160 | --filter "\.git" \ 161 | --id net.fletcherpenney.multimarkdown.pkg \ 162 | --out "MultiMarkdown-Mac-$(VERSION).pkg" 163 | cd mac_installer; zip -r MultiMarkdown-Mac-$(VERSION).zip MultiMarkdown-Mac-$(VERSION).pkg 164 | cd mac_installer; zip -r MultiMarkdown-Support-Mac-$(VERSION).zip MultiMarkdown-Support-Mac-$(VERSION).pkg 165 | 166 | # Requires installation of the platypus command line tool to create 167 | # a drag and drop application for Mac OS X 168 | 169 | drop: 170 | mkdir drag; rm -rf drag/*.app; \ 171 | /usr/local/bin/platypus -D -a 'MMD to LaTeX' -o 'Text Window' -p '/bin/sh' -V '3.0' -I 'net.fletcherpenney.MMD2LaTeX' -X '*' -T '****|fold' -N 'PATH=/usr/local/bin' -c 'scripts/mmd2tex' 'drag/MMD2LaTeX.app'; \ 172 | /usr/local/bin/platypus -D -a 'MMD to HTML' -o 'Text Window' -p '/bin/sh' -V '3.0' -I 'net.fletcherpenney.MMD2HTML' -X '*' -T '****|fold' -N 'PATH=/usr/local/bin' -c 'scripts/mmd' 'drag/MMD2HTML.app'; \ 173 | /usr/local/bin/platypus -D -a 'MMD to OPML' -o 'Text Window' -p '/bin/sh' -V '3.0' -I 'net.fletcherpenney.MMD2OPML' -X '*' -T '****|fold' -N 'PATH=/usr/local/bin' -c 'scripts/mmd2opml' 'drag/MMD2OPML.app'; \ 174 | /usr/local/bin/platypus -D -a 'MMD to ODF' -o 'Text Window' -p '/bin/sh' -V '3.0' -I 'net.fletcherpenney.MMD2ODF' -X '*' -T '****|fold' -N 'PATH=/usr/local/bin' -c 'scripts/mmd2odf' 'drag/MMD2ODF.app'; 175 | 176 | # Create HTML and PDF (if latex installed) documentation 177 | docs: $(PROGRAM) 178 | cd documentation; \ 179 | ../Support/Utilities/mmd_merge.pl index.txt > manual.txt; \ 180 | mkdir -p ../manual; \ 181 | ../multimarkdown manual.txt > ../manual/index.html; \ 182 | ../multimarkdown -b -t latex manual.txt; \ 183 | latexmk -pdf manual.tex; \ 184 | latexmk -c manual.tex; \ 185 | mv manual.pdf ../manual/mmd-manual.pdf; \ 186 | rm ../documentation/manual.t*; 187 | 188 | 189 | # For me to push updated documentation to my github site 190 | docs-live: docs 191 | cd manual; git add mmd-manual.pdf index.html; \ 192 | git commit -m "update manual"; git push origin gh-pages; \ 193 | -------------------------------------------------------------------------------- /MarkdownMacPrefix.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #import "GLibFacade.h" 5 | #import "markdown_lib.h" 6 | 7 | #define link PEG_link 8 | #define STR PEG_STR 9 | #import "markdown_peg.h" 10 | 11 | // peg 12 | #define Class PEG_Class 13 | #import "tree.h" 14 | #undef Class 15 | 16 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | README.markdown -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | Title: peg-multimarkdown User's Guide 2 | Author: Fletcher T. Penney 3 | Base Header Level: 2 4 | 5 | Note: This project has been deprecated in favor of [MultiMarkdown-6](https://github.com/fletcher/MultiMarkdown-6). 6 | 7 | # Introduction # 8 | 9 | [Markdown] is a simple markup language used to convert plain text into HTML. 10 | 11 | [MultiMarkdown] is a derivative of Markdown that adds new syntax features, such as footnotes, tables, and metadata. Additionally, it offers mechanisms to convert plain text into LaTeX in addition to HTML. 12 | 13 | [peg-multimarkdown] is an implementation of MultiMarkdown derived from John MacFarlane's [peg-markdown]. It makes use of a parsing expression grammar (PEG), and is written in C. It should compile for most any (major) operating system. 14 | 15 | Thanks to work by Daniel Jalkut, MMD no longer requires GLib2 as a dependency. This should make it easier to compile on various operating systems. 16 | 17 | 18 | # Installation # 19 | 20 | 21 | ## Mac OS X ## 22 | 23 | On the Mac, you can choose from using an installer to install the program for you, or you can compile it yourself from scratch. If you know what that means, follow the instructions below in the Linux section. Otherwise, definitely go for the installer! 24 | 25 | You can also install MultiMarkdown with the package manager [MacPorts] with the following command: 26 | 27 | sudo port install multimarkdown 28 | 29 | Or using [homebrew]: 30 | 31 | brew install multimarkdown 32 | 33 | **NOTE**: I don't maintain either of these ports/packages and can't vouch that they are up to date or working properly. That said, I have started using [homebrew] to install the latest development build on my machine, while using `make` in my working directory while editing: 34 | 35 | brew install multimarkdown --HEAD 36 | 37 | If you don't know what any of that means, just [grab the installer][downloads]. 38 | 39 | If you want to compile for yourself, be sure you have the Developer Tools installed, and then follow the directions for [Linux]. 40 | 41 | If you want to make your own installer, you can use the `make mac-installer` command after compiling the `multimarkdown` binary itself. 42 | 43 | 44 | ## Windows ## 45 | 46 | The easiest way to get peg-multimarkdown running on Windows is to download the installer from the [downloads page][downloads]. It is created with the help of BitRock's software. 47 | 48 | If you want to compile this yourself, you do it in the same way that you would install peg-markdown for Windows. The instructions are on the peg-multimarkdown [wiki] (https://github.com/fletcher/peg-multimarkdown/wiki/Building-for-Windows). I was able to compile for Windows fairly easily using Ubuntu linux following those instructions. I have not tried to actually compile on a Windows machine. 49 | 50 | As a shortcut, if running on a linux machine you can use: 51 | 52 | make windows 53 | 54 | This creates the `multimarkdown.exe` binary. You can then install this manually. 55 | 56 | The `make win-installer` command is what I use to package up the BitRock installer into a zipfile. You probably won't need it. 57 | 58 | 59 | ## Linux ## 60 | 61 | You can either download the source from [peg-multimarkdown], or (preferentially) you can use git: 62 | 63 | git clone git://github.com/fletcher/peg-multimarkdown.git 64 | 65 | You can run the `update_submodules.sh` script to update the submodules if you want to run the test commands, download the sample files and the Support directory, or compile the documentation. 66 | 67 | Then, simply run `make` to compile the source. 68 | 69 | You can also run some test commands to verify that everything is working properly. Of note, it is normal to fail one test in the Markdown tests, but the others should pass. You can then install the binary wherever you like. 70 | 71 | make 72 | make test 73 | make mmd-test 74 | make latex-test 75 | make compat-test 76 | 77 | **NOTE** As of version 3.2, the tests including obfuscated email addresses will also fail due to a change in how random numbers are generated. 78 | 79 | ## FreeBSD ## 80 | 81 | If you want to compile manually, you should be able to follow the directions for Linux above. However, apparently MultiMarkdown has been put in the ports tree, so you can also use: 82 | 83 | cd /usr/ports/textproc/multimarkdown 84 | make install 85 | 86 | (I have not tested this myself, and cannot guarantee that it works properly. Come to think of it, I don't even know which version of MMD they use.) 87 | 88 | 89 | # Usage # 90 | 91 | Once installed, you simply do something like the following: 92 | 93 | * `multimarkdown file.txt` --- process text into HTML. 94 | 95 | * `multimarkdown -c file.txt` --- use a compatibility mode that emulates the original Markdown. 96 | 97 | * `multimarkdown -t latex file.txt` --- output the results as LaTeX instead of HTML. This can then be processed into a PDF if you have LaTeX installed. You can further specify the `LaTeX Mode` metadata to customize output for compatibility with `memoir` or `beamer` classes. 98 | 99 | * `multimarkdown -t odf file.txt` --- output the results as an OpenDocument Text Flat XML file. Does require the plugin be installed in your copy of OpenOffice, which is available at the [downloads] page. LibreOffice includes this plugin by default. 100 | 101 | * `multimarkdown -t opml file.txt` --- convert the MMD text file to an MMD OPML file, compatible with OmniOutliner and certain other outlining and mind-mapping programs (including iThoughts and iThoughtsHD). 102 | 103 | * `multimarkdown -h` --- display help and additional options. 104 | 105 | * `multimarkdown -b *.txt` --- `-b` or `--batch` mode can process multiple files at once, converting `file.txt` to `file.html` or `file.tex` as directed. Using this feature, you can convert a directory of MultiMarkdown text files into HTML files, or LaTeX files with a single command without having to specify the output files manually. **CAUTION**: This will overwrite existing files with the `html` or `tex` extension, so use with caution. 106 | 107 | **Note**: Several convenience scripts are available to simplify things: 108 | 109 | mmd => multimarkdown -b 110 | mmd2tex => multimarkdown -b -t latex 111 | mmd2odf => multimarkdown -b -t odf 112 | mmd2opml => multimarkdown -b -t opml 113 | 114 | mmd2pdf => Unsupported script to try and run latex/xelatex. 115 | You can direct questions to the discussion list, but 116 | I may or may not respond. It works for me, so I share 117 | it with those who are interested but make no 118 | guarantees. 119 | 120 | 121 | # Why create another version of MultiMarkdown? # 122 | 123 | * Maintaining a growing collection of nested regular expressions was going to become increasingly difficult. I don't plan on adding much (if any) in the way of new syntax features, but it was a mess. 124 | 125 | * Performance on longer documents was poor. The nested perl regular expressions was slow, even on a relatively fast computer. Performance on something like an iPhone would probably have been miserable. 126 | 127 | * The reliance on Perl made installation fairly complex on Windows. That didn't bother me too much, but it is a factor. 128 | 129 | * Perl can't be run on an iPhone/iPad, and I would like to be able to have MultiMarkdown on an iOS device, and not just regular Markdown (which exists in C versions). 130 | 131 | * I was interested in learning about PEG's and revisiting C programming. 132 | 133 | * The syntax has been fairly stable, and it would be nice to be able to formalize it a bit --- which happens by definition when using a PEG. 134 | 135 | * I wanted to revisit the syntax and features and clean things up a bit. 136 | 137 | * Did I mention how much faster this is? And that it could (eventually) run on an iPhone? 138 | 139 | 140 | # What's different? # 141 | 142 | 143 | ## "Complete" documents vs. "snippets" ## 144 | 145 | A "snippet" is a section of HTML (or LaTeX) that is not a complete, fully-formed document. It doesn't contain the header information to make it a valid XML document. It can't be compiled with LaTeX into a PDF without further commands. 146 | 147 | For example: 148 | 149 | # This is a header # 150 | 151 | And a paragraph. 152 | 153 | becomes the following HTML snippet: 154 | 155 |

This is a header

156 | 157 |

And a paragraph.

158 | 159 | and the following LaTeX snippet: 160 | 161 | \part{This is a header} 162 | \label{thisisaheader} 163 | 164 | 165 | And a paragraph. 166 | 167 | It was not possible to create a LaTeX snippet with the original MultiMarkdown, because it relied on having a complete XHTML document that was then converted to LaTeX via an XSLT document (requiring a whole separate program). This was powerful, but complicated. 168 | 169 | Now, I have come full-circle. peg-multimarkdown will now output LaTeX directly, without requiring XSLT. This allows the creation of LaTeX snippets, or complete documents, as necessary. 170 | 171 | To create a complete document, simply include metadata. You can include a title, author, date, or whatever you like. If you don't want to include any real metadata, including "format: complete" will still trigger a complete document, just like it used to. 172 | 173 | **NOTE**: If the *only* metadata present is `Base Header Level` then a complete document will not be triggered. This can be useful when combining various documents together. 174 | 175 | The old approach (even though it was hidden from most users) was a bit of a kludge, and this should be more elegant, and more flexible. 176 | 177 | 178 | ## Creating LaTeX Documents ## 179 | 180 | LaTeX documents are created a bit differently than under the old system. You no longer have to use an XSLT file to convert from XHTML to LaTeX. You can go straight from MultiMarkdown to LaTeX, which is faster and more flexible. 181 | 182 | To create a complete LaTeX document, you can process your file as a snippet, and then place it in a LaTeX template that you already have. Alternatively, you can use metadata to trigger the creation of a complete document. You can use the `LaTeX Input` metadata to insert a `\input{file}` command. You can then store various template files in your texmf directory and call them with metadata, or with embedded raw LaTeX commands in your document. For example: 183 | 184 | LaTeX Input: mmd-memoir-header 185 | Title: Sample MultiMarkdown Document 186 | Author: Fletcher T. Penney 187 | LaTeX Mode: memoir 188 | LaTeX Input: mmd-memoir-begin-doc 189 | LaTeX Footer: mmd-memoir-footer 190 | 191 | This would include several template files in the order that you see. The `LaTeX Footer` metadata inserts a template at the end of your document. Note that the order and placement of the `LaTeX Include` statements is important. 192 | 193 | The `LaTeX Mode` metadata allows you to specify that MultiMarkdown should use the `memoir` or `beamer` output format. This places subtle differences in the output document for compatibility with those respective classes. 194 | 195 | This system isn't quite as powerful as the XSLT approach, since it doesn't alter the actual MultiMarkdown to LaTeX conversion process. But it is probably much more familiar to LaTeX users who are accustomed to using `\input{}` commands and doesn't require knowledge of XSLT programming. 196 | 197 | I recommend checking out the default [LaTeX Support Files] that are available on github. They are designed to serve as a starting point for your own needs. 198 | 199 | **Note**: You can still use this version of MultiMarkdown to convert text into XHTML, and then process the XHTML using XSLT to create a LaTeX document, just like you used to in MMD 2.0. 200 | 201 | [LaTeX Support Files]: https://github.com/fletcher/peg-multimarkdown-latex-support 202 | 203 | 204 | ## Footnotes ## 205 | 206 | Footnotes work slightly differently than before. This is partially on purpose, and partly out of necessity. Specifically: 207 | 208 | * Footnotes are anchored based on number, rather than the label used in the MMD source. This won't show a visible difference to the reader, but the XHTML source will be different. 209 | 210 | * Footnotes can be used more than once. Each reference will link to the same numbered note, but the "return" link will only link to the first instance. 211 | 212 | * Footnote "return" links are a separate paragraph after the footnote. This is due to the way peg-markdown works, and it's not worth the effort to me to change it. You can always use CSS to change the appearance however you like. 213 | 214 | * Footnote numbers are surrounded by "[]" in the text. 215 | 216 | 217 | ## Raw HTML ## 218 | 219 | Because the original MultiMarkdown processed the text document into XHTML first, and then processed the entire XHTML document into LaTeX, it couldn't tell the difference between raw HTML and HTML that was created from plaintext. This version, however, uses the original plain text to create the LaTeX document. This means that any raw HTML inside your MultiMarkdown document is **not** converted into LaTeX. 220 | 221 | The benefit of this is that you can embed one piece of the document in two formats --- one for XHTML, and one for LaTeX: 222 | 223 |
224 |

Release early, release often!

225 |

Linus Torvalds

226 |
227 | 228 | 229 | 230 | In this section, when the document is converted into XHTML, the `blockquote` sections will be used as expected, and the `epigraph` will be ignored since it is inside a comment. Conversely, when processed into LaTeX, the raw HTML will be ignored, and the comment will be processed as raw LaTeX. 231 | 232 | You shouldn't need to use this feature, but if you want to specify exactly how a certain part of your document is processed into LaTeX, it's a neat trick. 233 | 234 | 235 | ## Processing MultiMarkdown inside HTML ## 236 | 237 | In the original MultiMarkdown, you could use something like `
` to tell MultiMarkdown to process the text inside the div. In peg-multimarkdown, you can do this, or you can use the command-line option `--process-html` to process the text inside all raw HTML. 238 | 239 | 240 | ## Math Support ## 241 | 242 | MultiMarkdown 2.0 supported [ASCIIMathML] embedded with MultiMarkdown documents. This syntax was then converted to MathML for XHTML output, and then further processed into LaTeX when creating LaTeX output. The benefit of this was that the ASCIIMathML syntax was pretty straightforward. The downside was that only a handful of browsers actually support MathML, so most of the time it was only useful for LaTeX. Many MMD users who are interested in LaTeX output already knew LaTeX, so they sometimes preferred native math syntax, which led to several hacks. 243 | 244 | MultiMarkdown 3.0 does not have built in support for ASCIIMathML. In fact, I would probably have to write a parser from scratch to do anything useful with it, which I have little desire to do. So I came up with a compromise. 245 | 246 | ASCIIMathML is no longer supported by MultiMarkdown. Instead, you *can* use LaTeX to code for math within your document. When creating a LaTeX document, the source is simply passed through, and LaTeX handles it as usual. *If* you desire, you can add a line to your header when creating XHTML documents that will allow [MathJax] to appropriately display your math. 247 | 248 | Normally, MathJax *and* LaTeX supported using `\[ math \]` or `\( math \)` to indicate that math was included. MMD stumbled on this due to some issues with escaping, so instead we use `\\[ math \\]` and `\\( math \\)`. See an example: 249 | 250 | latex input: mmd-article-header 251 | Title: MultiMarkdown Math Example 252 | latex input: mmd-article-begin-doc 253 | latex footer: mmd-memoir-footer 254 | xhtml header: 257 | 258 | 259 | An example of math within a paragraph --- \\({e}^{i\pi }+1=0\\) 260 | --- easy enough. 261 | 262 | And an equation on it's own: 263 | 264 | \\[ {x}_{1,2}=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a} \\] 265 | 266 | That's it. 267 | 268 | You would, of course, need to change the `xhtml header` metadata to point to your own installation of MathJax. 269 | 270 | **Note**: MultiMarkdown doesn't actually *do* anything with the code inside the brackets. It simply strips away the extra backslash and passes the LaTeX source unchanged, where it is handled by MathJax *if* it's properly installed, or by LaTeX. If you're having trouble, you can certainly email the [MultiMarkdown Discussion List], but I do not provide support for LaTeX code. 271 | 272 | [ASCIIMathML]: http://www.chapman.edu/~jipsen/mathml/Asciimath.html 273 | [MathJax]: http://www.mathjax.org/ 274 | [MultiMarkdown Discussion List]: http://groups.google.com/group/multimarkdown/ 275 | 276 | 277 | # Acknowledgments # 278 | 279 | Thanks to John MacFarlane for [peg-markdown]. Obviously, this derivative work would not be possible without his work. Additionally, he was very gracious in giving me some pointers when I was getting started with trying to modify his software, and he continues to update peg-markdown with the various edge cases MultiMarkdown users have found. Hopefully both programs are better as a result. 280 | 281 | Thanks to Daniel Jalkut for his work on enabling MultiMarkdown to run without relying on GLib2. This makes it much more flexible! 282 | 283 | Thanks to John Gruber for the original [Markdown]. 'Nuff said. 284 | 285 | And thanks to the many contributors and users of the original MultiMarkdown that helped me refine the syntax and search out bugs. 286 | 287 | 288 | [peg-markdown]: https://github.com/jgm/peg-markdown 289 | [Markdown]: http://daringfireball.net/projects/markdown/ 290 | [MultiMarkdown]: http://fletcherpenney.net/multimarkdown/ 291 | [peg-multimarkdown]: https://github.com/fletcher/peg-multimarkdown 292 | [fink]: http://www.finkproject.org/ 293 | [downloads]: http://github.com/fletcher/peg-multimarkdown/downloads 294 | [GTK+]: http://www.gtk.org/ 295 | [homebrew]: https://github.com/mxcl/homebrew 296 | [MacPorts]: http://www.macports.org/ 297 | -------------------------------------------------------------------------------- /TODO.txt: -------------------------------------------------------------------------------- 1 | Notes for myself while pulling together the remaining lose ends in MultiMarkdown standalone for Mac. 2 | 3 | CURRENT: 4 | 5 | ? 6 | 7 | HISTORY: 8 | 9 | - Fix short options parsing in markdown.c 10 | 11 | - Performance tests - compare with a very large markdown file vs. e.g. multimarkdown based on GLib. 12 | - Performance now seems approximately on par with the GLib version for massive files 13 | - Garbage output e.g. when processing unicode within tags:

14 | - This went away with removal of NSString from the GString printf-append function. 15 | 16 | -------------------------------------------------------------------------------- /glib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * glib.h 3 | * MultiMarkdown 4 | * 5 | * Created by Daniel Jalkut on 7/26/11. 6 | * Copyright 2011 __MyCompanyName__. All rights reserved. 7 | * 8 | */ 9 | 10 | /* Just a dummy file to keep the glib-dependent sources compiling as we would hope */ 11 | #include "GLibFacade.h" 12 | -------------------------------------------------------------------------------- /mac_installer/Make OS X Installer.pmdoc/01package-contents.xml: -------------------------------------------------------------------------------- 1 | ownermodegroupownermodegroupownermodegroupownermodegroupownermodegroupownermodegroupgroupownergroupownergroupownergroupownergroupownergroupownergroupownergroupownergroupowner -------------------------------------------------------------------------------- /mac_installer/Make OS X Installer.pmdoc/01package.xml: -------------------------------------------------------------------------------- 1 | net.fletcherpenney.multimarkdown.pkg3.0b8Package_Root/installFrom.isRelativeTypeidentifierparentinstallToversion01package-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ -------------------------------------------------------------------------------- /mac_installer/Make OS X Installer.pmdoc/index.xml: -------------------------------------------------------------------------------- 1 | MultiMarkdown/Users/fletcher/MultiMarkdown-Mac-3.0b3.pkgnet.fletcherpenney.multimarkdownInstalls the multimarkdown binary, as well as the glib2 library (libglib2.0.0) and libintl filesResources/License.htmlResources/README.htmlResources/Welcome.html01package.xmlproperties.titledescriptionproperties.anywhereDomainproperties.systemDomain -------------------------------------------------------------------------------- /mac_installer/Make Support Installer.pmdoc/01library.xml: -------------------------------------------------------------------------------- 1 | net.fletcherpenney.mmdsupport3.0b3Support_Root/Library/installTorequireAuthorizationparentversionidentifierinstallFrom.isRelativeTypeincludeRoot01library-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ -------------------------------------------------------------------------------- /mac_installer/Make Support Installer.pmdoc/index.xml: -------------------------------------------------------------------------------- 1 | MultiMarkdown-Mac-Support-3.0b2/Users/fletcher/MultiMarkdown-Mac-Support-3.0b3.mpkgnet.fletcherpenneyResources/License.htmlResources/Support_Welcome.html01library.xmlproperties.titleproperties.customizeOptionproperties.userDomainproperties.anywhereDomainproperties.systemDomain -------------------------------------------------------------------------------- /mac_installer/README.markdown: -------------------------------------------------------------------------------- 1 | 2 | To create an installer for Mac OS X: 3 | 4 | * `make` peg-multimarkdown 5 | 6 | * `make test`, `make mmdtest`, `make latextest` to be sure everything worked 7 | properly 8 | 9 | * `make installer` to copy the binary into the proper folder 10 | 11 | * open the `Make OS X Installer` file and select "Build" 12 | 13 | You can now run the installer or distribute it to others. You can also modify 14 | the other resource files to add to the Readme, etc. -------------------------------------------------------------------------------- /mac_installer/Resources/Support_Welcome.txt: -------------------------------------------------------------------------------- 1 | Title: Installer Welcome Message 2 | 3 | This custom installer will install the **MultiMarkdown** directory into 4 | `~/Library/Application Support/MultiMarkdown`. This directory contains a few 5 | utility scripts and XSLT files that enable use of MultiMarkdown with 6 | [Scrivener] and adds some additional features when using the [TextMate][] 7 | [bundle]. 8 | 9 | **NOTE**: This package will overwrite certain files if you have previously 10 | installed MultiMarkdown 2.0 in your `Application Support` folder. It will 11 | leave most of the files untouched, but will overwrite some of the core XSLT 12 | files and the core convenience scripts in `/bin`. You may wish to back that 13 | folder up just in case (or better yet, move it to another location and start 14 | fresh) 15 | 16 | This package does **not** include the actual MultiMarkdown binary --- that 17 | requires a separate installer. 18 | 19 | For more information, please check out the MultiMarkdown [web 20 | site](http://fletcherpenney.net/multimarkdown/). 21 | 22 | You will be guided through the steps necessary to install this software. 23 | 24 | [Scrivener]: http://www.literatureandlatte.com/ 25 | 26 | [TextMate]: http://macromates.com/ 27 | 28 | [bundle]: https://github.com/fletcher/markdown.tmbundle -------------------------------------------------------------------------------- /mac_installer/Resources/Welcome.txt: -------------------------------------------------------------------------------- 1 | Title: Installer Welcome Message 2 | 3 | This custom installer will install **MultiMarkdown** and several convenience scripts to serve as shortcuts for using MultiMarkdown from the command line. 4 | 5 | 6 | For more information, please check out the MultiMarkdown [web 7 | site](http://fletcherpenney.net/multimarkdown/). 8 | 9 | You will be guided through the steps necessary to install this software. -------------------------------------------------------------------------------- /markdown.c: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | 3 | markdown.c - markdown in C using a PEG grammar. 4 | (c) 2008 John MacFarlane (jgm at berkeley dot edu). 5 | 6 | portions Copyright (c) 2010-2013 Fletcher T. Penney 7 | portions Copyright (c) 2011 Daniel Jalkut 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License or the MIT 11 | license. See LICENSE for details. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | ***********************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "glib.h" 27 | #include "markdown_peg.h" 28 | 29 | static int extensions; 30 | 31 | /********************************************************************** 32 | 33 | The main program is just a wrapper around the library functions in 34 | markdown_lib.c. It parses command-line options, reads the text to 35 | be converted from input files or stdin, converts the text, and sends 36 | the output to stdout or a file. Character encodings are ignored. 37 | 38 | ***********************************************************************/ 39 | 40 | #define VERSION "3.7" 41 | #define COPYRIGHT "portions Copyright (c) 2010-2013 Fletcher T. Penney.\n" \ 42 | "portions Copyright (c) 2011 Daniel Jalkut, MIT licensed.\n" \ 43 | "original Copyright (c) 2008-2009 John MacFarlane. License GPLv2+ or MIT.\n" \ 44 | "This is free software: you are free to change and redistribute it.\n" \ 45 | "There is NO WARRANTY, to the extent permitted by law." 46 | 47 | /* print version and copyright information */ 48 | void version(const char *progname) 49 | { 50 | printf("peg-multimarkdown version %s\n" 51 | "%s\n", 52 | VERSION, 53 | COPYRIGHT); 54 | } 55 | 56 | #define MD_ARGUMENT_FLAG(name, flagChar, flagValue, outPointer, desc, argPlaceholder) { name, no_argument, outPointer, outPointer ? flagValue : flagChar } 57 | #define MD_ARGUMENT_STRING(name, flagChar, outPointer, desc, argPlaceholder) { name, required_argument, NULL, flagChar } 58 | 59 | /* With getopt we don't get the same fancy automatic usage (I don't think?) so for now we're faking it ... */ 60 | static void printUsage() { 61 | printf("Usage:\ 62 | multimarkdown [OPTION...] [FILE...]\n\ 63 | \n\ 64 | Help Options:\n\ 65 | -h, --help Show help options\n\ 66 | \n\ 67 | Application Options:\n\ 68 | -v, --version print version and exit\n\ 69 | -o, --output=FILE send output to FILE (default is stdout)\n\ 70 | -t, --to=FORMAT convert to FORMAT (default is html)\n\ 71 | -x, --extensions use all syntax extensions\n\ 72 | --filter-html filter out raw HTML (except styles)\n\ 73 | --filter-styles filter out HTML styles\n\ 74 | -c, --compatibility markdown compatibility mode\n\ 75 | -b, --batch process multiple files automatically\n\ 76 | -e, --extract extract and display specified metadata\n\ 77 | \n\ 78 | Syntax extensions\n\ 79 | --smart --nosmart toggle smart typography extension\n\ 80 | --notes --nonotes toggle notes extension\n\ 81 | --process-html process MultiMarkdown inside of raw HTML\n\ 82 | --nolabels do not generate id attributes for headers\n\ 83 | \n\ 84 | Converts text in specified files (or stdin) from markdown to FORMAT.\n\ 85 | Available FORMATs: html, latex, memoir, beamer, odf, opml\n"); 86 | } 87 | 88 | int main(int argc, char * argv[]) { 89 | 90 | int numargs; /* number of filename arguments */ 91 | int i; 92 | 93 | GString *inputbuf; 94 | char *out; /* string containing processed output */ 95 | 96 | GString *file; 97 | char *fake; 98 | FILE *input; 99 | FILE *output; 100 | char curchar; 101 | char *progname = argv[0]; 102 | 103 | int output_format = HTML_FORMAT; 104 | 105 | /* Code for command-line option parsing. */ 106 | 107 | static gboolean opt_version = FALSE; 108 | static gchar *opt_output = 0; 109 | static gchar *opt_to = 0; 110 | static gboolean opt_smart = TRUE; 111 | static gboolean opt_no_smart = FALSE; 112 | static gboolean opt_notes = TRUE; 113 | static gboolean opt_no_notes = FALSE; 114 | static gboolean opt_process_html = FALSE; 115 | static gboolean opt_filter_html = FALSE; 116 | static gboolean opt_filter_styles = FALSE; 117 | static gboolean opt_allext = FALSE; 118 | static gboolean opt_compatibility = FALSE; 119 | static gboolean opt_batchmode = FALSE; 120 | static gchar *opt_extract_meta = FALSE; 121 | static gboolean opt_no_labels = FALSE; 122 | 123 | static struct option entries[] = 124 | { 125 | MD_ARGUMENT_FLAG( "help", 'h', 1, NULL, "Show help options", NULL ), 126 | MD_ARGUMENT_FLAG( "version", 'v', 1, &opt_version, "print version and exit", NULL ), 127 | MD_ARGUMENT_STRING( "output", 'o', &opt_output, "send output to FILE (default is stdout)", "FILE" ), 128 | MD_ARGUMENT_STRING( "to", 't', &opt_to, "convert to FORMAT (default is html)", "FORMAT" ), 129 | MD_ARGUMENT_FLAG( "extensions", 'x', 1, &opt_allext, "use all syntax extensions", NULL ), 130 | MD_ARGUMENT_FLAG( "filter-html", 0, 1, &opt_filter_html, "filter out raw HTML (except styles)", NULL ), 131 | MD_ARGUMENT_FLAG( "filter-styles", 0, 1, &opt_filter_styles, "filter out HTML styles", NULL ), 132 | MD_ARGUMENT_FLAG( "compatibility", 'c', 1, &opt_compatibility, "markdown compatibility mode", NULL ), 133 | MD_ARGUMENT_FLAG( "batch", 'b', 1, &opt_batchmode, "process multiple files automatically", NULL ), 134 | MD_ARGUMENT_STRING( "extract", 'e', &opt_extract_meta, "extract and display specified metadata", NULL ), 135 | MD_ARGUMENT_FLAG( "smart", 0, 1, &opt_smart, "use smart typography extension (on by default)", NULL ), 136 | MD_ARGUMENT_FLAG( "nosmart", 0, 1, &opt_no_smart, "do not use smart typography extension", NULL ), 137 | MD_ARGUMENT_FLAG( "notes", 0, 1, &opt_notes, "use notes extension (on by default)", NULL ), 138 | MD_ARGUMENT_FLAG( "nonotes", 0, 1, &opt_no_notes, "do not use notes extension", NULL ), 139 | MD_ARGUMENT_FLAG( "process-html", 0, 1, &opt_process_html, "process MultiMarkdown inside of raw HTML", NULL ), 140 | MD_ARGUMENT_FLAG( "nolabels", 0, 1, &opt_no_labels, "do not generate id attributes for headers", NULL ), 141 | { NULL } 142 | }; 143 | 144 | char ch; 145 | while ((ch = getopt_long(argc, argv, "hvo:t:xcbe:", entries, NULL)) != -1) { 146 | switch (ch) { 147 | case 'h': 148 | printUsage(); 149 | return EXIT_SUCCESS; 150 | break; 151 | case 'v': 152 | opt_version = true; 153 | break; 154 | case 'o': 155 | opt_output = malloc(strlen(optarg) + 1); 156 | strcpy(opt_output, optarg); 157 | break; 158 | case 't': 159 | opt_to = malloc(strlen(optarg) + 1); 160 | strcpy(opt_to, optarg); 161 | break; 162 | case 'x': 163 | opt_allext = true; 164 | break; 165 | case 'c': 166 | opt_compatibility = true; 167 | break; 168 | case 'b': 169 | opt_batchmode = true; 170 | break; 171 | case 'e': 172 | opt_extract_meta = malloc(strlen(optarg) + 1); 173 | strcpy(opt_extract_meta, optarg); 174 | break; 175 | } 176 | } 177 | 178 | argc -= optind; 179 | argv += optind; 180 | 181 | /* We expect argc and argv to still point just one below the start of remaining args */ 182 | argc++; 183 | argv--; 184 | 185 | /* Process command-line options and arguments. */ 186 | 187 | if (opt_version) { 188 | version(progname); 189 | return EXIT_SUCCESS; 190 | } 191 | 192 | extensions = 0; 193 | if (opt_allext) 194 | extensions = 0xFFFFFF; /* turn on all extensions */ 195 | if (opt_no_smart) 196 | opt_smart = FALSE; 197 | if (opt_smart) 198 | extensions = extensions | EXT_SMART; 199 | if (opt_no_notes) 200 | opt_notes = FALSE; 201 | if (opt_notes) 202 | extensions = extensions | EXT_NOTES; 203 | if (opt_process_html) 204 | extensions = extensions | EXT_PROCESS_HTML; 205 | if (opt_filter_html) 206 | extensions = extensions | EXT_FILTER_HTML; 207 | if (opt_filter_styles) 208 | extensions = extensions | EXT_FILTER_STYLES; 209 | if (opt_no_labels) 210 | extensions = extensions | EXT_NO_LABELS; 211 | 212 | /* Compatibility mode turns off extensions and most 213 | MultiMarkdown-specific features */ 214 | if (opt_compatibility) { 215 | extensions = 0x000000; 216 | extensions = extensions | EXT_COMPATIBILITY; 217 | extensions = extensions | EXT_NO_LABELS; 218 | } 219 | 220 | if (opt_to == NULL) 221 | output_format = HTML_FORMAT; 222 | else if (strcmp(opt_to, "html") == 0) 223 | output_format = HTML_FORMAT; 224 | else if (strcmp(opt_to, "latex") == 0) 225 | output_format = LATEX_FORMAT; 226 | else if (strcmp(opt_to, "memoir") == 0) 227 | output_format = MEMOIR_FORMAT; 228 | else if (strcmp(opt_to, "beamer") == 0) 229 | output_format = BEAMER_FORMAT; 230 | else if (strcmp(opt_to, "opml") == 0) 231 | output_format = OPML_FORMAT; 232 | else if (strcmp(opt_to, "odf") == 0) 233 | output_format = ODF_FORMAT; 234 | else { 235 | fprintf(stderr, "%s: Unknown output format '%s'\n", progname, opt_to); 236 | exit(EXIT_FAILURE); 237 | } 238 | 239 | numargs = argc - 1; 240 | 241 | if (opt_batchmode && numargs != 0) { 242 | /* handle each file individually, and set output to filename with 243 | appropriate extension */ 244 | 245 | for (i = 0; i < numargs; i++) { 246 | inputbuf = g_string_new(""); /* string for concatenated input */ 247 | /* Read file */ 248 | if ((input = fopen(argv[i+1], "r")) == NULL) { 249 | perror(argv[i+1]); 250 | exit(EXIT_FAILURE); 251 | } 252 | while ((curchar = fgetc(input)) != EOF) 253 | g_string_append_c(inputbuf, curchar); 254 | fclose(input); 255 | 256 | /* Display metadata on request */ 257 | if (opt_extract_meta) { 258 | out = extract_metadata_value(inputbuf->str, extensions, opt_extract_meta); 259 | if (out != NULL) fprintf(stdout, "%s\n", out); 260 | return(EXIT_SUCCESS); 261 | } 262 | 263 | /* remove file extension, if present */ 264 | fake = argv[i+1]; 265 | if (strrchr(fake, '.') != NULL) { 266 | int count = strrchr(fake,'.') - fake; 267 | if (count != 0) { 268 | fake[count] = '\0'; 269 | } 270 | } 271 | 272 | file = g_string_new(fake); 273 | if (output_format == HTML_FORMAT) { 274 | g_string_append(file,".html"); 275 | } else if (output_format == OPML_FORMAT) { 276 | g_string_append(file,".opml"); 277 | } else if (output_format == ODF_FORMAT) { 278 | g_string_append(file,".fodt"); 279 | } else { 280 | g_string_append(file,".tex"); 281 | } 282 | 283 | /* open output file */ 284 | if (!(output = fopen(file->str, "w"))) { 285 | perror(opt_output); 286 | return 1; 287 | } 288 | 289 | out = markdown_to_string(inputbuf->str, extensions, output_format); 290 | 291 | fprintf(output, "%s\n", out); 292 | fclose(output); 293 | g_string_free(file,true); 294 | free(out); 295 | g_string_free(inputbuf, true); 296 | } 297 | 298 | } else { 299 | /* Read input from stdin or input files into inputbuf */ 300 | 301 | inputbuf = g_string_new(""); /* string for concatenated input */ 302 | 303 | if (numargs == 0) { /* use stdin if no files specified */ 304 | while ((curchar = fgetc(stdin)) != EOF) 305 | g_string_append_c(inputbuf, curchar); 306 | fclose(stdin); 307 | } 308 | else { /* open all the files on command line */ 309 | for (i = 0; i < numargs; i++) { 310 | if ((input = fopen(argv[i+1], "r")) == NULL) { 311 | perror(argv[i+1]); 312 | exit(EXIT_FAILURE); 313 | } 314 | while ((curchar = fgetc(input)) != EOF) 315 | g_string_append_c(inputbuf, curchar); 316 | fclose(input); 317 | } 318 | } 319 | 320 | /* Display metadata on request */ 321 | if (opt_extract_meta) { 322 | out = extract_metadata_value(inputbuf->str, extensions, opt_extract_meta); 323 | if (out != NULL) fprintf(stdout, "%s\n", out); 324 | return(EXIT_SUCCESS); 325 | } 326 | 327 | /* we allow "-" as a synonym for stdout here */ 328 | if (opt_output == NULL || strcmp(opt_output, "-") == 0) 329 | output = stdout; 330 | else if (!(output = fopen(opt_output, "w"))) { 331 | perror(opt_output); 332 | return 1; 333 | } 334 | 335 | out = markdown_to_string(inputbuf->str, extensions, output_format); 336 | fprintf(output, "%s\n", out); 337 | free(out); 338 | fclose(output); 339 | g_string_free(inputbuf, true); 340 | 341 | } 342 | 343 | return(EXIT_SUCCESS); 344 | } 345 | -------------------------------------------------------------------------------- /markdown_lib.c: -------------------------------------------------------------------------------- 1 | 2 | /********************************************************************** 3 | 4 | markdown_lib.c - markdown in C using a PEG grammar. 5 | (c) 2008 John MacFarlane (jgm at berkeley dot edu). 6 | 7 | portions Copyright (c) 2010-2013 Fletcher T. Penney 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License or the MIT 11 | license. See LICENSE for details. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | ***********************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "markdown_peg.h" 24 | 25 | #define TABSTOP 4 26 | #define VERSION "3.7" 27 | 28 | /* preformat_text - allocate and copy text buffer while 29 | * performing tab expansion. */ 30 | static GString *preformat_text(char *text) { 31 | GString *buf; 32 | char next_char; 33 | int charstotab; 34 | 35 | int len = 0; 36 | 37 | buf = g_string_new(""); 38 | 39 | charstotab = TABSTOP; 40 | while ((next_char = *text++) != '\0') { 41 | switch (next_char) { 42 | case '\t': 43 | while (charstotab > 0) 44 | g_string_append_c(buf, ' '), len++, charstotab--; 45 | break; 46 | case '\n': 47 | g_string_append_c(buf, '\n'), len++, charstotab = TABSTOP; 48 | break; 49 | default: 50 | g_string_append_c(buf, next_char), len++, charstotab--; 51 | } 52 | if (charstotab == 0) 53 | charstotab = TABSTOP; 54 | } 55 | g_string_append(buf, "\n\n"); 56 | return(buf); 57 | } 58 | 59 | /* print_tree - print tree of elements, for debugging only. */ 60 | static void print_tree(element * elt, int indent) { 61 | int i; 62 | char * key; 63 | while (elt != NULL) { 64 | for (i = 0; i < indent; i++) 65 | fputc(' ', stderr); 66 | switch (elt->key) { 67 | case LIST: key = "LIST"; break; 68 | case RAW: key = "RAW"; break; 69 | case SPACE: key = "SPACE"; break; 70 | case LINEBREAK: key = "LINEBREAK"; break; 71 | case ELLIPSIS: key = "ELLIPSIS"; break; 72 | case EMDASH: key = "EMDASH"; break; 73 | case ENDASH: key = "ENDASH"; break; 74 | case APOSTROPHE: key = "APOSTROPHE"; break; 75 | case SINGLEQUOTED: key = "SINGLEQUOTED"; break; 76 | case DOUBLEQUOTED: key = "DOUBLEQUOTED"; break; 77 | case STR: key = "STR"; break; 78 | case LINK: key = "LINK"; break; 79 | case IMAGE: key = "IMAGE"; break; 80 | case CODE: key = "CODE"; break; 81 | case HTML: key = "HTML"; break; 82 | case EMPH: key = "EMPH"; break; 83 | case STRONG: key = "STRONG"; break; 84 | case PLAIN: key = "PLAIN"; break; 85 | case PARA: key = "PARA"; break; 86 | case LISTITEM: key = "LISTITEM"; break; 87 | case BULLETLIST: key = "BULLETLIST"; break; 88 | case ORDEREDLIST: key = "ORDEREDLIST"; break; 89 | case H1: key = "H1"; break; 90 | case H2: key = "H2"; break; 91 | case H3: key = "H3"; break; 92 | case H4: key = "H4"; break; 93 | case H5: key = "H5"; break; 94 | case H6: key = "H6"; break; 95 | case BLOCKQUOTE: key = "BLOCKQUOTE"; break; 96 | case VERBATIM: key = "VERBATIM"; break; 97 | case HTMLBLOCK: key = "HTMLBLOCK"; break; 98 | case HRULE: key = "HRULE"; break; 99 | case REFERENCE: key = "REFERENCE"; break; 100 | case NOTE: key = "NOTE"; break; 101 | default: key = "?"; 102 | } 103 | if ( elt->key == STR ) { 104 | fprintf(stderr, "0x%p: %s '%s'\n", (void *)elt, key, elt->contents.str); 105 | } else { 106 | fprintf(stderr, "0x%p: %s\n", (void *)elt, key); 107 | } 108 | if (elt->children) 109 | print_tree(elt->children, indent + 4); 110 | elt = elt->next; 111 | } 112 | } 113 | 114 | /* process_raw_blocks - traverses an element list, replacing any RAW elements with 115 | * the result of parsing them as markdown text, and recursing into the children 116 | * of parent elements. The result should be a tree of elements without any RAWs. */ 117 | static element * process_raw_blocks(element *input, int extensions, element *references, element *notes, element *labels) { 118 | element *current = NULL; 119 | element *last_child = NULL; 120 | char *contents; 121 | current = input; 122 | 123 | while (current != NULL) { 124 | if (current->key == RAW) { 125 | /* \001 is used to indicate boundaries between nested lists when there 126 | * is no blank line. We split the string by \001 and parse 127 | * each chunk separately. */ 128 | contents = strtok(current->contents.str, "\001"); 129 | current->key = LIST; 130 | current->children = parse_markdown(contents, extensions, references, notes, labels); 131 | last_child = current->children; 132 | while ((contents = strtok(NULL, "\001"))) { 133 | while (last_child->next != NULL) 134 | last_child = last_child->next; 135 | last_child->next = parse_markdown(contents, extensions, references, notes, labels); 136 | } 137 | free(current->contents.str); 138 | current->contents.str = NULL; 139 | } 140 | if (current->children != NULL) 141 | current->children = process_raw_blocks(current->children, extensions, references, notes, labels); 142 | current = current->next; 143 | } 144 | return input; 145 | } 146 | 147 | /* markdown_to_gstring - convert markdown text to the output format specified. 148 | * Returns a GString, which must be freed after use using g_string_free(). */ 149 | GString * markdown_to_g_string(char *text, int extensions, int output_format) { 150 | element *result; 151 | element *references; 152 | element *notes; 153 | element *labels; 154 | GString *formatted_text; 155 | GString *out; 156 | out = g_string_new(""); 157 | 158 | formatted_text = preformat_text(text); 159 | 160 | references = parse_references(formatted_text->str, extensions); 161 | notes = parse_notes(formatted_text->str, extensions, references); 162 | labels = parse_labels(formatted_text->str, extensions, references, notes); 163 | 164 | if (output_format == OPML_FORMAT) { 165 | result = parse_markdown_for_opml(formatted_text->str, extensions); 166 | } else { 167 | result = parse_markdown_with_metadata(formatted_text->str, extensions, references, notes, labels); 168 | result = process_raw_blocks(result, extensions, references, notes, labels); 169 | } 170 | 171 | g_string_free(formatted_text, TRUE); 172 | 173 | if (result == NULL) { 174 | /* The parsing was aborted */ 175 | g_string_append(out,"MultiMarkdown was unable to parse this file."); 176 | } else { 177 | print_element_list(out, result, output_format, extensions); 178 | } 179 | free_element_list(result); 180 | 181 | free_element_list(references); 182 | free_element_list(labels); 183 | 184 | return out; 185 | } 186 | 187 | /* markdown_to_string - convert markdown text to the output format specified. 188 | * Returns a null-terminated string, which must be freed after use. */ 189 | char * markdown_to_string(char *text, int extensions, int output_format) { 190 | GString *out; 191 | char *char_out; 192 | out = markdown_to_g_string(text, extensions, output_format); 193 | char_out = out->str; 194 | g_string_free(out, FALSE); 195 | return char_out; 196 | } 197 | 198 | /* vim:set ts=4 sw=4: */ 199 | 200 | /* extract_metadata_value - parse document and return value of specified 201 | metadata key (e.g. "LateX Mode")/ 202 | Returns a null-terminated string, which must be freed after use. */ 203 | char * extract_metadata_value(char *text, int extensions, char *key) { 204 | char *value; 205 | element *result; 206 | element *references; 207 | element *notes; 208 | element *labels; 209 | GString *formatted_text; 210 | 211 | formatted_text = preformat_text(text); 212 | 213 | references = parse_references(formatted_text->str, extensions); 214 | notes = parse_notes(formatted_text->str, extensions, references); 215 | labels = parse_labels(formatted_text->str, extensions, references, notes); 216 | 217 | result = parse_metadata_only(formatted_text->str, extensions); 218 | 219 | value = metavalue_for_key(key, result); 220 | free_element_list(result); 221 | free_element_list(references); 222 | free_element_list(labels); 223 | 224 | return value; 225 | } 226 | 227 | /* has_metadata - parse document and report whether metadata is present */ 228 | gboolean has_metadata(char *text, int extensions) { 229 | gboolean hasMeta; 230 | element *result; 231 | element *references; 232 | element *notes; 233 | element *labels; 234 | GString *formatted_text; 235 | 236 | formatted_text = preformat_text(text); 237 | 238 | references = parse_references(formatted_text->str, extensions); 239 | notes = parse_notes(formatted_text->str, extensions, references); 240 | labels = parse_labels(formatted_text->str, extensions, references, notes); 241 | 242 | result = parse_metadata_only(formatted_text->str, extensions); 243 | 244 | hasMeta = FALSE; 245 | 246 | if (result != NULL) { 247 | if (result->children != NULL) { 248 | hasMeta = TRUE; 249 | free_element_list(result); 250 | } else { 251 | free_element(result); 252 | } 253 | } 254 | 255 | free_element_list(references); 256 | free_element_list(labels); 257 | return hasMeta; 258 | } 259 | 260 | /* version - return the MultiMarkdown library version */ 261 | char * mmd_version() { 262 | char* result = (char*)malloc(8); 263 | sprintf(result, "%s",VERSION); 264 | return result; 265 | } 266 | -------------------------------------------------------------------------------- /markdown_lib.h: -------------------------------------------------------------------------------- 1 | #ifndef MARKDOWN_LIB_H 2 | #define MARKDOWN_LIB_H 3 | 4 | #include 5 | #include 6 | #include "glib.h" 7 | 8 | enum markdown_extensions { 9 | EXT_SMART = 1 << 0, 10 | EXT_NOTES = 1 << 1, 11 | EXT_FILTER_HTML = 1 << 2, 12 | EXT_FILTER_STYLES = 1 << 3, 13 | EXT_COMPATIBILITY = 1 << 4, 14 | EXT_PROCESS_HTML = 1 << 5, 15 | EXT_NO_LABELS = 1 << 6, 16 | }; 17 | 18 | enum markdown_formats { 19 | HTML_FORMAT, 20 | LATEX_FORMAT, 21 | MEMOIR_FORMAT, 22 | BEAMER_FORMAT, 23 | OPML_FORMAT, 24 | GROFF_MM_FORMAT, 25 | ODF_FORMAT, 26 | ODF_BODY_FORMAT, 27 | ORIGINAL_FORMAT 28 | }; 29 | 30 | GString * markdown_to_g_string(char *text, int extensions, int output_format); 31 | char * markdown_to_string(char *text, int extensions, int output_format); 32 | char * extract_metadata_value(char *text, int extensions, char *key); 33 | gboolean has_metadata(char *text, int extensions); 34 | char * mmd_version(); 35 | 36 | /* vim: set ts=4 sw=4 : */ 37 | #endif 38 | 39 | -------------------------------------------------------------------------------- /markdown_peg.h: -------------------------------------------------------------------------------- 1 | /* markdown_peg.h */ 2 | #ifndef MARKDOWN_PEG_H 3 | #define MARKDOWN_PEG_H 4 | 5 | #include "markdown_lib.h" 6 | #include "glib.h" 7 | 8 | /* Information (label, URL and title) for a link. */ 9 | struct Link { 10 | struct Element *label; 11 | char *url; 12 | char *title; 13 | struct Element *attr; 14 | char *identifier; 15 | }; 16 | 17 | typedef struct Link link; 18 | 19 | /* Union for contents of an Element (string, list, or link). */ 20 | union Contents { 21 | char *str; 22 | struct Link *link; 23 | }; 24 | 25 | /* Types of semantic values returned by parsers. */ 26 | enum keys { LIST, /* A generic list of values. For ordered and bullet lists, see below. */ 27 | RAW, /* Raw markdown to be processed further */ 28 | SPACE, 29 | LINEBREAK, 30 | ELLIPSIS, 31 | EMDASH, 32 | ENDASH, 33 | APOSTROPHE, 34 | SINGLEQUOTED, 35 | DOUBLEQUOTED, 36 | STR, 37 | LINK, 38 | IMAGE, 39 | IMAGEBLOCK, 40 | CODE, 41 | HTML, 42 | EMPH, 43 | STRONG, 44 | PLAIN, 45 | PARA, 46 | LISTITEM, 47 | BULLETLIST, 48 | ORDEREDLIST, 49 | H1, H2, H3, H4, H5, H6, H7, /* Code assumes that these are in order. */ 50 | BLOCKQUOTE, 51 | VERBATIM, 52 | HTMLBLOCK, 53 | HRULE, 54 | REFERENCE, 55 | NOTE, 56 | CITATION, 57 | NOCITATION, 58 | LOCATOR, 59 | NOTELABEL, 60 | DEFLIST, 61 | TERM, 62 | DEFINITION, 63 | METAKEY, 64 | METAVALUE, 65 | METADATA, 66 | FOOTER, 67 | LABEL, 68 | HEADINGSECTION, 69 | ENDHTML, 70 | TABLE, 71 | TABLEHEAD, 72 | TABLEBODY, 73 | TABLEROW, 74 | TABLECELL, 75 | CELLSPAN, 76 | TABLECAPTION, 77 | TABLELABEL, 78 | TABLESEPARATOR, 79 | AUTOLABEL, 80 | ATTRIBUTE, 81 | ATTRKEY, 82 | ATTRVALUE, 83 | GLOSSARY, 84 | GLOSSARYTERM, 85 | GLOSSARYSORTKEY, 86 | MATHSPAN 87 | }; 88 | 89 | /* constants for managing Smart Typography */ 90 | enum smartelements { 91 | LSQUOTE, 92 | RSQUOTE, 93 | LDQUOTE, 94 | RDQUOTE, 95 | NDASH, 96 | MDASH, 97 | ELLIP, 98 | APOS, 99 | }; 100 | 101 | enum smartoutput { 102 | HTMLOUT, 103 | LATEXOUT, 104 | }; 105 | 106 | enum language { 107 | DUTCH, 108 | ENGLISH, 109 | FRENCH, 110 | GERMAN, 111 | SWEDISH, 112 | GERMANGUILL, 113 | }; 114 | 115 | /* Semantic value of a parsing action. */ 116 | struct Element { 117 | int key; 118 | union Contents contents; 119 | struct Element *children; 120 | struct Element *next; 121 | }; 122 | 123 | 124 | 125 | typedef struct Element element; 126 | 127 | element * parse_references(char *string, int extensions); 128 | element * parse_notes(char *string, int extensions, element *reference_list); 129 | element * parse_labels(char *string, int extensions, element *reference_list, element *note_list); 130 | 131 | element * parse_markdown(char *string, int extensions, element *reference_list, element *note_list, element *label_list); 132 | element * parse_markdown_with_metadata(char *string, int extensions, element *reference_list, element *note_list, element *label_list); 133 | void free_element_list(element * elt); 134 | void free_element(element *elt); 135 | void print_element_list(GString *out, element *elt, int format, int exts); 136 | 137 | element * parse_metadata_only(char *string, int extensions); 138 | char * extract_metadata_value(char *text, int extensions, char *key); 139 | 140 | char * metavalue_for_key(char *key, element *list); 141 | 142 | element * parse_markdown_for_opml(char *string, int extensions); 143 | #endif 144 | -------------------------------------------------------------------------------- /odf.c: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | 3 | odf.c - Utility routines to enable ODF support in peg-multimarkdown. 4 | (c) 2011 Fletcher T. Penney (http://fletcherpenney.net/). 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License or the MIT 8 | license. See LICENSE for details. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | ***********************************************************************/ 16 | 17 | #include "odf.h" 18 | 19 | 20 | void print_odf_header(GString *out){ 21 | 22 | /* Insert required XML header */ 23 | g_string_append_printf(out, 24 | "\n" \ 25 | "\n"); 60 | 61 | /* Font Declarations */ 62 | g_string_append_printf(out, "\n" \ 63 | " \n" \ 67 | "\n"); 68 | 69 | /* Append basic style information */ 70 | g_string_append_printf(out, "\n" \ 71 | "\n" \ 72 | " \n" \ 74 | " \n" \ 75 | "\n" \ 79 | " \n" \ 81 | " \n" \ 86 | "\n" \ 87 | "\n" \ 89 | " \n" \ 92 | "\n" \ 93 | "\n" \ 96 | " \n" \ 97 | " \n" \ 98 | "\n" \ 99 | "\n" \ 102 | " \n" \ 108 | "\n" \ 109 | "\n" \ 113 | " \n" \ 116 | " \n" \ 118 | "\n" \ 119 | "\n" \ 123 | " \n" \ 133 | " \n" \ 134 | "\n" \ 135 | "" \ 137 | " " \ 138 | " " \ 139 | "\n"); 140 | 141 | /* Automatic style information */ 142 | g_string_append_printf(out, "" \ 143 | " \n" \ 144 | " \n" \ 146 | " \n" \ 147 | " \n" \ 148 | " \n" \ 150 | " \n" \ 151 | "\n" \ 152 | " \n" \ 153 | "\n" \ 154 | "\n" \ 155 | " \n" \ 156 | "\n" \ 157 | "\n" \ 158 | " \n" \ 159 | "\n" \ 160 | "\n" \ 162 | "\n" \ 163 | "\n" \ 164 | "\n" \ 165 | " \n" \ 170 | "\n" \ 171 | "\n" \ 172 | "\n" \ 174 | "\n" \ 175 | " \n" \ 176 | "\n" \ 177 | "\n" \ 178 | " \n" \ 179 | "\n"); 180 | } 181 | 182 | void print_odf_footer(GString *out) { 183 | g_string_append_printf(out, "\n\n"); 184 | } 185 | 186 | -------------------------------------------------------------------------------- /odf.h: -------------------------------------------------------------------------------- 1 | #ifndef ODF_H 2 | #define ODF_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void print_odf_header(GString *out); 9 | void print_odf_footer(GString *out); 10 | #endif 11 | 12 | -------------------------------------------------------------------------------- /parsing_functions.c: -------------------------------------------------------------------------------- 1 | /* parsing_functions.c - Functions for parsing markdown and 2 | * freeing element lists. */ 3 | 4 | /* These yy_* functions come from markdown_parser.c which is 5 | * generated from markdown_parser.leg 6 | * */ 7 | typedef int (*yyrule)(); 8 | 9 | extern int yyparse(); 10 | extern int yyparsefrom(yyrule); 11 | extern int yy_References(); 12 | extern int yy_Notes(); 13 | extern int yy_Doc(); 14 | 15 | extern int yy_AutoLabels(); 16 | extern int yy_DocWithMetaData(); 17 | extern int yy_MetaDataOnly(); 18 | extern int yy_DocForOPML(); 19 | 20 | #include "utility_functions.h" 21 | #include "parsing_functions.h" 22 | #include "markdown_peg.h" 23 | 24 | static void free_element_contents(element elt); 25 | 26 | /* free_element_list - free list of elements recursively */ 27 | void free_element_list(element * elt) { 28 | element * next = NULL; 29 | while (elt != NULL) { 30 | next = elt->next; 31 | free_element_contents(*elt); 32 | if (elt->children != NULL) { 33 | free_element_list(elt->children); 34 | elt->children = NULL; 35 | } 36 | free(elt); 37 | elt = next; 38 | } 39 | } 40 | 41 | /* free_element_contents - free element contents depending on type */ 42 | static void free_element_contents(element elt) { 43 | switch (elt.key) { 44 | case STR: 45 | case SPACE: 46 | case RAW: 47 | case HTMLBLOCK: 48 | case HTML: 49 | case VERBATIM: 50 | case CODE: 51 | case NOTE: 52 | case AUTOLABEL: 53 | case CITATION: 54 | case TERM: 55 | case METAKEY: 56 | case METAVALUE: 57 | case TABLESEPARATOR: 58 | case ATTRKEY: 59 | case GLOSSARY: 60 | case GLOSSARYTERM: 61 | case NOTELABEL: 62 | case CELLSPAN: 63 | case EMDASH: 64 | case ENDASH: 65 | case GLOSSARYSORTKEY: 66 | case MATHSPAN: 67 | free(elt.contents.str); 68 | elt.contents.str = NULL; 69 | break; 70 | case LINK: 71 | case IMAGE: 72 | case REFERENCE: 73 | free(elt.contents.link->url); 74 | elt.contents.link->url = NULL; 75 | free(elt.contents.link->title); 76 | elt.contents.link->title = NULL; 77 | free_element_list(elt.contents.link->label); 78 | free(elt.contents.link->identifier); 79 | elt.contents.link->identifier = NULL; 80 | /* free_element_list(elt.contents.link->attr);*/ 81 | free(elt.contents.link); 82 | elt.contents.link = NULL; 83 | break; 84 | default: 85 | ; 86 | } 87 | } 88 | 89 | /* free_element - free element and contents */ 90 | void free_element(element *elt) { 91 | free_element_contents(*elt); 92 | free(elt); 93 | } 94 | 95 | element * parse_references(char *string, int extensions) { 96 | 97 | char *oldcharbuf; 98 | syntax_extensions = extensions; 99 | 100 | oldcharbuf = charbuf; 101 | charbuf = string; 102 | yyparsefrom(yy_References); /* first pass, just to collect references */ 103 | charbuf = oldcharbuf; 104 | 105 | return references; 106 | } 107 | 108 | element * parse_notes(char *string, int extensions, element *reference_list) { 109 | 110 | char *oldcharbuf; 111 | notes = NULL; 112 | syntax_extensions = extensions; 113 | 114 | if (extension(EXT_NOTES)) { 115 | references = reference_list; 116 | oldcharbuf = charbuf; 117 | charbuf = string; 118 | yyparsefrom(yy_Notes); /* second pass for notes */ 119 | charbuf = oldcharbuf; 120 | } 121 | 122 | return notes; 123 | } 124 | 125 | element * parse_labels(char *string, int extensions, element *reference_list, element *note_list) { 126 | 127 | char *oldcharbuf; 128 | syntax_extensions = extensions; 129 | references = reference_list; 130 | notes = note_list; 131 | labels = NULL; 132 | 133 | oldcharbuf = charbuf; 134 | charbuf = string; 135 | yyparsefrom(yy_AutoLabels); /* third pass, to collect labels */ 136 | charbuf = oldcharbuf; 137 | 138 | return labels; 139 | } 140 | 141 | element * parse_markdown(char *string, int extensions, element *reference_list, element *note_list, element *label_list) { 142 | 143 | char *oldcharbuf; 144 | syntax_extensions = extensions; 145 | references = reference_list; 146 | notes = note_list; 147 | labels = label_list; 148 | 149 | oldcharbuf = charbuf; 150 | charbuf = string; 151 | 152 | yyparsefrom(yy_Doc); 153 | 154 | charbuf = oldcharbuf; /* restore charbuf to original value */ 155 | 156 | /* if (parse_aborted) { 157 | free_element_list(parse_result); 158 | return NULL; 159 | }*/ 160 | 161 | return parse_result; 162 | 163 | } 164 | 165 | element * parse_markdown_with_metadata(char *string, int extensions, element *reference_list, element *note_list, element *label_list) { 166 | 167 | char *oldcharbuf; 168 | syntax_extensions = extensions; 169 | references = reference_list; 170 | notes = note_list; 171 | labels = label_list; 172 | 173 | oldcharbuf = charbuf; 174 | charbuf = string; 175 | 176 | start_time = clock(); 177 | 178 | yyparsefrom(yy_DocWithMetaData); 179 | charbuf = oldcharbuf; /* restore charbuf to original value */ 180 | 181 | /* reset start_time for subsequent passes */ 182 | start_time = 0; 183 | 184 | if (parse_aborted) { 185 | parse_aborted = 0; 186 | free_element_list(parse_result); 187 | return NULL; 188 | } 189 | 190 | return parse_result; 191 | 192 | } 193 | 194 | element * parse_metadata_only(char *string, int extensions) { 195 | 196 | char *oldcharbuf; 197 | syntax_extensions = extensions; 198 | 199 | oldcharbuf = charbuf; 200 | charbuf = string; 201 | 202 | yyparsefrom(yy_MetaDataOnly); 203 | 204 | charbuf = oldcharbuf; /* restore charbuf to original value */ 205 | return parse_result; 206 | 207 | } 208 | 209 | element * parse_markdown_for_opml(char *string, int extensions) { 210 | 211 | char *oldcharbuf; 212 | syntax_extensions = extensions; 213 | 214 | oldcharbuf = charbuf; 215 | charbuf = string; 216 | 217 | yyparsefrom(yy_DocForOPML); 218 | 219 | charbuf = oldcharbuf; /* restore charbuf to original value */ 220 | return parse_result; 221 | 222 | } 223 | -------------------------------------------------------------------------------- /parsing_functions.h: -------------------------------------------------------------------------------- 1 | #ifndef PARSING_FUNCTIONS_H 2 | #define PARSING_FUNCTIONS_H 3 | /* parsing_functions.c - Functions for parsing markdown and 4 | * freeing element lists. */ 5 | 6 | #include "markdown_peg.h" 7 | 8 | /* free_element_list - free list of elements recursively */ 9 | void free_element_list(element * elt); 10 | /* free_element - free element and contents */ 11 | void free_element(element *elt); 12 | 13 | element * parse_references(char *string, int extensions); 14 | element * parse_notes(char *string, int extensions, element *reference_list); 15 | element * parse_markdown(char *string, int extensions, element *reference_list, element *note_list, element *label_list); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /peg-0.1.9/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -g -Wall $(OFLAGS) $(XFLAGS) 2 | OFLAGS = -O3 -DNDEBUG 3 | #OFLAGS = -pg 4 | 5 | OBJS = tree.o compile.o 6 | 7 | all : peg leg 8 | 9 | peg : peg.o $(OBJS) 10 | $(CC) $(CFLAGS) -o $@-new peg.o $(OBJS) 11 | mv $@-new $@ 12 | 13 | leg : leg.o $(OBJS) 14 | $(CC) $(CFLAGS) -o $@-new leg.o $(OBJS) 15 | mv $@-new $@ 16 | 17 | ROOT = 18 | PREFIX = /usr/local 19 | BINDIR = $(ROOT)$(PREFIX)/bin 20 | 21 | install : $(BINDIR)/peg $(BINDIR)/leg 22 | 23 | $(BINDIR)/% : % 24 | cp -p $< $@ 25 | strip $@ 26 | 27 | uninstall : .FORCE 28 | rm -f $(BINDIR)/peg 29 | rm -f $(BINDIR)/leg 30 | 31 | peg.o : peg.c peg.peg-c 32 | 33 | %.peg-c : %.peg compile.c 34 | ./peg -o $@ $< 35 | 36 | leg.o : leg.c 37 | 38 | leg.c : leg.leg compile.c 39 | ./leg -o $@ $< 40 | 41 | check : check-peg check-leg 42 | 43 | check-peg : peg .FORCE 44 | ./peg < peg.peg > peg.out 45 | diff peg.peg-c peg.out 46 | rm peg.out 47 | 48 | check-leg : leg .FORCE 49 | ./leg < leg.leg > leg.out 50 | diff leg.c leg.out 51 | rm leg.out 52 | 53 | test examples : .FORCE 54 | $(SHELL) -ec '(cd examples; $(MAKE))' 55 | 56 | clean : .FORCE 57 | rm -f *~ *.o *.peg.[cd] *.leg.[cd] 58 | $(SHELL) -ec '(cd examples; $(MAKE) $@)' 59 | 60 | spotless : clean .FORCE 61 | rm -f peg 62 | rm -f leg 63 | $(SHELL) -ec '(cd examples; $(MAKE) $@)' 64 | 65 | .FORCE : 66 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/Makefile: -------------------------------------------------------------------------------- 1 | EXAMPLES = test rule accept wc dc dcv calc basic localctx 2 | 3 | CFLAGS = -g -O3 4 | 5 | DIFF = diff 6 | TEE = cat > 7 | 8 | all : $(EXAMPLES) 9 | 10 | test : .FORCE 11 | ../peg -o test.peg.c test.peg 12 | $(CC) $(CFLAGS) -o test test.c 13 | echo 'ab.ac.ad.ae.afg.afh.afg.afh.afi.afj.' | ./$@ | $(TEE) $@.out 14 | $(DIFF) $@.ref $@.out 15 | rm -f $@.out 16 | @echo 17 | 18 | rule : .FORCE 19 | ../peg -o rule.peg.c rule.peg 20 | $(CC) $(CFLAGS) -o rule rule.c 21 | echo 'abcbcdabcbcdabcbcdabcbcd' | ./$@ | $(TEE) $@.out 22 | $(DIFF) $@.ref $@.out 23 | rm -f $@.out 24 | @echo 25 | 26 | accept : .FORCE 27 | ../peg -o accept.peg.c accept.peg 28 | $(CC) $(CFLAGS) -o accept accept.c 29 | echo 'abcbcdabcbcdabcbcdabcbcd' | ./$@ | $(TEE) $@.out 30 | $(DIFF) $@.ref $@.out 31 | rm -f $@.out 32 | @echo 33 | 34 | wc : .FORCE 35 | ../leg -o wc.leg.c wc.leg 36 | $(CC) $(CFLAGS) -o wc wc.leg.c 37 | cat wc.leg | ./$@ | $(TEE) $@.out 38 | $(DIFF) $@.ref $@.out 39 | rm -f $@.out 40 | @echo 41 | 42 | dc : .FORCE 43 | ../peg -o dc.peg.c dc.peg 44 | $(CC) $(CFLAGS) -o dc dc.c 45 | echo ' 2 *3 *(3+ 4) ' | ./dc | $(TEE) $@.out 46 | $(DIFF) $@.ref $@.out 47 | rm -f $@.out 48 | @echo 49 | 50 | dcv : .FORCE 51 | ../peg -o dcv.peg.c dcv.peg 52 | $(CC) $(CFLAGS) -o dcv dcv.c 53 | echo 'a = 6; b = 7; a * b' | ./dcv | $(TEE) $@.out 54 | $(DIFF) $@.ref $@.out 55 | rm -f $@.out 56 | @echo 57 | 58 | calc : .FORCE 59 | ../leg -o calc.leg.c calc.leg 60 | $(CC) $(CFLAGS) -o calc calc.leg.c 61 | echo 'a = 6; b = 7; a * b' | ./calc | $(TEE) $@.out 62 | $(DIFF) $@.ref $@.out 63 | rm -f $@.out 64 | @echo 65 | 66 | basic : .FORCE 67 | ../leg -o basic.leg.c basic.leg 68 | $(CC) $(CFLAGS) -o basic basic.leg.c 69 | ( echo 'load "test"'; echo "run" ) | ./basic | $(TEE) $@.out 70 | $(DIFF) $@.ref $@.out 71 | rm -f $@.out 72 | @echo 73 | 74 | localctx : .FORCE 75 | ../peg -o test.peg.c test.peg 76 | $(CC) $(CFLAGS) -o localctx localctx.c 77 | echo 'ab.ac.ad.ae.afg.afh.afg.afh.afi.afj.' | ./$@ | $(TEE) $@.out 78 | $(DIFF) $@.ref $@.out 79 | rm -f $@.out 80 | @echo 81 | 82 | clean : .FORCE 83 | rm -f *~ *.o *.[pl]eg.[cd] $(EXAMPLES) 84 | rm -rf *.dSYM 85 | 86 | spotless : clean 87 | 88 | .FORCE : 89 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/accept.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "accept.peg.c" 5 | 6 | int main() 7 | { 8 | while (yyparse()); 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/accept.peg: -------------------------------------------------------------------------------- 1 | start <- abcd+ 2 | 3 | abcd <- 'a' { printf("A %d\n", yypos); } bc { printf("ABC %d\n", yypos); } &{YYACCEPT} 4 | / 'b' { printf("B %d\n", yypos); } cd { printf("BCD %d\n", yypos); } &{YYACCEPT} 5 | 6 | bc <- 'b' { printf("B %d\n", yypos); } 'c' { printf("C %d\n", yypos); } 7 | 8 | cd <- 'c' { printf("C %d\n", yypos); } 'd' { printf("D %d\n", yypos); } 9 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/accept.ref: -------------------------------------------------------------------------------- 1 | A 3 2 | B 3 3 | C 3 4 | ABC 3 5 | B 3 6 | C 3 7 | D 3 8 | BCD 3 9 | A 3 10 | B 3 11 | C 3 12 | ABC 3 13 | B 3 14 | C 3 15 | D 3 16 | BCD 3 17 | A 3 18 | B 3 19 | C 3 20 | ABC 3 21 | B 3 22 | C 3 23 | D 3 24 | BCD 3 25 | A 3 26 | B 3 27 | C 3 28 | ABC 3 29 | B 3 30 | C 3 31 | D 3 32 | BCD 3 33 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/basic.leg: -------------------------------------------------------------------------------- 1 | # A 'syntax-directed interpreter' (all execution is a side-effect of parsing). 2 | # Inspired by Dennis Allison's original Tiny BASIC grammar, circa 1975. 3 | # 4 | # Copyright (c) 2007 by Ian Piumarta 5 | # All rights reserved. 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a 8 | # copy of this software and associated documentation files (the 'Software'), 9 | # to deal in the Software without restriction, including without limitation 10 | # the rights to use, copy, modify, merge, publish, distribute, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, provided that the above copyright notice(s) and this 13 | # permission notice appear in all copies of the Software. Acknowledgement 14 | # of the use of this Software in supporting documentation would be 15 | # appreciated but is not required. 16 | # 17 | # THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. 18 | # 19 | # Last edited: 2012-04-29 15:14:06 by piumarta on emilia 20 | 21 | %{ 22 | # include 23 | 24 | typedef struct line line; 25 | 26 | struct line 27 | { 28 | int number; 29 | int length; 30 | char *text; 31 | }; 32 | 33 | line *lines= 0; 34 | int numLines= 0; 35 | int pc= -1, epc= -1; 36 | int batch= 0; 37 | 38 | int nextline(char *buf, int max); 39 | 40 | # define min(x, y) ((x) < (y) ? (x) : (y)) 41 | 42 | # define YY_INPUT(buf, result, max_size) \ 43 | { \ 44 | if ((pc >= 0) && (pc < numLines)) \ 45 | { \ 46 | line *linep= lines+pc++; \ 47 | result= min(max_size, linep->length); \ 48 | memcpy(buf, linep->text, result); \ 49 | } \ 50 | else \ 51 | result= nextline(buf, max_size); \ 52 | } 53 | 54 | union value { 55 | int number; 56 | char *string; 57 | int (*binop)(int lhs, int rhs); 58 | }; 59 | 60 | # define YYSTYPE union value 61 | 62 | int variables[26]; 63 | 64 | void accept(int number, char *line); 65 | 66 | void save(char *name); 67 | void load(char *name); 68 | void type(char *name); 69 | 70 | int lessThan(int lhs, int rhs) { return lhs < rhs; } 71 | int lessEqual(int lhs, int rhs) { return lhs <= rhs; } 72 | int notEqual(int lhs, int rhs) { return lhs != rhs; } 73 | int equalTo(int lhs, int rhs) { return lhs == rhs; } 74 | int greaterEqual(int lhs, int rhs) { return lhs >= rhs; } 75 | int greaterThan(int lhs, int rhs) { return lhs > rhs; } 76 | 77 | int input(void); 78 | 79 | int stack[1024], sp= 0; 80 | 81 | char *help; 82 | 83 | void error(char *fmt, ...); 84 | int findLine(int n, int create); 85 | %} 86 | 87 | line = - s:statement CR 88 | | - n:number < ( !CR . )* CR > { accept(n.number, yytext); } 89 | | - CR 90 | | - < ( !CR . )* CR > { epc= pc; error("syntax error"); } 91 | | - !. { exit(0); } 92 | 93 | statement = 'print'- expr-list 94 | | 'if'- e1:expression r:relop e2:expression { if (!r.binop(e1.number, e2.number)) yythunkpos= 0; } 95 | 'then'- statement 96 | | 'goto'- e:expression { epc= pc; if ((pc= findLine(e.number, 0)) < 0) error("no such line"); } 97 | | 'input'- var-list 98 | | 'let'- v:var EQUAL e:expression { variables[v.number]= e.number; } 99 | | 'gosub'- e:expression { epc= pc; if (sp < 1024) stack[sp++]= pc, pc= findLine(e.number, 0); else error("too many gosubs"); 100 | if (pc < 0) error("no such line"); } 101 | | 'return'- { epc= pc; if ((pc= sp ? stack[--sp] : -1) < 0) error("no gosub"); } 102 | | 'clear'- { while (numLines) accept(lines->number, "\n"); } 103 | | 'list'- { int i; for (i= 0; i < numLines; ++i) printf("%5d %s", lines[i].number, lines[i].text); } 104 | | 'run'- s:string { load(s.string); pc= 0; } 105 | | 'run'- { pc= 0; } 106 | | 'end'- { pc= -1; if (batch) exit(0); } 107 | | 'rem'- ( !CR . )* 108 | | ('bye'|'quit'|'exit')- { exit(0); } 109 | | 'save'- s:string { save(s.string); } 110 | | 'load'- s:string { load(s.string); } 111 | | 'type'- s:string { type(s.string); } 112 | | 'dir'- { system("ls *.bas"); } 113 | | 'help'- { fprintf(stderr, "%s", help); } 114 | 115 | expr-list = ( e:string { printf("%s", e.string); } 116 | | e:expression { printf("%d", e.number); } 117 | )? ( COMMA ( e:string { printf("%s", e.string); } 118 | | e:expression { printf("%d", e.number); } 119 | ) 120 | )* ( COMMA 121 | | !COMMA { printf("\n"); } 122 | ) 123 | 124 | var-list = v:var { variables[v.number]= input(); } 125 | ( COMMA v:var { variables[v.number]= input(); } 126 | )* 127 | 128 | expression = ( PLUS? l:term 129 | | MINUS l:term { l.number = -l.number } 130 | ) ( PLUS r:term { l.number += r.number } 131 | | MINUS r:term { l.number -= r.number } 132 | )* { $$.number = l.number } 133 | 134 | term = l:factor ( STAR r:factor { l.number *= r.number } 135 | | SLASH r:factor { l.number /= r.number } 136 | )* { $$.number = l.number } 137 | 138 | factor = v:var { $$.number = variables[v.number] } 139 | | n:number 140 | | OPEN expression CLOSE 141 | 142 | var = < [a-z] > - { $$.number = yytext[0] - 'a' } 143 | 144 | number = < digit+ > - { $$.number = atoi(yytext); } 145 | 146 | digit = [0-9] 147 | 148 | string = '"' < [^\"]* > '"' - { $$.string = yytext; } 149 | 150 | relop = '<=' - { $$.binop= lessEqual; } 151 | | '<>' - { $$.binop= notEqual; } 152 | | '<' - { $$.binop= lessThan; } 153 | | '>=' - { $$.binop= greaterEqual; } 154 | | '>' - { $$.binop= greaterThan; } 155 | | '=' - { $$.binop= equalTo; } 156 | 157 | EQUAL = '=' - CLOSE = ')' - OPEN = '(' - 158 | SLASH = '/' - STAR = '*' - MINUS = '-' - 159 | PLUS = '+' - COMMA = ',' - 160 | 161 | - = [ \t]* 162 | 163 | CR = '\n' | '\r' | '\r\n' 164 | 165 | %% 166 | 167 | #include 168 | #include 169 | 170 | char *help= 171 | "print | [, | ...] [,]\n" 172 | "if <|<=|<>|=|>=|> then \n" 173 | "input [, ...] let = \n" 174 | "goto gosub \n" 175 | "end return\n" 176 | "list clear\n" 177 | "run [\"filename\"] rem \n" 178 | "dir type \"filename\"\n" 179 | "save \"filename\" load \"filename\"\n" 180 | "bye|quit|exit help\n" 181 | ; 182 | 183 | void error(char *fmt, ...) 184 | { 185 | va_list ap; 186 | va_start(ap, fmt); 187 | if (epc > 0) 188 | fprintf(stderr, "\nline %d: %s", lines[epc-1].number, lines[epc-1].text); 189 | else 190 | fprintf(stderr, "\n"); 191 | vfprintf(stderr, fmt, ap); 192 | fprintf(stderr, "\n"); 193 | va_end(ap); 194 | epc= pc= -1; 195 | } 196 | 197 | #ifdef USE_READLINE 198 | # include 199 | # include 200 | #endif 201 | 202 | int nextline(char *buf, int max) 203 | { 204 | pc= -1; 205 | if (batch) exit(0); 206 | if (isatty(fileno(stdin))) 207 | { 208 | # ifdef USE_READLINE 209 | char *line= readline(">"); 210 | if (line) 211 | { 212 | int len= strlen(line); 213 | if (len >= max) len= max - 1; 214 | strncpy(buf, line, len); 215 | (buf)[len]= '\n'; 216 | add_history(line); 217 | free(line); 218 | return len + 1; 219 | } 220 | else 221 | { 222 | printf("\n"); 223 | return 0; 224 | } 225 | # endif 226 | putchar('>'); 227 | fflush(stdout); 228 | } 229 | return fgets(buf, max, stdin) ? strlen(buf) : 0; 230 | } 231 | 232 | int maxLines= 0; 233 | 234 | int findLine(int n, int create) 235 | { 236 | int lo= 0, hi= numLines - 1; 237 | while (lo <= hi) 238 | { 239 | int mid= (lo + hi) / 2, lno= lines[mid].number; 240 | if (lno > n) 241 | hi= mid - 1; 242 | else if (lno < n) 243 | lo= mid + 1; 244 | else 245 | return mid; 246 | } 247 | if (create) 248 | { 249 | if (numLines == maxLines) 250 | { 251 | maxLines *= 2; 252 | lines= realloc(lines, sizeof(line) * maxLines); 253 | } 254 | if (lo < numLines) 255 | memmove(lines + lo + 1, lines + lo, sizeof(line) * (numLines - lo)); 256 | ++numLines; 257 | lines[lo].number= n; 258 | lines[lo].text= 0; 259 | return lo; 260 | } 261 | return -1; 262 | } 263 | 264 | void accept(int n, char *s) 265 | { 266 | if (s[0] < 32) /* delete */ 267 | { 268 | int lno= findLine(n, 0); 269 | if (lno >= 0) 270 | { 271 | if (lno < numLines - 1) 272 | memmove(lines + lno, lines + lno + 1, sizeof(line) * (numLines - lno - 1)); 273 | --numLines; 274 | } 275 | } 276 | else /* insert */ 277 | { 278 | int lno= findLine(n, 1); 279 | if (lines[lno].text) free(lines[lno].text); 280 | lines[lno].length= strlen(s); 281 | lines[lno].text= strdup(s); 282 | } 283 | } 284 | 285 | char *extend(char *name) 286 | { 287 | static char path[1024]; 288 | int len= strlen(name); 289 | sprintf(path, "%s%s", name, (((len > 4) && !strcasecmp(".bas", name + len - 4)) ? "" : ".bas")); 290 | return path; 291 | } 292 | 293 | void save(char *name) 294 | { 295 | FILE *f= fopen(name= extend(name), "w"); 296 | if (!f) 297 | perror(name); 298 | else 299 | { 300 | int i; 301 | for (i= 0; i < numLines; ++i) 302 | fprintf(f, "%d %s", lines[i].number, lines[i].text); 303 | fclose(f); 304 | } 305 | } 306 | 307 | void load(char *name) 308 | { 309 | FILE *f= fopen(name= extend(name), "r"); 310 | if (!f) 311 | perror(name); 312 | else 313 | { 314 | int lineNumber; 315 | char lineText[1024]; 316 | while ((1 == fscanf(f, " %d ", &lineNumber)) && fgets(lineText, sizeof(lineText), f)) 317 | accept(lineNumber, lineText); 318 | fclose(f); 319 | } 320 | } 321 | 322 | void type(char *name) 323 | { 324 | FILE *f= fopen(name= extend(name), "r"); 325 | if (!f) 326 | perror(name); 327 | else 328 | { 329 | int c, d; 330 | while ((c= getc(f)) >= 0) 331 | putchar(d= c); 332 | fclose(f); 333 | if ('\n' != d && '\r' != d) putchar('\n'); 334 | } 335 | } 336 | 337 | int input(void) 338 | { 339 | char line[32]; 340 | fgets(line, sizeof(line), stdin); 341 | return atoi(line); 342 | } 343 | 344 | int main(int argc, char **argv) 345 | { 346 | lines= malloc(sizeof(line) * (maxLines= 32)); 347 | numLines= 0; 348 | 349 | if (argc > 1) 350 | { 351 | batch= 1; 352 | while (argc-- > 1) 353 | load(*++argv); 354 | pc= 0; 355 | } 356 | 357 | while (!feof(stdin)) 358 | yyparse(); 359 | 360 | return 0; 361 | } 362 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/basic.ref: -------------------------------------------------------------------------------- 1 | 1 2 | 2 4 3 | 3 6 9 4 | 4 8 12 16 5 | 5 10 15 20 25 6 | 6 12 18 24 30 36 7 | 7 14 21 28 35 42 49 8 | 8 16 24 32 40 48 56 64 9 | 9 18 27 36 45 54 63 72 81 10 | 10 20 30 40 50 60 70 80 90 100 11 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/bench.bas: -------------------------------------------------------------------------------- 1 | 100 let n=100000 2 | 120 let m=0 3 | 110 let s=0 4 | 130 let m=m+1 5 | 140 let s=s+m 6 | 150 if m 3 | int vars[26]; 4 | %} 5 | 6 | Stmt = - e:Expr EOL { printf("%d\n", e); } 7 | | ( !EOL . )* EOL { printf("error\n"); } 8 | 9 | Expr = i:ID ASSIGN s:Sum { $$= vars[i]= s; } 10 | | s:Sum { $$= s; } 11 | 12 | Sum = l:Product 13 | ( PLUS r:Product { l += r; } 14 | | MINUS r:Product { l -= r; } 15 | )* { $$= l; } 16 | 17 | Product = l:Value 18 | ( TIMES r:Value { l *= r; } 19 | | DIVIDE r:Value { l /= r; } 20 | )* { $$= l; } 21 | 22 | Value = i:NUMBER { $$= atoi(yytext); } 23 | | i:ID !ASSIGN { $$= vars[i]; } 24 | | OPEN i:Expr CLOSE { $$= i; } 25 | 26 | NUMBER = < [0-9]+ > - { $$= atoi(yytext); } 27 | ID = < [a-z] > - { $$= yytext[0] - 'a'; } 28 | ASSIGN = '=' - 29 | PLUS = '+' - 30 | MINUS = '-' - 31 | TIMES = '*' - 32 | DIVIDE = '/' - 33 | OPEN = '(' - 34 | CLOSE = ')' - 35 | 36 | - = [ \t]* 37 | EOL = '\n' | '\r\n' | '\r' | ';' 38 | 39 | %% 40 | 41 | int main() 42 | { 43 | while (yyparse()); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/calc.ref: -------------------------------------------------------------------------------- 1 | 6 2 | 7 3 | 42 4 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/dc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int stack[1024]; 5 | int stackp= -1; 6 | 7 | int push(int n) { return stack[++stackp]= n; } 8 | int pop(void) { return stack[stackp--]; } 9 | 10 | #include "dc.peg.c" 11 | 12 | int main() 13 | { 14 | while (yyparse()); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/dc.peg: -------------------------------------------------------------------------------- 1 | # Grammar 2 | 3 | Expr <- SPACE Sum EOL { printf("%d\n", pop()); } 4 | / (!EOL .)* EOL { printf("error\n"); } 5 | 6 | Sum <- Product ( PLUS Product { int r= pop(), l= pop(); push(l + r); } 7 | / MINUS Product { int r= pop(), l= pop(); push(l - r); } 8 | )* 9 | 10 | Product <- Value ( TIMES Value { int r= pop(), l= pop(); push(l * r); } 11 | / DIVIDE Value { int r= pop(), l= pop(); push(l / r); } 12 | )* 13 | 14 | Value <- NUMBER { push(atoi(yytext)); } 15 | / OPEN Sum CLOSE 16 | 17 | # Lexemes 18 | 19 | NUMBER <- < [0-9]+ > SPACE 20 | PLUS <- '+' SPACE 21 | MINUS <- '-' SPACE 22 | TIMES <- '*' SPACE 23 | DIVIDE <- '/' SPACE 24 | OPEN <- '(' SPACE 25 | CLOSE <- ')' SPACE 26 | SPACE <- [ \t]* 27 | EOL <- '\n' / '\r\n' / '\r' 28 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/dc.ref: -------------------------------------------------------------------------------- 1 | 42 2 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/dcv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int stack[1024]; 5 | int stackp= -1; 6 | int var= 0; 7 | int vars[26]; 8 | 9 | int push(int n) { return stack[++stackp]= n; } 10 | int pop(void) { return stack[stackp--]; } 11 | int top(void) { return stack[stackp]; } 12 | 13 | #include "dcv.peg.c" 14 | 15 | int main() 16 | { 17 | while (yyparse()); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/dcv.peg: -------------------------------------------------------------------------------- 1 | # Grammar 2 | 3 | Stmt <- SPACE Expr EOL { printf("%d\n", pop()); } 4 | / (!EOL .)* EOL { printf("error\n"); } 5 | 6 | Expr <- ID { var= yytext[0] } ASSIGN Sum { vars[var - 'a']= top(); } 7 | / Sum 8 | 9 | Sum <- Product ( PLUS Product { int r= pop(), l= pop(); push(l + r); } 10 | / MINUS Product { int r= pop(), l= pop(); push(l - r); } 11 | )* 12 | 13 | Product <- Value ( TIMES Value { int r= pop(), l= pop(); push(l * r); } 14 | / DIVIDE Value { int r= pop(), l= pop(); push(l / r); } 15 | )* 16 | 17 | Value <- NUMBER { push(atoi(yytext)); } 18 | / < ID > !ASSIGN { push(vars[yytext[0] - 'a']); } 19 | / OPEN Expr CLOSE 20 | 21 | # Lexemes 22 | 23 | NUMBER <- < [0-9]+ > SPACE 24 | ID <- < [a-z] > SPACE 25 | ASSIGN <- '=' SPACE 26 | PLUS <- '+' SPACE 27 | MINUS <- '-' SPACE 28 | TIMES <- '*' SPACE 29 | DIVIDE <- '/' SPACE 30 | OPEN <- '(' SPACE 31 | CLOSE <- ')' SPACE 32 | 33 | SPACE <- [ \t]* 34 | EOL <- '\n' / '\r\n' / '\r' / ';' 35 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/dcv.ref: -------------------------------------------------------------------------------- 1 | 6 2 | 7 3 | 42 4 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/fibonacci.bas: -------------------------------------------------------------------------------- 1 | 100 let n=32 2 | 110 gosub 200 3 | 120 print "fibonacci(",n,") = ", m 4 | 130 end 5 | 6 | 200 let c=n 7 | 210 let b=1 8 | 220 if c<2 then goto 400 9 | 230 let c=c-1 10 | 240 let a=1 11 | 300 let c=c-1 12 | 310 let d=a+b 13 | 320 let a=b 14 | 330 let b=d+1 15 | 340 if c<>0 then goto 300 16 | 400 let m=b 17 | 410 return 18 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/left.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define YY_INPUT(buf, result, max) \ 4 | { \ 5 | int c= getchar(); \ 6 | result= (EOF == c) ? 0 : (*(buf)= c, 1); \ 7 | if (EOF != c) printf("<%c>\n", c); \ 8 | } 9 | 10 | #include "left.peg.c" 11 | 12 | int main() 13 | { 14 | printf(yyparse() ? "success\n" : "failure\n"); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/left.peg: -------------------------------------------------------------------------------- 1 | # Grammar 2 | 3 | S <- (S 'a' / 'a') !'a' 4 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/localctx.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define YY_CTX_LOCAL 4 | 5 | #include "test.peg.c" 6 | 7 | int main() 8 | { 9 | yycontext ctx; 10 | memset(&ctx, 0, sizeof(yycontext)); 11 | while (yyparse(&ctx)); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/localctx.ref: -------------------------------------------------------------------------------- 1 | a1 ab1 . 2 | a2 ac2 . 3 | a3 ad3 . 4 | a3 ae3 . 5 | a4 af4 afg4 . 6 | a4 af5 afh5 . 7 | a4 af4 afg4 . 8 | a4 af5 afh5 . 9 | af6 afi6 a6 . 10 | af6 af7 afj7 a6 . 11 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/rule.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "rule.peg.c" 5 | 6 | int main() 7 | { 8 | while (yyparse()); 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/rule.peg: -------------------------------------------------------------------------------- 1 | start <- abcd+ 2 | 3 | abcd <- 'a' { printf("A %d\n", yypos); } bc { printf("ABC %d\n", yypos); } 4 | / 'b' { printf("B %d\n", yypos); } cd { printf("BCD %d\n", yypos); } 5 | 6 | bc <- 'b' { printf("B %d\n", yypos); } 'c' { printf("C %d\n", yypos); } 7 | 8 | cd <- 'c' { printf("C %d\n", yypos); } 'd' { printf("D %d\n", yypos); } 9 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/rule.ref: -------------------------------------------------------------------------------- 1 | A 24 2 | B 24 3 | C 24 4 | ABC 24 5 | B 24 6 | C 24 7 | D 24 8 | BCD 24 9 | A 24 10 | B 24 11 | C 24 12 | ABC 24 13 | B 24 14 | C 24 15 | D 24 16 | BCD 24 17 | A 24 18 | B 24 19 | C 24 20 | ABC 24 21 | B 24 22 | C 24 23 | D 24 24 | BCD 24 25 | A 24 26 | B 24 27 | C 24 28 | ABC 24 29 | B 24 30 | C 24 31 | D 24 32 | BCD 24 33 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/test.bas: -------------------------------------------------------------------------------- 1 | 10 let i=1 2 | 20 gosub 100 3 | 30 let i=i+1 4 | 40 if i<=10 then goto 20 5 | 50 end 6 | 7 | 100 let j=1 8 | 110 print " ", i*j, 9 | 120 let j=j+1 10 | 130 if j<=i then goto 110 11 | 140 print 12 | 150 return 13 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test.peg.c" 3 | 4 | int main() 5 | { 6 | while (yyparse()); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/test.peg: -------------------------------------------------------------------------------- 1 | start <- body '.' { printf(".\n"); } 2 | 3 | body <- 'a' { printf("a1 "); } 'b' { printf("ab1 "); } 4 | 5 | / 'a' { printf("a2 "); } 'c' { printf("ac2 "); } 6 | 7 | / 'a' { printf("a3 "); } ( 'd' { printf("ad3 "); } / 'e' { printf("ae3 "); } ) 8 | 9 | / 'a' { printf("a4 "); } ( 'f' { printf("af4 "); } 'g' { printf("afg4 "); } 10 | / 'f' { printf("af5 "); } 'h' { printf("afh5 "); } ) 11 | 12 | / 'a' { printf("a6 "); } ( 'f' &{ printf("af6 ") } 'i' &{ printf("afi6 ") } 13 | / 'f' &{ printf("af7 ") } 'j' &{ printf("afj7 ") } ) 14 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/test.ref: -------------------------------------------------------------------------------- 1 | a1 ab1 . 2 | a2 ac2 . 3 | a3 ad3 . 4 | a3 ae3 . 5 | a4 af4 afg4 . 6 | a4 af5 afh5 . 7 | a4 af4 afg4 . 8 | a4 af5 afh5 . 9 | af6 afi6 a6 . 10 | af6 af7 afj7 a6 . 11 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/username.leg: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | start = "username" { printf("%s", getlogin()); } 6 | | < . > { putchar(yytext[0]); } 7 | 8 | %% 9 | 10 | int main() 11 | { 12 | while (yyparse()); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/wc.leg: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | int lines= 0, words= 0, chars= 0; 4 | %} 5 | 6 | start = (line | word | char) 7 | 8 | line = < (( '\n' '\r'* ) | ( '\r' '\n'* )) > { lines++; chars += yyleng; } 9 | word = < [a-zA-Z]+ > { words++; chars += yyleng; printf("<%s>\n", yytext); } 10 | char = . { chars++; } 11 | 12 | %% 13 | 14 | int main() 15 | { 16 | while (yyparse()) 17 | ; 18 | printf("%d lines\n", lines); 19 | printf("%d chars\n", chars); 20 | printf("%d words\n", words); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /peg-0.1.9/examples/wc.ref: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 22 lines 54 | 425 chars 55 | 52 words 56 | -------------------------------------------------------------------------------- /peg-0.1.9/leg.leg: -------------------------------------------------------------------------------- 1 | # LE Grammar for LE Grammars 2 | # 3 | # Copyright (c) 2007 by Ian Piumarta 4 | # All rights reserved. 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a 7 | # copy of this software and associated documentation files (the 'Software'), 8 | # to deal in the Software without restriction, including without limitation 9 | # the rights to use, copy, modify, merge, publish, distribute, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, provided that the above copyright notice(s) and this 12 | # permission notice appear in all copies of the Software. Acknowledgement 13 | # of the use of this Software in supporting documentation would be 14 | # appreciated but is not required. 15 | # 16 | # THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. 17 | # 18 | # Last edited: 2012-04-29 15:51:15 by piumarta on emilia 19 | 20 | %{ 21 | # include "tree.h" 22 | # include "version.h" 23 | 24 | # include 25 | # include 26 | # include 27 | # include 28 | # include 29 | # include 30 | 31 | typedef struct Header Header; 32 | 33 | struct Header { 34 | char *text; 35 | Header *next; 36 | }; 37 | 38 | FILE *input= 0; 39 | 40 | int verboseFlag= 0; 41 | 42 | static int lineNumber= 0; 43 | static char *fileName= 0; 44 | static char *trailer= 0; 45 | static Header *headers= 0; 46 | 47 | void makeHeader(char *text); 48 | void makeTrailer(char *text); 49 | 50 | void yyerror(char *message); 51 | 52 | # define YY_INPUT(buf, result, max) \ 53 | { \ 54 | int c= getc(input); \ 55 | if ('\n' == c || '\r' == c) ++lineNumber; \ 56 | result= (EOF == c) ? 0 : (*(buf)= c, 1); \ 57 | } 58 | 59 | # define YY_LOCAL(T) static T 60 | # define YY_RULE(T) static T 61 | %} 62 | 63 | # Hierarchical syntax 64 | 65 | grammar= - ( declaration | definition )+ trailer? end-of-file 66 | 67 | declaration= '%{' < ( !'%}' . )* > RPERCENT { makeHeader(yytext); } #{YYACCEPT} 68 | 69 | trailer= '%%' < .* > { makeTrailer(yytext); } #{YYACCEPT} 70 | 71 | definition= identifier { if (push(beginRule(findRule(yytext)))->rule.expression) 72 | fprintf(stderr, "rule '%s' redefined\n", yytext); } 73 | EQUAL expression { Node *e= pop(); Rule_setExpression(pop(), e); } 74 | SEMICOLON? #{YYACCEPT} 75 | 76 | expression= sequence (BAR sequence { Node *f= pop(); push(Alternate_append(pop(), f)); } 77 | )* 78 | 79 | sequence= prefix (prefix { Node *f= pop(); push(Sequence_append(pop(), f)); } 80 | )* 81 | 82 | prefix= AND action { push(makePredicate(yytext)); } 83 | | AND suffix { push(makePeekFor(pop())); } 84 | | NOT suffix { push(makePeekNot(pop())); } 85 | | suffix 86 | 87 | suffix= primary (QUESTION { push(makeQuery(pop())); } 88 | | STAR { push(makeStar (pop())); } 89 | | PLUS { push(makePlus (pop())); } 90 | )? 91 | 92 | primary= identifier { push(makeVariable(yytext)); } 93 | COLON identifier !EQUAL { Node *name= makeName(findRule(yytext)); name->name.variable= pop(); push(name); } 94 | | identifier !EQUAL { push(makeName(findRule(yytext))); } 95 | | OPEN expression CLOSE 96 | | literal { push(makeString(yytext)); } 97 | | class { push(makeClass(yytext)); } 98 | | DOT { push(makeDot()); } 99 | | action { push(makeAction(yytext)); } 100 | | BEGIN { push(makePredicate("YY_BEGIN")); } 101 | | END { push(makePredicate("YY_END")); } 102 | 103 | # Lexical syntax 104 | 105 | identifier= < [-a-zA-Z_][-a-zA-Z_0-9]* > - 106 | 107 | literal= ['] < ( !['] char )* > ['] - 108 | | ["] < ( !["] char )* > ["] - 109 | 110 | class= '[' < ( !']' range )* > ']' - 111 | 112 | range= char '-' char | char 113 | 114 | char= '\\' [-abefnrtv'"\[\]\\] 115 | | '\\' [0-3][0-7][0-7] 116 | | '\\' [0-7][0-7]? 117 | | !'\\' . 118 | 119 | action= '{' < braces* > '}' - 120 | 121 | braces= '{' braces* '}' 122 | | !'}' . 123 | 124 | EQUAL= '=' - 125 | COLON= ':' - 126 | SEMICOLON= ';' - 127 | BAR= '|' - 128 | AND= '&' - 129 | NOT= '!' - 130 | QUESTION= '?' - 131 | STAR= '*' - 132 | PLUS= '+' - 133 | OPEN= '(' - 134 | CLOSE= ')' - 135 | DOT= '.' - 136 | BEGIN= '<' - 137 | END= '>' - 138 | RPERCENT= '%}' - 139 | 140 | -= (space | comment)* 141 | space= ' ' | '\t' | end-of-line 142 | comment= '#' (!end-of-line .)* end-of-line 143 | end-of-line= '\r\n' | '\n' | '\r' 144 | end-of-file= !. 145 | 146 | %% 147 | 148 | void yyerror(char *message) 149 | { 150 | fprintf(stderr, "%s:%d: %s", fileName, lineNumber, message); 151 | if (yyctx->text[0]) fprintf(stderr, " near token '%s'", yyctx->text); 152 | if (yyctx->pos < yyctx->limit || !feof(input)) 153 | { 154 | yyctx->buf[yyctx->limit]= '\0'; 155 | fprintf(stderr, " before text \""); 156 | while (yyctx->pos < yyctx->limit) 157 | { 158 | if ('\n' == yyctx->buf[yyctx->pos] || '\r' == yyctx->buf[yyctx->pos]) break; 159 | fputc(yyctx->buf[yyctx->pos++], stderr); 160 | } 161 | if (yyctx->pos == yyctx->limit) 162 | { 163 | int c; 164 | while (EOF != (c= fgetc(input)) && '\n' != c && '\r' != c) 165 | fputc(c, stderr); 166 | } 167 | fputc('\"', stderr); 168 | } 169 | fprintf(stderr, "\n"); 170 | exit(1); 171 | } 172 | 173 | void makeHeader(char *text) 174 | { 175 | Header *header= (Header *)malloc(sizeof(Header)); 176 | header->text= strdup(text); 177 | header->next= headers; 178 | headers= header; 179 | } 180 | 181 | void makeTrailer(char *text) 182 | { 183 | trailer= strdup(text); 184 | } 185 | 186 | static void version(char *name) 187 | { 188 | printf("%s version %d.%d.%d\n", name, PEG_MAJOR, PEG_MINOR, PEG_LEVEL); 189 | } 190 | 191 | static void usage(char *name) 192 | { 193 | version(name); 194 | fprintf(stderr, "usage: %s [