From 1109430680601b8356bac5f37c9a4a1e501b6fba Mon Sep 17 00:00:00 2001 From: Matthew Brush Date: Sun, 15 Jul 2012 05:47:31 -0700 Subject: [PATCH] markdown: Initial commit No Waf build system yet. --- Makefile.am | 4 + build/markdown.m4 | 24 + configure.ac | 1 + markdown/AUTHORS | 1 + markdown/COPYING | 339 +++++ markdown/ChangeLog | 0 markdown/Makefile.am | 4 + markdown/NEWS | 0 markdown/README | 1 + markdown/discount/COPYRIGHT | 47 + markdown/discount/CREDITS | 35 + markdown/discount/Csio.c | 61 + markdown/discount/Makefile.am | 31 + markdown/discount/amalloc.c | 111 ++ markdown/discount/amalloc.h | 29 + markdown/discount/basename.c | 43 + markdown/discount/blocktags | 33 + markdown/discount/config.h | 35 + markdown/discount/css.c | 85 ++ markdown/discount/cstring.h | 77 + markdown/discount/discount-changes.patch | 961 ++++++++++++ markdown/discount/docheader.c | 49 + markdown/discount/dumptree.c | 152 ++ markdown/discount/emmatch.c | 188 +++ markdown/discount/flags.c | 84 ++ markdown/discount/generate.c | 1762 ++++++++++++++++++++++ markdown/discount/html5.c | 22 + markdown/discount/markdown.c | 1302 ++++++++++++++++ markdown/discount/markdown.h | 189 +++ markdown/discount/mkdio.c | 357 +++++ markdown/discount/mkdio.h | 111 ++ markdown/discount/resource.c | 157 ++ markdown/discount/setup.c | 39 + markdown/discount/tags.c | 91 ++ markdown/discount/tags.h | 19 + markdown/discount/toc.c | 114 ++ markdown/discount/version.c | 30 + markdown/discount/xml.c | 82 + markdown/discount/xmlpage.c | 48 + markdown/docs/Makefile.am | 2 + markdown/docs/README.md | 55 + markdown/src/Makefile.am | 33 + markdown/src/conf.c | 177 +++ markdown/src/conf.h | 52 + markdown/src/md.c | 46 + markdown/src/md.h | 33 + markdown/src/plugin.c | 362 +++++ markdown/src/tmpl.c | 143 ++ markdown/src/tmpl.h | 51 + markdown/src/tmplmgr.c | 149 ++ markdown/src/tmplmgr.h | 40 + markdown/src/viewer.c | 141 ++ markdown/src/viewer.h | 48 + markdown/templates/Alternate/Makefile.am | 3 + markdown/templates/Alternate/index.html | 22 + markdown/templates/Default/Makefile.am | 3 + markdown/templates/Default/index.html | 5 + markdown/templates/Makefile.am | 1 + 58 files changed, 8084 insertions(+) create mode 100644 build/markdown.m4 create mode 100644 markdown/AUTHORS create mode 100644 markdown/COPYING create mode 100644 markdown/ChangeLog create mode 100644 markdown/Makefile.am create mode 100644 markdown/NEWS create mode 100644 markdown/README create mode 100644 markdown/discount/COPYRIGHT create mode 100644 markdown/discount/CREDITS create mode 100644 markdown/discount/Csio.c create mode 100644 markdown/discount/Makefile.am create mode 100644 markdown/discount/amalloc.c create mode 100644 markdown/discount/amalloc.h create mode 100644 markdown/discount/basename.c create mode 100644 markdown/discount/blocktags create mode 100644 markdown/discount/config.h create mode 100644 markdown/discount/css.c create mode 100644 markdown/discount/cstring.h create mode 100644 markdown/discount/discount-changes.patch create mode 100644 markdown/discount/docheader.c create mode 100644 markdown/discount/dumptree.c create mode 100644 markdown/discount/emmatch.c create mode 100644 markdown/discount/flags.c create mode 100644 markdown/discount/generate.c create mode 100644 markdown/discount/html5.c create mode 100644 markdown/discount/markdown.c create mode 100644 markdown/discount/markdown.h create mode 100644 markdown/discount/mkdio.c create mode 100644 markdown/discount/mkdio.h create mode 100644 markdown/discount/resource.c create mode 100644 markdown/discount/setup.c create mode 100644 markdown/discount/tags.c create mode 100644 markdown/discount/tags.h create mode 100644 markdown/discount/toc.c create mode 100644 markdown/discount/version.c create mode 100644 markdown/discount/xml.c create mode 100644 markdown/discount/xmlpage.c create mode 100644 markdown/docs/Makefile.am create mode 100644 markdown/docs/README.md create mode 100644 markdown/src/Makefile.am create mode 100644 markdown/src/conf.c create mode 100644 markdown/src/conf.h create mode 100644 markdown/src/md.c create mode 100644 markdown/src/md.h create mode 100644 markdown/src/plugin.c create mode 100644 markdown/src/tmpl.c create mode 100644 markdown/src/tmpl.h create mode 100644 markdown/src/tmplmgr.c create mode 100644 markdown/src/tmplmgr.h create mode 100644 markdown/src/viewer.c create mode 100644 markdown/src/viewer.h create mode 100644 markdown/templates/Alternate/Makefile.am create mode 100644 markdown/templates/Alternate/index.html create mode 100644 markdown/templates/Default/Makefile.am create mode 100644 markdown/templates/Default/index.html create mode 100644 markdown/templates/Makefile.am diff --git a/Makefile.am b/Makefile.am index e70b474ba..6060c1c7f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -86,6 +86,10 @@ if ENABLE_GPROJECT SUBDIRS += gproject endif +if ENABLE_MARKDOWN +SUBDIRS += markdown +endif + if ENABLE_MULTITERM SUBDIRS += multiterm endif diff --git a/build/markdown.m4 b/build/markdown.m4 new file mode 100644 index 000000000..3b5f9fb7a --- /dev/null +++ b/build/markdown.m4 @@ -0,0 +1,24 @@ +AC_DEFUN([GP_CHECK_MARKDOWN], +[ + GP_ARG_DISABLE([markdown], [auto]) + + GTK_VERSION=2.16 + WEBKIT_VERSION=1.1.13 + + GP_CHECK_PLUGIN_DEPS([markdown], [MARKDOWN], + [gtk+-2.0 >= ${GTK_VERSION} + webkit-1.0 >= ${WEBKIT_VERSION} + gthread-2.0]) + + GP_STATUS_PLUGIN_ADD([Markdown], [$enable_markdown]) + + AC_CONFIG_FILES([ + markdown/Makefile + markdown/discount/Makefile + markdown/src/Makefile + markdown/templates/Makefile + markdown/templates/Default/Makefile + markdown/templates/Alternate/Makefile + markdown/docs/Makefile + ]) +]) diff --git a/configure.ac b/configure.ac index a728cfa12..2037337c2 100644 --- a/configure.ac +++ b/configure.ac @@ -45,6 +45,7 @@ GP_CHECK_GEANYVC GP_CHECK_GEANYPG GP_CHECK_GENIUSPASTE GP_CHECK_GPROJECT +GP_CHECK_MARKDOWN GP_CHECK_MULTITERM GP_CHECK_PRETTYPRINTER GP_CHECK_SHIFTCOLUMN diff --git a/markdown/AUTHORS b/markdown/AUTHORS new file mode 100644 index 000000000..6eba690e6 --- /dev/null +++ b/markdown/AUTHORS @@ -0,0 +1 @@ +Matthew Brush diff --git a/markdown/COPYING b/markdown/COPYING new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/markdown/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/markdown/ChangeLog b/markdown/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/markdown/Makefile.am b/markdown/Makefile.am new file mode 100644 index 000000000..d9c691f18 --- /dev/null +++ b/markdown/Makefile.am @@ -0,0 +1,4 @@ +include $(top_srcdir)/build/vars.auxfiles.mk + +SUBDIRS = discount src templates docs +plugin = markdown diff --git a/markdown/NEWS b/markdown/NEWS new file mode 100644 index 000000000..e69de29bb diff --git a/markdown/README b/markdown/README new file mode 100644 index 000000000..94b178ee1 --- /dev/null +++ b/markdown/README @@ -0,0 +1 @@ +See the ``docs/README.md`` file for more information. diff --git a/markdown/discount/COPYRIGHT b/markdown/discount/COPYRIGHT new file mode 100644 index 000000000..0cf98208a --- /dev/null +++ b/markdown/discount/COPYRIGHT @@ -0,0 +1,47 @@ +->Copyright (C) 2007 David Loren Parsons. +All rights reserved.<- + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicence, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution, and in the same place and form as other + copyright, license and disclaimer information. + + 3. The end-user documentation included with the redistribution, if + any, must include the following acknowledgment: + + This product includes software developed by + David Loren Parsons + + in the same place and form as other third-party acknowledgments. + Alternately, this acknowledgment may appear in the software + itself, in the same form and location as other such third-party + acknowledgments. + + 4. Except as contained in this notice, the name of David Loren + Parsons shall not be used in advertising or otherwise to promote + the sale, use or other dealings in this Software without prior + written authorization from David Loren Parsons. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL DAVID LOREN PARSONS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/markdown/discount/CREDITS b/markdown/discount/CREDITS new file mode 100644 index 000000000..2014bc5b8 --- /dev/null +++ b/markdown/discount/CREDITS @@ -0,0 +1,35 @@ +Discount is primarily my work, but it has only reached the point +where it is via contributions, critiques, and bug reports from a +host of other people, some of which are listed before. If your +name isn't on this list, please remind me + -david parsons (orc@pell.chi.il.us) + + +Josh Wood -- Plan9 support. +Mike Schiraldi -- Reddit style automatic links, MANY MANY MANY + bug reports about boundary conditions and + places where I didn't get it right. +Jjgod Jiang -- Table of contents support. +Petite Abeille -- Many bug reports about places where I didn't + get it right. +Tim Channon -- inspiration for the `mkd_xhtmlpage()` function +Christian Herenz-- Many bug reports regarding my implementation of + `[]()` and `![]()` +A.S.Bradbury -- Portability bug reports for 64 bit systems. +Joyent -- Loan of a solaris box so I could get discount + working under solaris. +Ryan Tomayko -- Portability requests (and the rdiscount ruby + binding.) +yidabu -- feedback on the documentation, bug reports + against utf-8 support. +Pierre Joye -- bug reports, php discount binding. +Masayoshi Sekimura- perl discount binding. +Jeremy Hinegardner- bug reports about list handling. +Andrew White -- bug reports about the format of generated urls. +Steve Huff -- bug reports about Makefile portability (for Fink) +Ignacio Burgue?o-- bug reports about `>%class%` +Henrik Nyh -- bug reports about embedded html handling. +John J. Foerch -- bug reports about incorrect `–` and `—` + translations. + + diff --git a/markdown/discount/Csio.c b/markdown/discount/Csio.c new file mode 100644 index 000000000..4358b3338 --- /dev/null +++ b/markdown/discount/Csio.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include "cstring.h" +#include "markdown.h" +#include "amalloc.h" + + +/* putc() into a cstring + */ +void +Csputc(int c, Cstring *iot) +{ + EXPAND(*iot) = c; +} + + +/* printf() into a cstring + */ +int +Csprintf(Cstring *iot, char *fmt, ...) +{ + va_list ptr; + int siz=100; + + do { + RESERVE(*iot, siz); + va_start(ptr, fmt); + siz = vsnprintf(T(*iot)+S(*iot), ALLOCATED(*iot)-S(*iot), fmt, ptr); + va_end(ptr); + } while ( siz > (ALLOCATED(*iot)-S(*iot)) ); + + S(*iot) += siz; + return siz; +} + + +/* write() into a cstring + */ +int +Cswrite(Cstring *iot, char *bfr, int size) +{ + RESERVE(*iot, size); + memcpy(T(*iot)+S(*iot), bfr, size); + S(*iot) += size; + return size; +} + + +/* reparse() into a cstring + */ +void +Csreparse(Cstring *iot, char *buf, int size, int flags) +{ + MMIOT f; + ___mkd_initmmiot(&f, 0); + ___mkd_reparse(buf, size, 0, &f); + ___mkd_emblock(&f); + SUFFIX(*iot, T(f.out), S(f.out)); + ___mkd_freemmiot(&f, 0); +} diff --git a/markdown/discount/Makefile.am b/markdown/discount/Makefile.am new file mode 100644 index 000000000..b70f3a570 --- /dev/null +++ b/markdown/discount/Makefile.am @@ -0,0 +1,31 @@ +noinst_LTLIBRARIES = libdiscount.la + +libdiscount_la_SOURCES = \ + amalloc.c \ + amalloc.h \ + basename.c \ + config.h \ + Csio.c \ + css.c \ + cstring.h \ + docheader.c \ + dumptree.c \ + emmatch.c \ + flags.c \ + generate.c \ + html5.c \ + markdown.c \ + markdown.h \ + mkdio.c \ + mkdio.h \ + resource.c \ + setup.c \ + tags.c \ + tags.h \ + toc.c \ + version.c \ + xml.c \ + xmlpage.c + +libdiscount_la_CPPFLAGS = @MARKDOWN_CFLAGS@ +libdiscount_la_LIBADD = @MARKDOWN_LIBS@ diff --git a/markdown/discount/amalloc.c b/markdown/discount/amalloc.c new file mode 100644 index 000000000..bb20ab671 --- /dev/null +++ b/markdown/discount/amalloc.c @@ -0,0 +1,111 @@ +/* + * debugging malloc()/realloc()/calloc()/free() that attempts + * to keep track of just what's been allocated today. + */ + +#include +#include + +#define MAGIC 0x1f2e3d4c + +struct alist { int magic, size; struct alist *next, *last; }; + +static struct alist list = { 0, 0, 0, 0 }; + +static int mallocs=0; +static int reallocs=0; +static int frees=0; + +void * +acalloc(int size, int count) +{ + struct alist *ret = calloc(size + sizeof(struct alist), count); + + if ( ret ) { + ret->magic = MAGIC; + ret->size = size * count; + if ( list.next ) { + ret->next = list.next; + ret->last = &list; + ret->next->last = ret; + list.next = ret; + } + else { + ret->last = ret->next = &list; + list.next = list.last = ret; + } + ++mallocs; + return ret+1; + } + return 0; +} + + +void* +amalloc(int size) +{ + return acalloc(size,1); +} + + +void +afree(void *ptr) +{ + struct alist *p2 = ((struct alist*)ptr)-1; + + if ( p2->magic == MAGIC ) { + p2->last->next = p2->next; + p2->next->last = p2->last; + ++frees; + free(p2); + } + else + free(ptr); +} + + +void * +arealloc(void *ptr, int size) +{ + struct alist *p2 = ((struct alist*)ptr)-1; + struct alist save; + + if ( p2->magic == MAGIC ) { + save.next = p2->next; + save.last = p2->last; + p2 = realloc(p2, sizeof(*p2) + size); + + if ( p2 ) { + p2->size = size; + p2->next->last = p2; + p2->last->next = p2; + ++reallocs; + return p2+1; + } + else { + save.next->last = save.last; + save.last->next = save.next; + return 0; + } + } + return realloc(ptr, size); +} + + +void +adump() +{ + struct alist *p; + + + for ( p = list.next; p && (p != &list); p = p->next ) { + fprintf(stderr, "allocated: %d byte%s\n", p->size, (p->size==1) ? "" : "s"); + fprintf(stderr, " [%.*s]\n", p->size, (char*)(p+1)); + } + + if ( getenv("AMALLOC_STATISTICS") ) { + fprintf(stderr, "%d malloc%s\n", mallocs, (mallocs==1)?"":"s"); + fprintf(stderr, "%d realloc%s\n", reallocs, (reallocs==1)?"":"s"); + fprintf(stderr, "%d free%s\n", frees, (frees==1)?"":"s"); + } +} diff --git a/markdown/discount/amalloc.h b/markdown/discount/amalloc.h new file mode 100644 index 000000000..43ca98586 --- /dev/null +++ b/markdown/discount/amalloc.h @@ -0,0 +1,29 @@ +/* + * debugging malloc()/realloc()/calloc()/free() that attempts + * to keep track of just what's been allocated today. + */ +#ifndef AMALLOC_D +#define AMALLOC_D + +#include "config.h" + +#ifdef USE_AMALLOC + +extern void *amalloc(int); +extern void *acalloc(int,int); +extern void *arealloc(void*,int); +extern void afree(void*); +extern void adump(); + +#define malloc amalloc +#define calloc acalloc +#define realloc arealloc +#define free afree + +#else + +#define adump() (void)1 + +#endif + +#endif/*AMALLOC_D*/ diff --git a/markdown/discount/basename.c b/markdown/discount/basename.c new file mode 100644 index 000000000..237022a20 --- /dev/null +++ b/markdown/discount/basename.c @@ -0,0 +1,43 @@ +/* + * mkdio -- markdown front end input functions + * + * Copyright (C) 2007 David L Parsons. + * The redistribution terms are provided in the COPYRIGHT file that must + * be distributed with this source code. + */ +#include "config.h" +#include +#include +#include + +#include "mkdio.h" +#include "cstring.h" +#include "amalloc.h" + +static char * +e_basename(const char *string, const int size, void *context) +{ + char *ret; + char *base = (char*)context; + + if ( base && string && (*string == '/') && (ret=malloc(strlen(base)+size+2)) ) { + strcpy(ret, base); + strncat(ret, string, size); + return ret; + } + return 0; +} + +static void +e_free(char *string, void *context) +{ + if ( string ) free(string); +} + +void +mkd_basename(MMIOT *document, char *base) +{ + mkd_e_url(document, e_basename); + mkd_e_data(document, base); + mkd_e_free(document, e_free); +} diff --git a/markdown/discount/blocktags b/markdown/discount/blocktags new file mode 100644 index 000000000..e7bdf7386 --- /dev/null +++ b/markdown/discount/blocktags @@ -0,0 +1,33 @@ +static struct kw blocktags[] = { + { "P", 1, 0 }, + { "DL", 2, 0 }, + { "H1", 2, 0 }, + { "H2", 2, 0 }, + { "H3", 2, 0 }, + { "H4", 2, 0 }, + { "H5", 2, 0 }, + { "H6", 2, 0 }, + { "HR", 2, 1 }, + { "OL", 2, 0 }, + { "UL", 2, 0 }, + { "BDO", 3, 0 }, + { "DFN", 3, 0 }, + { "DIV", 3, 0 }, + { "MAP", 3, 0 }, + { "PRE", 3, 0 }, + { "WBR", 3, 0 }, + { "XMP", 3, 0 }, + { "NOBR", 4, 0 }, + { "STYLE", 5, 0 }, + { "TABLE", 5, 0 }, + { "CENTER", 6, 0 }, + { "IFRAME", 6, 0 }, + { "OBJECT", 6, 0 }, + { "SCRIPT", 6, 0 }, + { "ADDRESS", 7, 0 }, + { "LISTING", 7, 0 }, + { "PLAINTEXT", 9, 0 }, + { "BLOCKQUOTE", 10, 0 }, +}; + +#define NR_blocktags 29 diff --git a/markdown/discount/config.h b/markdown/discount/config.h new file mode 100644 index 000000000..da2c2921b --- /dev/null +++ b/markdown/discount/config.h @@ -0,0 +1,35 @@ +/* + * In the upstream Discount tree, this file is auto-generated, for the + * Geany plugin it's not. + */ +#ifndef DISCOUNT_CONFIG_H +#define DISCOUNT_CONFIG_H 1 + +#include + +G_BEGIN_DECLS + +#define OS_LINUX G_OS_UNIX +#define USE_DISCOUNT_DL 0 +#define DWORD guint32 +#define WORD guint16 +#define BYTE guint8 +#define HAVE_BASENAME 0 +#define HAVE_LIBGEN_H 0 +#define HAVE_PWD_H 0 +#define HAVE_GETPWUID 0 +#define HAVE_SRANDOM 0 +#define INITRNG(x) srandom((unsigned int)x) +#define HAVE_BZERO 0 +#define HAVE_RANDOM 0 +#define COINTOSS() (random()&1) +#define HAVE_STRCASECMP 0 +#define HAVE_STRNCASECMP 0 +#define HAVE_FCHDIR 0 +#define TABSTOP 4 +#define HAVE_MALLOC_H 0 +#define VERSION "2.1.3" + +G_END_DECLS + +#endif /* DISCOUNT_CONFIG_H */ diff --git a/markdown/discount/css.c b/markdown/discount/css.c new file mode 100644 index 000000000..3eb30b34f --- /dev/null +++ b/markdown/discount/css.c @@ -0,0 +1,85 @@ +/* markdown: a C implementation of John Gruber's Markdown markup language. + * + * Copyright (C) 2009 David L Parsons. + * The redistribution terms are provided in the COPYRIGHT file that must + * be distributed with this source code. + */ +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#include "cstring.h" +#include "markdown.h" +#include "amalloc.h" + + +/* + * dump out stylesheet sections. + */ +static void +stylesheets(Paragraph *p, Cstring *f) +{ + Line* q; + + for ( ; p ; p = p->next ) { + if ( p->typ == STYLE ) { + for ( q = p->text; q ; q = q->next ) { + Cswrite(f, T(q->text), S(q->text)); + Csputc('\n', f); + } + } + if ( p->down ) + stylesheets(p->down, f); + } +} + + +/* dump any embedded styles to a string + */ +int +mkd_css(Document *d, char **res) +{ + Cstring f; + int size; + + if ( res && d && d->compiled ) { + *res = 0; + CREATE(f); + RESERVE(f, 100); + stylesheets(d->code, &f); + + if ( (size = S(f)) > 0 ) { + EXPAND(f) = 0; + /* HACK ALERT! HACK ALERT! HACK ALERT! */ + *res = T(f);/* we know that a T(Cstring) is a character pointer */ + /* so we can simply pick it up and carry it away, */ + /* leaving the husk of the Ctring on the stack */ + /* END HACK ALERT */ + } + else + DELETE(f); + return size; + } + return EOF; +} + + +/* dump any embedded styles to a file + */ +int +mkd_generatecss(Document *d, FILE *f) +{ + char *res; + int written = EOF, size = mkd_css(d, &res); + + if ( size > 0 ) + written = fwrite(res, 1, size, f); + if ( res ) + free(res); + return (written == size) ? size : EOF; +} diff --git a/markdown/discount/cstring.h b/markdown/discount/cstring.h new file mode 100644 index 000000000..f31e10370 --- /dev/null +++ b/markdown/discount/cstring.h @@ -0,0 +1,77 @@ +/* two template types: STRING(t) which defines a pascal-style string + * of element (t) [STRING(char) is the closest to the pascal string], + * and ANCHOR(t) which defines a baseplate that a linked list can be + * built up from. [The linked list /must/ contain a ->next pointer + * for linking the list together with.] + */ +#ifndef _CSTRING_D +#define _CSTRING_D + +#include +#include + +#ifndef __WITHOUT_AMALLOC +# include "amalloc.h" +#endif + +/* expandable Pascal-style string. + */ +#define STRING(type) struct { type *text; int size, alloc; } + +#define CREATE(x) ( (T(x) = (void*)0), (S(x) = (x).alloc = 0) ) +#define EXPAND(x) (S(x)++)[(S(x) < (x).alloc) \ + ? (T(x)) \ + : (T(x) = T(x) ? realloc(T(x), sizeof T(x)[0] * ((x).alloc += 100)) \ + : malloc(sizeof T(x)[0] * ((x).alloc += 100)) )] + +#define DELETE(x) ALLOCATED(x) ? (free(T(x)), S(x) = (x).alloc = 0) \ + : ( S(x) = 0 ) +#define CLIP(t,i,sz) \ + ( ((i) >= 0) && ((sz) > 0) && (((i)+(sz)) <= S(t)) ) ? \ + (memmove(&T(t)[i], &T(t)[i+sz], (S(t)-(i+sz)+1)*sizeof(T(t)[0])), \ + S(t) -= (sz)) : -1 + +#define RESERVE(x, sz) T(x) = ((x).alloc > S(x) + (sz) \ + ? T(x) \ + : T(x) \ + ? realloc(T(x), sizeof T(x)[0] * ((x).alloc = 100+(sz)+S(x))) \ + : malloc(sizeof T(x)[0] * ((x).alloc = 100+(sz)+S(x)))) +#define SUFFIX(t,p,sz) \ + memcpy(((S(t) += (sz)) - (sz)) + \ + (T(t) = T(t) ? realloc(T(t), sizeof T(t)[0] * ((t).alloc += sz)) \ + : malloc(sizeof T(t)[0] * ((t).alloc += sz))), \ + (p), sizeof(T(t)[0])*(sz)) + +#define MDPREFIX(t,p,sz) \ + RESERVE( (t), (sz) ); \ + if ( S(t) ) { memmove(T(t)+(sz), T(t), S(t)); } \ + memcpy( T(t), (p), (sz) ); \ + S(t) += (sz) + +/* reference-style links (and images) are stored in an array + */ +#define T(x) (x).text +#define S(x) (x).size +#define ALLOCATED(x) (x).alloc + +/* abstract anchor type that defines a list base + * with a function that attaches an element to + * the end of the list. + * + * the list base field is named .text so that the T() + * macro will work with it. + */ +#define ANCHOR(t) struct { t *text, *end; } +#define E(t) ((t).end) + +#define ATTACH(t, p) ( T(t) ? ( (E(t)->next = (p)), (E(t) = (p)) ) \ + : ( (T(t) = E(t) = (p)) ) ) + +typedef STRING(char) Cstring; + +extern void Csputc(int, Cstring *); +extern int Csprintf(Cstring *, char *, ...); +extern int Cswrite(Cstring *, char *, int); +extern void Csreparse(Cstring *, char *, int, int); + +#endif/*_CSTRING_D*/ diff --git a/markdown/discount/discount-changes.patch b/markdown/discount/discount-changes.patch new file mode 100644 index 000000000..11bcc9583 --- /dev/null +++ b/markdown/discount/discount-changes.patch @@ -0,0 +1,961 @@ +Only in discount/: blocktags +Only in discount/: config.h +Only in discount-2.1.3/: configure.inc +Only in discount-2.1.3/: configure.sh +Only in discount/: .deps +Only in discount-2.1.3/: INSTALL +Only in discount-2.1.3/: main.c +Only in discount/: Makefile +Only in discount/: Makefile.am +diff -u discount-2.1.3/Makefile.in discount/Makefile.in +--- discount-2.1.3/Makefile.in 2012-01-16 13:08:52.000000000 -0800 ++++ discount/Makefile.in 2012-07-14 17:18:03.592754692 -0700 +@@ -1,138 +1,793 @@ +-CC=@CC@ -I. -L. +-CFLAGS=@CFLAGS@ +-AR=@AR@ +-RANLIB=@RANLIB@ +- +-BINDIR=@exedir@ +-MANDIR=@mandir@ +-LIBDIR=@libdir@ +-INCDIR=@prefix@/include +- +-PGMS=markdown +-SAMPLE_PGMS=mkd2html makepage +-@THEME@SAMPLE_PGMS+= theme +-MKDLIB=libmarkdown +-OBJS=mkdio.o markdown.o dumptree.o generate.o \ +- resource.o docheader.o version.o toc.o css.o \ +- xml.o Csio.o xmlpage.o basename.o emmatch.o \ +- setup.o tags.o html5.o flags.o @AMALLOC@ +-TESTFRAMEWORK=echo cols +- +-MAN3PAGES=mkd-callbacks.3 mkd-functions.3 markdown.3 mkd-line.3 +- +-all: $(PGMS) $(SAMPLE_PGMS) $(TESTFRAMEWORK) +- +-install: $(PGMS) $(DESTDIR)$(BINDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(INCDIR) +- @INSTALL_PROGRAM@ $(PGMS) $(DESTDIR)$(BINDIR) +- ./librarian.sh install libmarkdown VERSION $(DESTDIR)$(LIBDIR) +- @INSTALL_DATA@ mkdio.h $(DESTDIR)$(INCDIR) +- +-install.everything: install install.samples install.man +- +-install.samples: $(SAMPLE_PGMS) install $(DESTDIR)$(BINDIR) +- @INSTALL_PROGRAM@ $(SAMPLE_PGMS) $(DESTDIR)$(BINDIR) +- @INSTALL_DIR@ $(DESTDIR)$(MANDIR)/man1 +- @INSTALL_DATA@ theme.1 makepage.1 mkd2html.1 $(DESTDIR)$(MANDIR)/man1 +- +-install.man: +- @INSTALL_DIR@ $(DESTDIR)$(MANDIR)/man3 +- @INSTALL_DATA@ $(MAN3PAGES) $(DESTDIR)$(MANDIR)/man3 +- for x in mkd_line mkd_generateline; do \ +- ( echo '.\"' ; echo ".so man3/mkd-line.3" ) > $(DESTDIR)$(MANDIR)/man3/$$x.3;\ +- done +- for x in mkd_in mkd_string; do \ +- ( echo '.\"' ; echo ".so man3/markdown.3" ) > $(DESTDIR)$(MANDIR)/man3/$$x.3;\ ++# Makefile.in generated by automake 1.11.3 from Makefile.am. ++# @configure_input@ ++ ++# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, ++# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software ++# Foundation, Inc. ++# This Makefile.in is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY, to the extent permitted by law; without ++# even the implied warranty of MERCHANTABILITY or FITNESS FOR A ++# PARTICULAR PURPOSE. ++ ++@SET_MAKE@ ++ ++VPATH = @srcdir@ ++pkgdatadir = $(datadir)/@PACKAGE@ ++pkgincludedir = $(includedir)/@PACKAGE@ ++pkglibdir = $(libdir)/@PACKAGE@ ++pkglibexecdir = $(libexecdir)/@PACKAGE@ ++am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd ++install_sh_DATA = $(install_sh) -c -m 644 ++install_sh_PROGRAM = $(install_sh) -c ++install_sh_SCRIPT = $(install_sh) -c ++INSTALL_HEADER = $(INSTALL_DATA) ++transform = $(program_transform_name) ++NORMAL_INSTALL = : ++PRE_INSTALL = : ++POST_INSTALL = : ++NORMAL_UNINSTALL = : ++PRE_UNINSTALL = : ++POST_UNINSTALL = : ++build_triplet = @build@ ++host_triplet = @host@ ++subdir = markdown/discount ++DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ++ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ++am__aclocal_m4_deps = $(top_srcdir)/build/bundled/gpgme.m4 \ ++ $(top_srcdir)/build/addons.m4 $(top_srcdir)/build/cflags.m4 \ ++ $(top_srcdir)/build/codenav.m4 $(top_srcdir)/build/common.m4 \ ++ $(top_srcdir)/build/cppcheck.m4 \ ++ $(top_srcdir)/build/debugger.m4 $(top_srcdir)/build/devhelp.m4 \ ++ $(top_srcdir)/build/expansions.m4 $(top_srcdir)/build/geany.m4 \ ++ $(top_srcdir)/build/geanydoc.m4 \ ++ $(top_srcdir)/build/geanyextrasel.m4 \ ++ $(top_srcdir)/build/geanygdb.m4 \ ++ $(top_srcdir)/build/geanygendoc.m4 \ ++ $(top_srcdir)/build/geanyinsertnum.m4 \ ++ $(top_srcdir)/build/geanylatex.m4 \ ++ $(top_srcdir)/build/geanylipsum.m4 \ ++ $(top_srcdir)/build/geanylua.m4 \ ++ $(top_srcdir)/build/geanymacro.m4 \ ++ $(top_srcdir)/build/geanyminiscript.m4 \ ++ $(top_srcdir)/build/geanynumberedbookmarks.m4 \ ++ $(top_srcdir)/build/geanypg.m4 $(top_srcdir)/build/geanyprj.m4 \ ++ $(top_srcdir)/build/geanysendmail.m4 \ ++ $(top_srcdir)/build/geanyvc.m4 \ ++ $(top_srcdir)/build/geniuspaste.m4 \ ++ $(top_srcdir)/build/gproject.m4 $(top_srcdir)/build/i18n.m4 \ ++ $(top_srcdir)/build/markdown.m4 \ ++ $(top_srcdir)/build/multiterm.m4 \ ++ $(top_srcdir)/build/pretty-printer.m4 \ ++ $(top_srcdir)/build/shiftcolumn.m4 \ ++ $(top_srcdir)/build/spellcheck.m4 \ ++ $(top_srcdir)/build/status.m4 \ ++ $(top_srcdir)/build/tableconvert.m4 \ ++ $(top_srcdir)/build/treebrowser.m4 \ ++ $(top_srcdir)/build/unittests.m4 \ ++ $(top_srcdir)/build/updatechecker.m4 \ ++ $(top_srcdir)/build/webhelper.m4 \ ++ $(top_srcdir)/build/xmlsnippets.m4 \ ++ $(top_srcdir)/build/cache/glib-gettext.m4 \ ++ $(top_srcdir)/build/cache/intltool.m4 \ ++ $(top_srcdir)/build/cache/libtool.m4 \ ++ $(top_srcdir)/build/cache/ltoptions.m4 \ ++ $(top_srcdir)/build/cache/ltsugar.m4 \ ++ $(top_srcdir)/build/cache/ltversion.m4 \ ++ $(top_srcdir)/build/cache/lt~obsolete.m4 \ ++ $(top_srcdir)/build/cache/nls.m4 \ ++ $(top_srcdir)/build/cache/pkg.m4 $(top_srcdir)/configure.ac ++am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ ++ $(ACLOCAL_M4) ++mkinstalldirs = $(install_sh) -d ++CONFIG_HEADER = $(top_builddir)/config.h ++CONFIG_CLEAN_FILES = ++CONFIG_CLEAN_VPATH_FILES = ++LTLIBRARIES = $(noinst_LTLIBRARIES) ++libdiscount_la_DEPENDENCIES = ++am_libdiscount_la_OBJECTS = libdiscount_la-amalloc.lo \ ++ libdiscount_la-basename.lo libdiscount_la-Csio.lo \ ++ libdiscount_la-css.lo libdiscount_la-docheader.lo \ ++ libdiscount_la-dumptree.lo libdiscount_la-emmatch.lo \ ++ libdiscount_la-flags.lo libdiscount_la-generate.lo \ ++ libdiscount_la-html5.lo libdiscount_la-markdown.lo \ ++ libdiscount_la-mkdio.lo libdiscount_la-resource.lo \ ++ libdiscount_la-setup.lo libdiscount_la-tags.lo \ ++ libdiscount_la-toc.lo libdiscount_la-version.lo \ ++ libdiscount_la-xml.lo libdiscount_la-xmlpage.lo ++libdiscount_la_OBJECTS = $(am_libdiscount_la_OBJECTS) ++AM_V_lt = $(am__v_lt_@AM_V@) ++am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) ++am__v_lt_0 = --silent ++DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) ++depcomp = $(SHELL) $(top_srcdir)/depcomp ++am__depfiles_maybe = depfiles ++am__mv = mv -f ++COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ ++ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) ++LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ ++ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ ++ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ ++ $(AM_CFLAGS) $(CFLAGS) ++AM_V_CC = $(am__v_CC_@AM_V@) ++am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) ++am__v_CC_0 = @echo " CC " $@; ++AM_V_at = $(am__v_at_@AM_V@) ++am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) ++am__v_at_0 = @ ++CCLD = $(CC) ++LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ ++ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ ++ $(AM_LDFLAGS) $(LDFLAGS) -o $@ ++AM_V_CCLD = $(am__v_CCLD_@AM_V@) ++am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) ++am__v_CCLD_0 = @echo " CCLD " $@; ++AM_V_GEN = $(am__v_GEN_@AM_V@) ++am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) ++am__v_GEN_0 = @echo " GEN " $@; ++SOURCES = $(libdiscount_la_SOURCES) ++DIST_SOURCES = $(libdiscount_la_SOURCES) ++ETAGS = etags ++CTAGS = ctags ++DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ++ACLOCAL = @ACLOCAL@ ++ALL_LINGUAS = @ALL_LINGUAS@ ++AMTAR = @AMTAR@ ++AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ ++AR = @AR@ ++AUTOCONF = @AUTOCONF@ ++AUTOHEADER = @AUTOHEADER@ ++AUTOMAKE = @AUTOMAKE@ ++AWK = @AWK@ ++CATALOGS = @CATALOGS@ ++CATOBJEXT = @CATOBJEXT@ ++CC = @CC@ ++CCDEPMODE = @CCDEPMODE@ ++CFLAGS = @CFLAGS@ ++CHECK_CFLAGS = @CHECK_CFLAGS@ ++CHECK_LIBS = @CHECK_LIBS@ ++CPP = @CPP@ ++CPPCHECK = @CPPCHECK@ ++CPPFLAGS = @CPPFLAGS@ ++CYGPATH_W = @CYGPATH_W@ ++DATADIRNAME = @DATADIRNAME@ ++DEFS = @DEFS@ ++DEPDIR = @DEPDIR@ ++DEVHELP_CFLAGS = @DEVHELP_CFLAGS@ ++DEVHELP_LIBS = @DEVHELP_LIBS@ ++DLLTOOL = @DLLTOOL@ ++DSYMUTIL = @DSYMUTIL@ ++DUMPBIN = @DUMPBIN@ ++ECHO_C = @ECHO_C@ ++ECHO_N = @ECHO_N@ ++ECHO_T = @ECHO_T@ ++EGREP = @EGREP@ ++ENCHANT_CFLAGS = @ENCHANT_CFLAGS@ ++ENCHANT_LIBS = @ENCHANT_LIBS@ ++EXEEXT = @EXEEXT@ ++FGREP = @FGREP@ ++GEANYGENDOC_CFLAGS = @GEANYGENDOC_CFLAGS@ ++GEANYGENDOC_LIBS = @GEANYGENDOC_LIBS@ ++GEANY_CFLAGS = @GEANY_CFLAGS@ ++GEANY_LIBS = @GEANY_LIBS@ ++GEANY_VERSION = @GEANY_VERSION@ ++GENIUSPASTE_CFLAGS = @GENIUSPASTE_CFLAGS@ ++GENIUSPASTE_LIBS = @GENIUSPASTE_LIBS@ ++GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ ++GIO_CFLAGS = @GIO_CFLAGS@ ++GIO_LIBS = @GIO_LIBS@ ++GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ ++GLIB_MKENUMS = @GLIB_MKENUMS@ ++GMODULE_CFLAGS = @GMODULE_CFLAGS@ ++GMODULE_LIBS = @GMODULE_LIBS@ ++GMOFILES = @GMOFILES@ ++GMSGFMT = @GMSGFMT@ ++GPGME_CFLAGS = @GPGME_CFLAGS@ ++GPGME_CONFIG = @GPGME_CONFIG@ ++GPGME_LIBS = @GPGME_LIBS@ ++GP_CFLAGS = @GP_CFLAGS@ ++GREP = @GREP@ ++GTKSPELL_CFLAGS = @GTKSPELL_CFLAGS@ ++GTKSPELL_LIBS = @GTKSPELL_LIBS@ ++INSTALL = @INSTALL@ ++INSTALL_DATA = @INSTALL_DATA@ ++INSTALL_PROGRAM = @INSTALL_PROGRAM@ ++INSTALL_SCRIPT = @INSTALL_SCRIPT@ ++INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ ++INSTOBJEXT = @INSTOBJEXT@ ++INTLLIBS = @INTLLIBS@ ++INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ ++INTLTOOL_MERGE = @INTLTOOL_MERGE@ ++INTLTOOL_PERL = @INTLTOOL_PERL@ ++INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ ++INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@ ++INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@ ++INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@ ++INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@ ++LD = @LD@ ++LDFLAGS = @LDFLAGS@ ++LIBOBJS = @LIBOBJS@ ++LIBS = @LIBS@ ++LIBTOOL = @LIBTOOL@ ++LIBXML_CFLAGS = @LIBXML_CFLAGS@ ++LIBXML_LIBS = @LIBXML_LIBS@ ++LIPO = @LIPO@ ++LN_S = @LN_S@ ++LOCALEDIR = @LOCALEDIR@ ++LTLIBOBJS = @LTLIBOBJS@ ++LUA_CFLAGS = @LUA_CFLAGS@ ++LUA_LIBS = @LUA_LIBS@ ++MAKEINFO = @MAKEINFO@ ++MANIFEST_TOOL = @MANIFEST_TOOL@ ++MARKDOWN_CFLAGS = @MARKDOWN_CFLAGS@ ++MARKDOWN_LIBS = @MARKDOWN_LIBS@ ++MKDIR_P = @MKDIR_P@ ++MKINSTALLDIRS = @MKINSTALLDIRS@ ++MSGFMT = @MSGFMT@ ++MSGFMT_OPTS = @MSGFMT_OPTS@ ++MSGMERGE = @MSGMERGE@ ++MULTITERM_CFLAGS = @MULTITERM_CFLAGS@ ++MULTITERM_LIBS = @MULTITERM_LIBS@ ++NM = @NM@ ++NMEDIT = @NMEDIT@ ++OBJDUMP = @OBJDUMP@ ++OBJEXT = @OBJEXT@ ++OTOOL = @OTOOL@ ++OTOOL64 = @OTOOL64@ ++PACKAGE = @PACKAGE@ ++PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ ++PACKAGE_NAME = @PACKAGE_NAME@ ++PACKAGE_STRING = @PACKAGE_STRING@ ++PACKAGE_TARNAME = @PACKAGE_TARNAME@ ++PACKAGE_URL = @PACKAGE_URL@ ++PACKAGE_VERSION = @PACKAGE_VERSION@ ++PATH_SEPARATOR = @PATH_SEPARATOR@ ++PKG_CONFIG = @PKG_CONFIG@ ++PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ ++PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ ++POFILES = @POFILES@ ++POSUB = @POSUB@ ++PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ ++PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ ++RANLIB = @RANLIB@ ++RST2HTML = @RST2HTML@ ++SED = @SED@ ++SET_MAKE = @SET_MAKE@ ++SHELL = @SHELL@ ++STRIP = @STRIP@ ++UPDATECHECKER_CFLAGS = @UPDATECHECKER_CFLAGS@ ++UPDATECHECKER_LIBS = @UPDATECHECKER_LIBS@ ++USE_NLS = @USE_NLS@ ++VALAC = @VALAC@ ++VERSION = @VERSION@ ++VTE_CFLAGS = @VTE_CFLAGS@ ++VTE_LIBS = @VTE_LIBS@ ++WEBHELPER_CFLAGS = @WEBHELPER_CFLAGS@ ++WEBHELPER_LIBS = @WEBHELPER_LIBS@ ++XGETTEXT = @XGETTEXT@ ++abs_builddir = @abs_builddir@ ++abs_srcdir = @abs_srcdir@ ++abs_top_builddir = @abs_top_builddir@ ++abs_top_srcdir = @abs_top_srcdir@ ++ac_ct_AR = @ac_ct_AR@ ++ac_ct_CC = @ac_ct_CC@ ++ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ++am__include = @am__include@ ++am__leading_dot = @am__leading_dot@ ++am__quote = @am__quote@ ++am__tar = @am__tar@ ++am__untar = @am__untar@ ++bindir = @bindir@ ++build = @build@ ++build_alias = @build_alias@ ++build_cpu = @build_cpu@ ++build_os = @build_os@ ++build_vendor = @build_vendor@ ++builddir = @builddir@ ++datadir = @datadir@ ++datarootdir = @datarootdir@ ++docdir = @docdir@ ++dvidir = @dvidir@ ++exec_prefix = @exec_prefix@ ++geanypluginsdir = @geanypluginsdir@ ++host = @host@ ++host_alias = @host_alias@ ++host_cpu = @host_cpu@ ++host_os = @host_os@ ++host_vendor = @host_vendor@ ++htmldir = @htmldir@ ++includedir = @includedir@ ++infodir = @infodir@ ++install_sh = @install_sh@ ++intltool__v_merge_options_ = @intltool__v_merge_options_@ ++intltool__v_merge_options_0 = @intltool__v_merge_options_0@ ++libdir = @libdir@ ++libexecdir = @libexecdir@ ++localedir = @localedir@ ++localstatedir = @localstatedir@ ++mandir = @mandir@ ++mkdir_p = @mkdir_p@ ++oldincludedir = @oldincludedir@ ++pdfdir = @pdfdir@ ++prefix = @prefix@ ++program_transform_name = @program_transform_name@ ++psdir = @psdir@ ++sbindir = @sbindir@ ++sharedstatedir = @sharedstatedir@ ++srcdir = @srcdir@ ++sysconfdir = @sysconfdir@ ++target_alias = @target_alias@ ++top_build_prefix = @top_build_prefix@ ++top_builddir = @top_builddir@ ++top_srcdir = @top_srcdir@ ++noinst_LTLIBRARIES = libdiscount.la ++libdiscount_la_SOURCES = \ ++ amalloc.c \ ++ amalloc.h \ ++ basename.c \ ++ config.h \ ++ Csio.c \ ++ css.c \ ++ cstring.h \ ++ docheader.c \ ++ dumptree.c \ ++ emmatch.c \ ++ flags.c \ ++ generate.c \ ++ html5.c \ ++ markdown.c \ ++ markdown.h \ ++ mkdio.c \ ++ mkdio.h \ ++ resource.c \ ++ setup.c \ ++ tags.c \ ++ tags.h \ ++ toc.c \ ++ version.c \ ++ xml.c \ ++ xmlpage.c ++ ++libdiscount_la_CPPFLAGS = @MARKDOWN_CFLAGS@ ++libdiscount_la_LIBADD = @MARKDOWN_LIBS@ ++all: all-am ++ ++.SUFFIXES: ++.SUFFIXES: .c .lo .o .obj ++$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) ++ @for dep in $?; do \ ++ case '$(am__configure_deps)' in \ ++ *$$dep*) \ ++ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ ++ && { if test -f $@; then exit 0; else break; fi; }; \ ++ exit 1;; \ ++ esac; \ ++ done; \ ++ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign markdown/discount/Makefile'; \ ++ $(am__cd) $(top_srcdir) && \ ++ $(AUTOMAKE) --foreign markdown/discount/Makefile ++.PRECIOUS: Makefile ++Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status ++ @case '$?' in \ ++ *config.status*) \ ++ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ ++ *) \ ++ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ ++ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ ++ esac; ++ ++$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) ++ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ++ ++$(top_srcdir)/configure: $(am__configure_deps) ++ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ++$(ACLOCAL_M4): $(am__aclocal_m4_deps) ++ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ++$(am__aclocal_m4_deps): ++ ++clean-noinstLTLIBRARIES: ++ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) ++ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ ++ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ ++ test "$$dir" != "$$p" || dir=.; \ ++ echo "rm -f \"$${dir}/so_locations\""; \ ++ rm -f "$${dir}/so_locations"; \ + done +- for x in mkd_compile mkd_css mkd_generatecss mkd_generatehtml mkd_cleanup mkd_doc_title mkd_doc_author mkd_doc_date; do \ +- ( echo '.\"' ; echo ".so man3/mkd-functions.3" ) > $(DESTDIR)$(MANDIR)/man3/$$x.3; \ ++libdiscount.la: $(libdiscount_la_OBJECTS) $(libdiscount_la_DEPENDENCIES) $(EXTRA_libdiscount_la_DEPENDENCIES) ++ $(AM_V_CCLD)$(LINK) $(libdiscount_la_OBJECTS) $(libdiscount_la_LIBADD) $(LIBS) ++ ++mostlyclean-compile: ++ -rm -f *.$(OBJEXT) ++ ++distclean-compile: ++ -rm -f *.tab.c ++ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-Csio.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-amalloc.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-basename.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-css.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-docheader.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-dumptree.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-emmatch.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-flags.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-generate.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-html5.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-markdown.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-mkdio.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-resource.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-setup.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-tags.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-toc.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-version.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-xml.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdiscount_la-xmlpage.Plo@am__quote@ ++ ++.c.o: ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< ++ ++.c.obj: ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` ++ ++.c.lo: ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< ++ ++libdiscount_la-amalloc.lo: amalloc.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-amalloc.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-amalloc.Tpo -c -o libdiscount_la-amalloc.lo `test -f 'amalloc.c' || echo '$(srcdir)/'`amalloc.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-amalloc.Tpo $(DEPDIR)/libdiscount_la-amalloc.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='amalloc.c' object='libdiscount_la-amalloc.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-amalloc.lo `test -f 'amalloc.c' || echo '$(srcdir)/'`amalloc.c ++ ++libdiscount_la-basename.lo: basename.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-basename.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-basename.Tpo -c -o libdiscount_la-basename.lo `test -f 'basename.c' || echo '$(srcdir)/'`basename.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-basename.Tpo $(DEPDIR)/libdiscount_la-basename.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='basename.c' object='libdiscount_la-basename.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-basename.lo `test -f 'basename.c' || echo '$(srcdir)/'`basename.c ++ ++libdiscount_la-Csio.lo: Csio.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-Csio.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-Csio.Tpo -c -o libdiscount_la-Csio.lo `test -f 'Csio.c' || echo '$(srcdir)/'`Csio.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-Csio.Tpo $(DEPDIR)/libdiscount_la-Csio.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='Csio.c' object='libdiscount_la-Csio.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-Csio.lo `test -f 'Csio.c' || echo '$(srcdir)/'`Csio.c ++ ++libdiscount_la-css.lo: css.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-css.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-css.Tpo -c -o libdiscount_la-css.lo `test -f 'css.c' || echo '$(srcdir)/'`css.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-css.Tpo $(DEPDIR)/libdiscount_la-css.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='css.c' object='libdiscount_la-css.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-css.lo `test -f 'css.c' || echo '$(srcdir)/'`css.c ++ ++libdiscount_la-docheader.lo: docheader.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-docheader.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-docheader.Tpo -c -o libdiscount_la-docheader.lo `test -f 'docheader.c' || echo '$(srcdir)/'`docheader.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-docheader.Tpo $(DEPDIR)/libdiscount_la-docheader.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='docheader.c' object='libdiscount_la-docheader.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-docheader.lo `test -f 'docheader.c' || echo '$(srcdir)/'`docheader.c ++ ++libdiscount_la-dumptree.lo: dumptree.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-dumptree.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-dumptree.Tpo -c -o libdiscount_la-dumptree.lo `test -f 'dumptree.c' || echo '$(srcdir)/'`dumptree.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-dumptree.Tpo $(DEPDIR)/libdiscount_la-dumptree.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dumptree.c' object='libdiscount_la-dumptree.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-dumptree.lo `test -f 'dumptree.c' || echo '$(srcdir)/'`dumptree.c ++ ++libdiscount_la-emmatch.lo: emmatch.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-emmatch.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-emmatch.Tpo -c -o libdiscount_la-emmatch.lo `test -f 'emmatch.c' || echo '$(srcdir)/'`emmatch.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-emmatch.Tpo $(DEPDIR)/libdiscount_la-emmatch.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emmatch.c' object='libdiscount_la-emmatch.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-emmatch.lo `test -f 'emmatch.c' || echo '$(srcdir)/'`emmatch.c ++ ++libdiscount_la-flags.lo: flags.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-flags.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-flags.Tpo -c -o libdiscount_la-flags.lo `test -f 'flags.c' || echo '$(srcdir)/'`flags.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-flags.Tpo $(DEPDIR)/libdiscount_la-flags.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='flags.c' object='libdiscount_la-flags.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-flags.lo `test -f 'flags.c' || echo '$(srcdir)/'`flags.c ++ ++libdiscount_la-generate.lo: generate.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-generate.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-generate.Tpo -c -o libdiscount_la-generate.lo `test -f 'generate.c' || echo '$(srcdir)/'`generate.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-generate.Tpo $(DEPDIR)/libdiscount_la-generate.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generate.c' object='libdiscount_la-generate.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-generate.lo `test -f 'generate.c' || echo '$(srcdir)/'`generate.c ++ ++libdiscount_la-html5.lo: html5.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-html5.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-html5.Tpo -c -o libdiscount_la-html5.lo `test -f 'html5.c' || echo '$(srcdir)/'`html5.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-html5.Tpo $(DEPDIR)/libdiscount_la-html5.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='html5.c' object='libdiscount_la-html5.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-html5.lo `test -f 'html5.c' || echo '$(srcdir)/'`html5.c ++ ++libdiscount_la-markdown.lo: markdown.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-markdown.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-markdown.Tpo -c -o libdiscount_la-markdown.lo `test -f 'markdown.c' || echo '$(srcdir)/'`markdown.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-markdown.Tpo $(DEPDIR)/libdiscount_la-markdown.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='markdown.c' object='libdiscount_la-markdown.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-markdown.lo `test -f 'markdown.c' || echo '$(srcdir)/'`markdown.c ++ ++libdiscount_la-mkdio.lo: mkdio.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-mkdio.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-mkdio.Tpo -c -o libdiscount_la-mkdio.lo `test -f 'mkdio.c' || echo '$(srcdir)/'`mkdio.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-mkdio.Tpo $(DEPDIR)/libdiscount_la-mkdio.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mkdio.c' object='libdiscount_la-mkdio.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-mkdio.lo `test -f 'mkdio.c' || echo '$(srcdir)/'`mkdio.c ++ ++libdiscount_la-resource.lo: resource.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-resource.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-resource.Tpo -c -o libdiscount_la-resource.lo `test -f 'resource.c' || echo '$(srcdir)/'`resource.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-resource.Tpo $(DEPDIR)/libdiscount_la-resource.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='resource.c' object='libdiscount_la-resource.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-resource.lo `test -f 'resource.c' || echo '$(srcdir)/'`resource.c ++ ++libdiscount_la-setup.lo: setup.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-setup.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-setup.Tpo -c -o libdiscount_la-setup.lo `test -f 'setup.c' || echo '$(srcdir)/'`setup.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-setup.Tpo $(DEPDIR)/libdiscount_la-setup.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='setup.c' object='libdiscount_la-setup.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-setup.lo `test -f 'setup.c' || echo '$(srcdir)/'`setup.c ++ ++libdiscount_la-tags.lo: tags.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-tags.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-tags.Tpo -c -o libdiscount_la-tags.lo `test -f 'tags.c' || echo '$(srcdir)/'`tags.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-tags.Tpo $(DEPDIR)/libdiscount_la-tags.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tags.c' object='libdiscount_la-tags.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-tags.lo `test -f 'tags.c' || echo '$(srcdir)/'`tags.c ++ ++libdiscount_la-toc.lo: toc.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-toc.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-toc.Tpo -c -o libdiscount_la-toc.lo `test -f 'toc.c' || echo '$(srcdir)/'`toc.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-toc.Tpo $(DEPDIR)/libdiscount_la-toc.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toc.c' object='libdiscount_la-toc.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-toc.lo `test -f 'toc.c' || echo '$(srcdir)/'`toc.c ++ ++libdiscount_la-version.lo: version.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-version.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-version.Tpo -c -o libdiscount_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-version.Tpo $(DEPDIR)/libdiscount_la-version.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='version.c' object='libdiscount_la-version.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c ++ ++libdiscount_la-xml.lo: xml.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-xml.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-xml.Tpo -c -o libdiscount_la-xml.lo `test -f 'xml.c' || echo '$(srcdir)/'`xml.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-xml.Tpo $(DEPDIR)/libdiscount_la-xml.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xml.c' object='libdiscount_la-xml.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-xml.lo `test -f 'xml.c' || echo '$(srcdir)/'`xml.c ++ ++libdiscount_la-xmlpage.lo: xmlpage.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdiscount_la-xmlpage.lo -MD -MP -MF $(DEPDIR)/libdiscount_la-xmlpage.Tpo -c -o libdiscount_la-xmlpage.lo `test -f 'xmlpage.c' || echo '$(srcdir)/'`xmlpage.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdiscount_la-xmlpage.Tpo $(DEPDIR)/libdiscount_la-xmlpage.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xmlpage.c' object='libdiscount_la-xmlpage.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdiscount_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdiscount_la-xmlpage.lo `test -f 'xmlpage.c' || echo '$(srcdir)/'`xmlpage.c ++ ++mostlyclean-libtool: ++ -rm -f *.lo ++ ++clean-libtool: ++ -rm -rf .libs _libs ++ ++ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) ++ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ ++ END { if (nonempty) { for (i in files) print i; }; }'`; \ ++ mkid -fID $$unique ++tags: TAGS ++ ++TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ ++ $(TAGS_FILES) $(LISP) ++ set x; \ ++ here=`pwd`; \ ++ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ ++ END { if (nonempty) { for (i in files) print i; }; }'`; \ ++ shift; \ ++ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ ++ test -n "$$unique" || unique=$$empty_fix; \ ++ if test $$# -gt 0; then \ ++ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ ++ "$$@" $$unique; \ ++ else \ ++ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ ++ $$unique; \ ++ fi; \ ++ fi ++ctags: CTAGS ++CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ ++ $(TAGS_FILES) $(LISP) ++ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ ++ END { if (nonempty) { for (i in files) print i; }; }'`; \ ++ test -z "$(CTAGS_ARGS)$$unique" \ ++ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ ++ $$unique ++ ++GTAGS: ++ here=`$(am__cd) $(top_builddir) && pwd` \ ++ && $(am__cd) $(top_srcdir) \ ++ && gtags -i $(GTAGS_ARGS) "$$here" ++ ++distclean-tags: ++ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags ++ ++distdir: $(DISTFILES) ++ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ ++ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ ++ list='$(DISTFILES)'; \ ++ dist_files=`for file in $$list; do echo $$file; done | \ ++ sed -e "s|^$$srcdirstrip/||;t" \ ++ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ ++ case $$dist_files in \ ++ */*) $(MKDIR_P) `echo "$$dist_files" | \ ++ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ ++ sort -u` ;; \ ++ esac; \ ++ for file in $$dist_files; do \ ++ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ ++ if test -d $$d/$$file; then \ ++ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ ++ if test -d "$(distdir)/$$file"; then \ ++ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ ++ fi; \ ++ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ ++ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ ++ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ ++ fi; \ ++ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ ++ else \ ++ test -f "$(distdir)/$$file" \ ++ || cp -p $$d/$$file "$(distdir)/$$file" \ ++ || exit 1; \ ++ fi; \ + done +- @INSTALL_DIR@ $(DESTDIR)$(MANDIR)/man7 +- @INSTALL_DATA@ markdown.7 mkd-extensions.7 $(DESTDIR)$(MANDIR)/man7 +- @INSTALL_DIR@ $(DESTDIR)$(MANDIR)/man1 +- @INSTALL_DATA@ markdown.1 $(DESTDIR)$(MANDIR)/man1 ++check-am: all-am ++check: check-am ++all-am: Makefile $(LTLIBRARIES) ++installdirs: ++install: install-am ++install-exec: install-exec-am ++install-data: install-data-am ++uninstall: uninstall-am + +-install.everything: install install.man ++install-am: all-am ++ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +-$(DESTDIR)$(BINDIR): +- @INSTALL_DIR@ $(DESTDIR)$(BINDIR) ++installcheck: installcheck-am ++install-strip: ++ if test -z '$(STRIP)'; then \ ++ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ ++ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ ++ install; \ ++ else \ ++ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ ++ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ ++ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ ++ fi ++mostlyclean-generic: + +-$(DESTDIR)$(INCDIR): +- @INSTALL_DIR@ $(DESTDIR)$(INCDIR) ++clean-generic: + +-$(DESTDIR)$(LIBDIR): +- @INSTALL_DIR@ $(DESTDIR)$(LIBDIR) ++distclean-generic: ++ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) ++ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +-version.o: version.c VERSION +- $(CC) -DVERSION=\"`cat VERSION`\" -c version.c ++maintainer-clean-generic: ++ @echo "This command is intended for maintainers to use" ++ @echo "it deletes files that may require special tools to rebuild." ++clean: clean-am + +-VERSION: +- @true ++clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ ++ mostlyclean-am + +-tags.o: tags.c blocktags ++distclean: distclean-am ++ -rm -rf ./$(DEPDIR) ++ -rm -f Makefile ++distclean-am: clean-am distclean-compile distclean-generic \ ++ distclean-tags + +-blocktags: mktags +- ./mktags > blocktags ++dvi: dvi-am + +-# example programs +-@THEME@theme: theme.o $(MKDLIB) mkdio.h +-@THEME@ $(CC) -o theme theme.o -lmarkdown @LIBS@ ++dvi-am: + ++html: html-am + +-mkd2html: mkd2html.o $(MKDLIB) mkdio.h +- $(CC) -o mkd2html mkd2html.o -lmarkdown @LIBS@ ++html-am: + +-markdown: main.o pgm_options.o $(MKDLIB) +- $(CC) $(CFLAGS) -o markdown main.o pgm_options.o -lmarkdown @LIBS@ +- +-makepage: makepage.c pgm_options.o $(MKDLIB) mkdio.h +- $(CC) $(CFLAGS) -o makepage makepage.c pgm_options.o -lmarkdown @LIBS@ ++info: info-am + +-pgm_options.o: pgm_options.c mkdio.h config.h +- $(CC) -I. -c pgm_options.c ++info-am: + +-main.o: main.c mkdio.h config.h +- $(CC) -I. -c main.c ++install-data-am: + +-$(MKDLIB): $(OBJS) +- ./librarian.sh make $(MKDLIB) VERSION $(OBJS) ++install-dvi: install-dvi-am + +-verify: echo tools/checkbits.sh +- @./echo -n "headers ... "; tools/checkbits.sh && echo "GOOD" ++install-dvi-am: ++ ++install-exec-am: ++ ++install-html: install-html-am ++ ++install-html-am: ++ ++install-info: install-info-am ++ ++install-info-am: ++ ++install-man: ++ ++install-pdf: install-pdf-am ++ ++install-pdf-am: ++ ++install-ps: install-ps-am ++ ++install-ps-am: ++ ++installcheck-am: ++ ++maintainer-clean: maintainer-clean-am ++ -rm -rf ./$(DEPDIR) ++ -rm -f Makefile ++maintainer-clean-am: distclean-am maintainer-clean-generic ++ ++mostlyclean: mostlyclean-am ++ ++mostlyclean-am: mostlyclean-compile mostlyclean-generic \ ++ mostlyclean-libtool ++ ++pdf: pdf-am ++ ++pdf-am: ++ ++ps: ps-am ++ ++ps-am: ++ ++uninstall-am: ++ ++.MAKE: install-am install-strip ++ ++.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ ++ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ ++ distclean-compile distclean-generic distclean-libtool \ ++ distclean-tags distdir dvi dvi-am html html-am info info-am \ ++ install install-am install-data install-data-am install-dvi \ ++ install-dvi-am install-exec install-exec-am install-html \ ++ install-html-am install-info install-info-am install-man \ ++ install-pdf install-pdf-am install-ps install-ps-am \ ++ install-strip installcheck installcheck-am installdirs \ ++ maintainer-clean maintainer-clean-generic mostlyclean \ ++ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ ++ pdf pdf-am ps ps-am tags uninstall uninstall-am + +-test: $(PGMS) $(TESTFRAMEWORK) verify +- @for x in tests/*.t; do \ +- @LD_LIBRARY_PATH@=`pwd` sh $$x || exit 1; \ +- done + +-cols: tools/cols.c config.h +- $(CC) -o cols tools/cols.c +-echo: tools/echo.c config.h +- $(CC) -o echo tools/echo.c +- +-clean: +- rm -f $(PGMS) $(TESTFRAMEWORK) $(SAMPLE_PGMS) *.o +- rm -f $(MKDLIB) `./librarian.sh files $(MKDLIB) VERSION` +- +-distclean spotless: clean +- rm -f @GENERATED_FILES@ @CONFIGURE_FILES@ +- +-Csio.o: Csio.c cstring.h amalloc.h config.h markdown.h +-amalloc.o: amalloc.c +-basename.o: basename.c config.h cstring.h amalloc.h markdown.h +-css.o: css.c config.h cstring.h amalloc.h markdown.h +-docheader.o: docheader.c config.h cstring.h amalloc.h markdown.h +-dumptree.o: dumptree.c markdown.h cstring.h amalloc.h config.h +-emmatch.o: emmatch.c config.h cstring.h amalloc.h markdown.h +-generate.o: generate.c config.h cstring.h amalloc.h markdown.h +-main.o: main.c config.h amalloc.h +-pgm_options.o: pgm_options.c pgm_options.h config.h amalloc.h +-makepage.o: makepage.c +-markdown.o: markdown.c config.h cstring.h amalloc.h markdown.h +-mkd2html.o: mkd2html.c config.h mkdio.h cstring.h amalloc.h +-mkdio.o: mkdio.c config.h cstring.h amalloc.h markdown.h +-resource.o: resource.c config.h cstring.h amalloc.h markdown.h +-theme.o: theme.c config.h mkdio.h cstring.h amalloc.h +-toc.o: toc.c config.h cstring.h amalloc.h markdown.h +-version.o: version.c config.h +-xml.o: xml.c config.h cstring.h amalloc.h markdown.h +-xmlpage.o: xmlpage.c config.h cstring.h amalloc.h markdown.h ++# Tell versions [3.59,3.63) of GNU make to not export all variables. ++# Otherwise a system limit (for SysV at least) may be exceeded. ++.NOEXPORT: +Only in discount-2.1.3/: makepage.1 +Only in discount-2.1.3/: makepage.c +Only in discount-2.1.3/: markdown.1 +Only in discount-2.1.3/: markdown.3 +Only in discount-2.1.3/: markdown.7 +diff -u discount-2.1.3/markdown.c discount/markdown.c +--- discount-2.1.3/markdown.c 2012-01-16 13:08:52.000000000 -0800 ++++ discount/markdown.c 2012-07-14 17:10:34.896759442 -0700 +@@ -514,7 +514,7 @@ + return AL; + } + +- strtoul(T(t->text)+t->dle, &q, 10); ++ unsigned long res = strtoul(T(t->text)+t->dle, &q, 10); + if ( (q > T(t->text)+t->dle) && (q == T(t->text) + (j-1)) ) { + j = nextnonblank(t,j); + *clip = (j > 4) ? 4 : j; +Only in discount-2.1.3/: mkd2html.1 +Only in discount-2.1.3/: mkd2html.c +Only in discount-2.1.3/: mkd-callbacks.3 +Only in discount-2.1.3/: mkd-extensions.7 +Only in discount-2.1.3/: mkd-functions.3 +Only in discount/: mkdio.h +Only in discount-2.1.3/: mkdio.h.in +Only in discount-2.1.3/: mkd-line.3 +Only in discount-2.1.3/: mktags.c +Only in discount-2.1.3/: pgm_options.c +Only in discount-2.1.3/: pgm_options.h +Only in discount-2.1.3/: Plan9 +Only in discount-2.1.3/: README +Only in discount-2.1.3/: tests +Only in discount-2.1.3/: theme.1 +Only in discount-2.1.3/: theme.c +Only in discount-2.1.3/: tools +Only in discount-2.1.3/: VERSION +Only in discount/: version.c +Only in discount-2.1.3/: version.c.in diff --git a/markdown/discount/docheader.c b/markdown/discount/docheader.c new file mode 100644 index 000000000..073f6da62 --- /dev/null +++ b/markdown/discount/docheader.c @@ -0,0 +1,49 @@ +/* + * docheader -- get values from the document header + * + * Copyright (C) 2007 David L Parsons. + * The redistribution terms are provided in the COPYRIGHT file that must + * be distributed with this source code. + */ +#include "config.h" +#include +#include +#include + +#include "cstring.h" +#include "markdown.h" +#include "amalloc.h" + +static char * +onlyifset(Line *l) +{ + char *ret = T(l->text) + l->dle; + + return ret[0] ? ret : 0; +} + +char * +mkd_doc_title(Document *doc) +{ + if ( doc && doc->title ) + return onlyifset(doc->title); + return 0; +} + + +char * +mkd_doc_author(Document *doc) +{ + if ( doc && doc->author ) + return onlyifset(doc->author); + return 0; +} + + +char * +mkd_doc_date(Document *doc) +{ + if ( doc && doc->date ) + return onlyifset(doc->date); + return 0; +} diff --git a/markdown/discount/dumptree.c b/markdown/discount/dumptree.c new file mode 100644 index 000000000..0c0c01f53 --- /dev/null +++ b/markdown/discount/dumptree.c @@ -0,0 +1,152 @@ +/* markdown: a C implementation of John Gruber's Markdown markup language. + * + * Copyright (C) 2007 David L Parsons. + * The redistribution terms are provided in the COPYRIGHT file that must + * be distributed with this source code. + */ +#include +#include "markdown.h" +#include "cstring.h" +#include "amalloc.h" + +struct frame { + int indent; + char c; +}; + +typedef STRING(struct frame) Stack; + +static char * +Pptype(int typ) +{ + switch (typ) { + case WHITESPACE: return "whitespace"; + case CODE : return "code"; + case QUOTE : return "quote"; + case MARKUP : return "markup"; + case HTML : return "html"; + case DL : return "dl"; + case UL : return "ul"; + case OL : return "ol"; + case LISTITEM : return "item"; + case HDR : return "header"; + case HR : return "hr"; + case TABLE : return "table"; + case SOURCE : return "source"; + case STYLE : return "style"; + default : return "mystery node!"; + } +} + +static void +pushpfx(int indent, char c, Stack *sp) +{ + struct frame *q = &EXPAND(*sp); + + q->indent = indent; + q->c = c; +} + + +static void +poppfx(Stack *sp) +{ + S(*sp)--; +} + + +static void +changepfx(Stack *sp, char c) +{ + char ch; + + if ( !S(*sp) ) return; + + ch = T(*sp)[S(*sp)-1].c; + + if ( ch == '+' || ch == '|' ) + T(*sp)[S(*sp)-1].c = c; +} + + +static void +printpfx(Stack *sp, FILE *f) +{ + int i; + char c; + + if ( !S(*sp) ) return; + + c = T(*sp)[S(*sp)-1].c; + + if ( c == '+' || c == '-' ) { + fprintf(f, "--%c", c); + T(*sp)[S(*sp)-1].c = (c == '-') ? ' ' : '|'; + } + else + for ( i=0; i < S(*sp); i++ ) { + if ( i ) + fprintf(f, " "); + fprintf(f, "%*s%c", T(*sp)[i].indent + 2, " ", T(*sp)[i].c); + if ( T(*sp)[i].c == '`' ) + T(*sp)[i].c = ' '; + } + fprintf(f, "--"); +} + + +static void +dumptree(Paragraph *pp, Stack *sp, FILE *f) +{ + int count; + Line *p; + int d; + static char *Begin[] = { 0, "P", "center" }; + + while ( pp ) { + if ( !pp->next ) + changepfx(sp, '`'); + printpfx(sp, f); + + d = fprintf(f, "[%s", Pptype(pp->typ)); + if ( pp->ident ) + d += fprintf(f, " %s", pp->ident); + if ( pp->align > 1 ) + d += fprintf(f, ", <%s>", Begin[pp->align]); + + for (count=0, p=pp->text; p; ++count, (p = p->next) ) + ; + + if ( count ) + d += fprintf(f, ", %d line%s", count, (count==1)?"":"s"); + + d += fprintf(f, "]"); + + if ( pp->down ) { + pushpfx(d, pp->down->next ? '+' : '-', sp); + dumptree(pp->down, sp, f); + poppfx(sp); + } + else fputc('\n', f); + pp = pp->next; + } +} + + +int +mkd_dump(Document *doc, FILE *out, int flags, char *title) +{ + Stack stack; + + if (mkd_compile(doc, flags) ) { + + CREATE(stack); + pushpfx(fprintf(out, "%s", title), doc->code->next ? '+' : '-', &stack); + dumptree(doc->code, &stack, out); + DELETE(stack); + + mkd_cleanup(doc); + return 0; + } + return -1; +} diff --git a/markdown/discount/emmatch.c b/markdown/discount/emmatch.c new file mode 100644 index 000000000..4f4eabd96 --- /dev/null +++ b/markdown/discount/emmatch.c @@ -0,0 +1,188 @@ +/* markdown: a C implementation of John Gruber's Markdown markup language. + * + * Copyright (C) 2010 David L Parsons. + * The redistribution terms are provided in the COPYRIGHT file that must + * be distributed with this source code. + */ +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#include "cstring.h" +#include "markdown.h" +#include "amalloc.h" + + +/* emmatch: the emphasis mangler that's run after a block + * of html has been generated. + * + * It should create MarkdownTest_1.0 (and _1.0.3) + * compatable emphasis for non-pathological cases + * and it should fail in a standards-compliant way + * when someone attempts to feed it junk. + * + * Emmatching is done after the input has been + * processed into a STRING (f->Q) of text and + * emphasis blocks. After ___mkd_emblock() finishes, + * it truncates f->Q and leaves the rendered paragraph + * if f->out. + */ + + +/* empair() -- find the NEAREST matching emphasis token (or + * subtoken of a 3+ long emphasis token. + */ +static int +empair(MMIOT *f, int first, int last, int match) +{ + + int i; + block *begin, *p; + + begin = &T(f->Q)[first]; + + for (i=first+1; i <= last; i++) { + p = &T(f->Q)[i]; + + if ( (p->b_type != bTEXT) && (p->b_count <= 0) ) + continue; /* break? */ + + if ( p->b_type == begin->b_type ) { + if ( p->b_count == match ) /* exact match */ + return i; + + if ( p->b_count > 2 ) /* fuzzy match */ + return i; + } + } + return 0; +} /* empair */ + + +/* emfill() -- if an emphasis token has leftover stars or underscores, + * convert them back into character and append them to b_text. + */ +static void +emfill(block *p) +{ + int j; + + if ( p->b_type == bTEXT ) + return; + + for (j=0; j < p->b_count; j++) + EXPAND(p->b_text) = p->b_char; + p->b_count = 0; +} /* emfill */ + + +static void +emclose(MMIOT *f, int first, int last) +{ + int j; + + for (j=first+1; jQ)[j]); +} + + +static struct emtags { + char open[10]; + char close[10]; + int size; +} emtags[] = { { "" , "", 5 }, { "", "", 9 } }; + + +static void emblock(MMIOT*,int,int); + + +/* emmatch() -- match emphasis for a single emphasis token. + */ +static void +emmatch(MMIOT *f, int first, int last) +{ + block *start = &T(f->Q)[first]; + int e, e2, match; + + switch (start->b_count) { + case 2: if ( e = empair(f,first,last,match=2) ) + break; + case 1: e = empair(f,first,last,match=1); + break; + case 0: return; + default: + e = empair(f,first,last,1); + e2= empair(f,first,last,2); + + if ( e2 >= e ) { + e = e2; + match = 2; + } + else + match = 1; + break; + } + + if ( e ) { + /* if we found emphasis to match, match it, recursively call + * emblock to match emphasis inside the new html block, add + * the emphasis markers for the block, then (tail) recursively + * call ourself to match any remaining emphasis on this token. + */ + block *end = &T(f->Q)[e]; + + end->b_count -= match; + start->b_count -= match; + + emblock(f, first, e); + + MDPREFIX(start->b_text, emtags[match-1].open, emtags[match-1].size-1); + SUFFIX(end->b_post, emtags[match-1].close, emtags[match-1].size); + + emmatch(f, first, last); + } +} /* emmatch */ + + +/* emblock() -- walk a blocklist, attempting to match emphasis + */ +static void +emblock(MMIOT *f, int first, int last) +{ + int i; + + for ( i = first; i <= last; i++ ) + if ( T(f->Q)[i].b_type != bTEXT ) + emmatch(f, i, last); + emclose(f, first, last); +} /* emblock */ + + +/* ___mkd_emblock() -- emblock a string of blocks, then concatenate the + * resulting text onto f->out. + */ +void +___mkd_emblock(MMIOT *f) +{ + int i; + block *p; + + emblock(f, 0, S(f->Q)-1); + + for (i=0; i < S(f->Q); i++) { + p = &T(f->Q)[i]; + emfill(p); + + if ( S(p->b_post) ) { SUFFIX(f->out, T(p->b_post), S(p->b_post)); + DELETE(p->b_post); } + if ( S(p->b_text) ) { SUFFIX(f->out, T(p->b_text), S(p->b_text)); + DELETE(p->b_text); } + } + + S(f->Q) = 0; +} /* ___mkd_emblock */ diff --git a/markdown/discount/flags.c b/markdown/discount/flags.c new file mode 100644 index 000000000..5bf206c18 --- /dev/null +++ b/markdown/discount/flags.c @@ -0,0 +1,84 @@ +#include +#include "markdown.h" + +struct flagnames { + DWORD flag; + char *name; +}; + +static struct flagnames flagnames[] = { + { MKD_NOLINKS, "!LINKS" }, + { MKD_NOIMAGE, "!IMAGE" }, + { MKD_NOPANTS, "!PANTS" }, + { MKD_NOHTML, "!HTML" }, + { MKD_STRICT, "STRICT" }, + { MKD_TAGTEXT, "TAGTEXT" }, + { MKD_NO_EXT, "!EXT" }, + { MKD_CDATA, "CDATA" }, + { MKD_NOSUPERSCRIPT, "!SUPERSCRIPT" }, + { MKD_NORELAXED, "!RELAXED" }, + { MKD_NOTABLES, "!TABLES" }, + { MKD_NOSTRIKETHROUGH,"!STRIKETHROUGH" }, + { MKD_TOC, "TOC" }, + { MKD_1_COMPAT, "MKD_1_COMPAT" }, + { MKD_AUTOLINK, "AUTOLINK" }, + { MKD_SAFELINK, "SAFELINK" }, + { MKD_NOHEADER, "!HEADER" }, + { MKD_TABSTOP, "TABSTOP" }, + { MKD_NODIVQUOTE, "!DIVQUOTE" }, + { MKD_NOALPHALIST, "!ALPHALIST" }, + { MKD_NODLIST, "!DLIST" }, + { MKD_EXTRA_FOOTNOTE, "FOOTNOTE" }, +}; +#define NR(x) (sizeof x/sizeof x[0]) + + +void +mkd_flags_are(FILE *f, DWORD flags, int htmlplease) +{ + int i; + int not, set, even=1; + char *name; + + if ( htmlplease ) + fprintf(f, "\n"); + for (i=0; i < NR(flagnames); i++) { + set = flags & flagnames[i].flag; + name = flagnames[i].name; + if ( not = (*name == '!') ) { + ++name; + set = !set; + } + + if ( htmlplease ) { + if ( even ) fprintf(f, " "); + fprintf(f, ""); + if ( !even ) fprintf(f, "\n"); + } + even = !even; + } + if ( htmlplease ) { + if ( even ) fprintf(f, "\n"); + fprintf(f, "
"); + } + else + fputc(' ', f); + + if ( !set ) + fprintf(f, htmlplease ? "" : "!"); + + fprintf(f, "%s", name); + + if ( htmlplease ) { + if ( !set ) + fprintf(f, ""); + fprintf(f, "
\n"); + } +} + +void +mkd_mmiot_flags(FILE *f, MMIOT *m, int htmlplease) +{ + if ( m ) + mkd_flags_are(f, m->flags, htmlplease); +} diff --git a/markdown/discount/generate.c b/markdown/discount/generate.c new file mode 100644 index 000000000..5c0b179f0 --- /dev/null +++ b/markdown/discount/generate.c @@ -0,0 +1,1762 @@ +/* markdown: a C implementation of John Gruber's Markdown markup language. + * + * Copyright (C) 2007 David L Parsons. + * The redistribution terms are provided in the COPYRIGHT file that must + * be distributed with this source code. + */ +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#include "cstring.h" +#include "markdown.h" +#include "amalloc.h" + +typedef int (*stfu)(const void*,const void*); +typedef void (*spanhandler)(MMIOT*,int); + +/* forward declarations */ +static void text(MMIOT *f); +static Paragraph *display(Paragraph*, MMIOT*); + +/* externals from markdown.c */ +int __mkd_footsort(Footnote *, Footnote *); + +/* + * push text into the generator input buffer + */ +static void +push(char *bfr, int size, MMIOT *f) +{ + while ( size-- > 0 ) + EXPAND(f->in) = *bfr++; +} + + +/* look characters ahead of the cursor. + */ +static inline int +peek(MMIOT *f, int i) +{ + + i += (f->isp-1); + + return (i >= 0) && (i < S(f->in)) ? T(f->in)[i] : EOF; +} + + +/* pull a byte from the input buffer + */ +static inline int +pull(MMIOT *f) +{ + return ( f->isp < S(f->in) ) ? T(f->in)[f->isp++] : EOF; +} + + +/* return a pointer to the current position in the input buffer. + */ +static inline char* +cursor(MMIOT *f) +{ + return T(f->in) + f->isp; +} + + +static inline int +isthisspace(MMIOT *f, int i) +{ + int c = peek(f, i); + + return isspace(c) || (c == EOF); +} + + +static inline int +isthisalnum(MMIOT *f, int i) +{ + int c = peek(f, i); + + return (c != EOF) && isalnum(c); +} + + +static inline int +isthisnonword(MMIOT *f, int i) +{ + return isthisspace(f, i) || ispunct(peek(f,i)); +} + + +/* return/set the current cursor position + */ +#define mmiotseek(f,x) (f->isp = x) +#define mmiottell(f) (f->isp) + + +/* move n characters forward ( or -n characters backward) in the input buffer. + */ +static void +shift(MMIOT *f, int i) +{ + if (f->isp + i >= 0 ) + f->isp += i; +} + + +/* Qchar() + */ +static void +Qchar(int c, MMIOT *f) +{ + block *cur; + + if ( S(f->Q) == 0 ) { + cur = &EXPAND(f->Q); + memset(cur, 0, sizeof *cur); + cur->b_type = bTEXT; + } + else + cur = &T(f->Q)[S(f->Q)-1]; + + EXPAND(cur->b_text) = c; + +} + + +/* Qstring() + */ +static void +Qstring(char *s, MMIOT *f) +{ + while (*s) + Qchar(*s++, f); +} + + +/* Qwrite() + */ +static void +Qwrite(char *s, int size, MMIOT *f) +{ + while (size-- > 0) + Qchar(*s++, f); +} + + +/* Qprintf() + */ +static void +Qprintf(MMIOT *f, char *fmt, ...) +{ + char bfr[80]; + va_list ptr; + + va_start(ptr,fmt); + vsnprintf(bfr, sizeof bfr, fmt, ptr); + va_end(ptr); + Qstring(bfr, f); +} + + +/* Qem() + */ +static void +Qem(MMIOT *f, char c, int count) +{ + block *p = &EXPAND(f->Q); + + memset(p, 0, sizeof *p); + p->b_type = (c == '*') ? bSTAR : bUNDER; + p->b_char = c; + p->b_count = count; + + memset(&EXPAND(f->Q), 0, sizeof(block)); +} + + +/* generate html from a markup fragment + */ +void +___mkd_reparse(char *bfr, int size, int flags, MMIOT *f) +{ + MMIOT sub; + + ___mkd_initmmiot(&sub, f->footnotes); + + sub.flags = f->flags | flags; + sub.cb = f->cb; + sub.ref_prefix = f->ref_prefix; + + push(bfr, size, &sub); + EXPAND(sub.in) = 0; + S(sub.in)--; + + text(&sub); + ___mkd_emblock(&sub); + + Qwrite(T(sub.out), S(sub.out), f); + + ___mkd_freemmiot(&sub, f->footnotes); +} + + +/* + * write out a url, escaping problematic characters + */ +static void +puturl(char *s, int size, MMIOT *f, int display) +{ + unsigned char c; + + while ( size-- > 0 ) { + c = *s++; + + if ( c == '\\' && size-- > 0 ) { + c = *s++; + + if ( !( ispunct(c) || isspace(c) ) ) + Qchar('\\', f); + } + + if ( c == '&' ) + Qstring("&", f); + else if ( c == '<' ) + Qstring("<", f); + else if ( c == '"' ) + Qstring("%22", f); + else if ( isalnum(c) || ispunct(c) || (display && isspace(c)) ) + Qchar(c, f); + else if ( c == 003 ) /* untokenize ^C */ + Qstring(" ", f); + else + Qprintf(f, "%%%02X", c); + } +} + + +/* advance forward until the next character is not whitespace + */ +static int +eatspace(MMIOT *f) +{ + int c; + + for ( ; ((c=peek(f, 1)) != EOF) && isspace(c); pull(f) ) + ; + return c; +} + + +/* (match (a (nested (parenthetical (string.))))) + */ +static int +parenthetical(int in, int out, MMIOT *f) +{ + int size, indent, c; + + for ( indent=1,size=0; indent; size++ ) { + if ( (c = pull(f)) == EOF ) + return EOF; + else if ( (c == '\\') && (peek(f,1) == out || peek(f,1) == in) ) { + ++size; + pull(f); + } + else if ( c == in ) + ++indent; + else if ( c == out ) + --indent; + } + return size ? (size-1) : 0; +} + + +/* extract a []-delimited label from the input stream. + */ +static int +linkylabel(MMIOT *f, Cstring *res) +{ + char *ptr = cursor(f); + int size; + + if ( (size = parenthetical('[',']',f)) != EOF ) { + T(*res) = ptr; + S(*res) = size; + return 1; + } + return 0; +} + + +/* see if the quote-prefixed linky segment is actually a title. + */ +static int +linkytitle(MMIOT *f, char quote, Footnote *ref) +{ + int whence = mmiottell(f); + char *title = cursor(f); + char *e; + register int c; + + while ( (c = pull(f)) != EOF ) { + e = cursor(f); + if ( c == quote ) { + if ( (c = eatspace(f)) == ')' ) { + T(ref->title) = 1+title; + S(ref->title) = (e-title)-2; + return 1; + } + } + } + mmiotseek(f, whence); + return 0; +} + + +/* extract a =HHHxWWW size from the input stream + */ +static int +linkysize(MMIOT *f, Footnote *ref) +{ + int height=0, width=0; + int whence = mmiottell(f); + int c; + + if ( isspace(peek(f,0)) ) { + pull(f); /* eat '=' */ + + for ( c = pull(f); isdigit(c); c = pull(f)) + width = (width * 10) + (c - '0'); + + if ( c == 'x' ) { + for ( c = pull(f); isdigit(c); c = pull(f)) + height = (height*10) + (c - '0'); + + if ( isspace(c) ) + c = eatspace(f); + + if ( (c == ')') || ((c == '\'' || c == '"') && linkytitle(f, c, ref)) ) { + ref->height = height; + ref->width = width; + return 1; + } + } + } + mmiotseek(f, whence); + return 0; +} + + +/* extract a <...>-encased url from the input stream. + * (markdown 1.0.2b8 compatibility; older versions + * of markdown treated the < and > as syntactic + * sugar that didn't have to be there. 1.0.2b8 + * requires a closing >, and then falls into the + * title or closing ) + */ +static int +linkybroket(MMIOT *f, int image, Footnote *p) +{ + int c; + int good = 0; + + T(p->link) = cursor(f); + for ( S(p->link)=0; (c = pull(f)) != '>'; ++S(p->link) ) { + /* pull in all input until a '>' is found, or die trying. + */ + if ( c == EOF ) + return 0; + else if ( (c == '\\') && ispunct(peek(f,2)) ) { + ++S(p->link); + pull(f); + } + } + + c = eatspace(f); + + /* next nonspace needs to be a title, a size, or ) + */ + if ( ( c == '\'' || c == '"' ) && linkytitle(f,c,p) ) + good=1; + else if ( image && (c == '=') && linkysize(f,p) ) + good=1; + else + good=( c == ')' ); + + if ( good ) { + if ( peek(f, 1) == ')' ) + pull(f); + + ___mkd_tidy(&p->link); + } + + return good; +} /* linkybroket */ + + +/* extract a (-prefixed url from the input stream. + * the label is either of the format ``, where I + * extract until I find a >, or it is of the format + * `text`, where I extract until I reach a ')', a quote, + * or (if image) a '=' + */ +static int +linkyurl(MMIOT *f, int image, Footnote *p) +{ + int c; + int mayneedtotrim=0; + + if ( (c = eatspace(f)) == EOF ) + return 0; + + if ( c == '<' ) { + pull(f); + if ( !(f->flags & MKD_1_COMPAT) ) + return linkybroket(f,image,p); + mayneedtotrim=1; + } + + T(p->link) = cursor(f); + for ( S(p->link)=0; (c = peek(f,1)) != ')'; ++S(p->link) ) { + if ( c == EOF ) + return 0; + else if ( (c == '"' || c == '\'') && linkytitle(f, c, p) ) + break; + else if ( image && (c == '=') && linkysize(f, p) ) + break; + else if ( (c == '\\') && ispunct(peek(f,2)) ) { + ++S(p->link); + pull(f); + } + pull(f); + } + if ( peek(f, 1) == ')' ) + pull(f); + + ___mkd_tidy(&p->link); + + if ( mayneedtotrim && (T(p->link)[S(p->link)-1] == '>') ) + --S(p->link); + + return 1; +} + + + +/* prefixes for + */ +static struct _protocol { + char *name; + int nlen; +} protocol[] = { +#define _aprotocol(x) { x, (sizeof x)-1 } + _aprotocol( "https:" ), + _aprotocol( "http:" ), + _aprotocol( "news:" ), + _aprotocol( "ftp:" ), +#undef _aprotocol +}; +#define NRPROTOCOLS (sizeof protocol / sizeof protocol[0]) + + +static int +isautoprefix(char *text, int size) +{ + int i; + struct _protocol *p; + + for (i=0, p=protocol; i < NRPROTOCOLS; i++, p++) + if ( (size >= p->nlen) && strncasecmp(text, p->name, p->nlen) == 0 ) + return 1; + return 0; +} + + +/* + * all the tag types that linkylinky can produce are + * defined by this structure. + */ +typedef struct linkytype { + char *pat; + int szpat; + char *link_pfx; /* tag prefix and link pointer (eg: "" */ + char *text_sfx; /* text suffix (eg: "" */ + int flags; /* reparse flags */ + int kind; /* tag is url or something else? */ +#define IS_URL 0x01 +} linkytype; + +static linkytype imaget = { 0, 0, "\"",", MKD_NOIMAGE|MKD_TAGTEXT, IS_URL }; +static linkytype linkt = { 0, 0, "", "", MKD_NOLINKS, IS_URL }; + +/* + * pseudo-protocols for [][]; + * + * id: generates tag + * class: generates tag + * raw: just dump the link without any processing + */ +static linkytype specials[] = { + { "id:", 3, "", "", 0, 0 }, + { "raw:", 4, 0, 0, 0, 0, 0, MKD_NOHTML, 0 }, + { "lang:", 5, "", "", 0, 0 }, + { "abbr:", 5, "", "", 0, 0 }, + { "class:", 6, "", "", 0, 0 }, +} ; + +#define NR(x) (sizeof x / sizeof x[0]) + +/* see if t contains one of our pseudo-protocols. + */ +static linkytype * +pseudo(Cstring t) +{ + int i; + linkytype *r; + + for ( i=0, r=specials; i < NR(specials); i++,r++ ) { + if ( (S(t) > r->szpat) && (strncasecmp(T(t), r->pat, r->szpat) == 0) ) + return r; + } + return 0; +} + + +/* print out the start of an `img' or `a' tag, applying callbacks as needed. + */ +static void +printlinkyref(MMIOT *f, linkytype *tag, char *link, int size) +{ + char *edit; + + if ( f->flags & IS_LABEL ) + return; + + Qstring(tag->link_pfx, f); + + if ( tag->kind & IS_URL ) { + if ( f->cb && f->cb->e_url && (edit = (*f->cb->e_url)(link, size, f->cb->e_data)) ) { + puturl(edit, strlen(edit), f, 0); + if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data); + } + else + puturl(link + tag->szpat, size - tag->szpat, f, 0); + } + else + ___mkd_reparse(link + tag->szpat, size - tag->szpat, MKD_TAGTEXT, f); + + Qstring(tag->link_sfx, f); + + if ( f->cb && f->cb->e_flags && (edit = (*f->cb->e_flags)(link, size, f->cb->e_data)) ) { + Qchar(' ', f); + Qstring(edit, f); + if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data); + } +} /* printlinkyref */ + + +/* helper function for php markdown extra footnotes; allow the user to + * define a prefix tag instead of just `fn` + */ +static char * +p_or_nothing(p) +MMIOT *p; +{ + return p->ref_prefix ? p->ref_prefix : "fn"; +} + + +/* php markdown extra/daring fireball style print footnotes + */ +static int +extra_linky(MMIOT *f, Cstring text, Footnote *ref) +{ + if ( ref->flags & REFERENCED ) + return 0; + + if ( f->flags & IS_LABEL ) + ___mkd_reparse(T(text), S(text), linkt.flags, f); + else { + ref->flags |= REFERENCED; + ref->refnumber = ++ f->reference; + Qprintf(f, "%d", + p_or_nothing(f), ref->refnumber, + p_or_nothing(f), ref->refnumber, ref->refnumber); + } + return 1; +} /* extra_linky */ + + +/* print out a linky (or fail if it's Not Allowed) + */ +static int +linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref) +{ + linkytype *tag; + + if ( image || (ref == 0) ) + tag = &imaget; + else if ( tag = pseudo(ref->link) ) { + if ( f->flags & (MKD_NO_EXT|MKD_SAFELINK) ) + return 0; + } + else if ( (f->flags & MKD_SAFELINK) && T(ref->link) + && (T(ref->link)[0] != '/') + && !isautoprefix(T(ref->link), S(ref->link)) ) + /* if MKD_SAFELINK, only accept links that are local or + * a well-known protocol + */ + return 0; + else + tag = &linkt; + + if ( f->flags & tag->flags ) + return 0; + + if ( f->flags & IS_LABEL ) + ___mkd_reparse(T(text), S(text), tag->flags, f); + else if ( tag->link_pfx ) { + printlinkyref(f, tag, T(ref->link), S(ref->link)); + + if ( tag->WxH ) { + if ( ref->height ) Qprintf(f," height=\"%d\"", ref->height); + if ( ref->width ) Qprintf(f, " width=\"%d\"", ref->width); + } + + if ( S(ref->title) ) { + Qstring(" title=\"", f); + ___mkd_reparse(T(ref->title), S(ref->title), MKD_TAGTEXT, f); + Qchar('"', f); + } + + Qstring(tag->text_pfx, f); + ___mkd_reparse(T(text), S(text), tag->flags, f); + Qstring(tag->text_sfx, f); + } + else + Qwrite(T(ref->link) + tag->szpat, S(ref->link) - tag->szpat, f); + + return 1; +} /* linkyformat */ + + +/* + * process embedded links and images + */ +static int +linkylinky(int image, MMIOT *f) +{ + int start = mmiottell(f); + Cstring name; + Footnote key, *ref; + + int status = 0; + int extra_footnote = 0; + + CREATE(name); + memset(&key, 0, sizeof key); + + if ( linkylabel(f, &name) ) { + if ( peek(f,1) == '(' ) { + pull(f); + if ( linkyurl(f, image, &key) ) + status = linkyformat(f, name, image, &key); + } + else { + int goodlink, implicit_mark = mmiottell(f); + + if ( isspace(peek(f,1)) ) + pull(f); + + if ( peek(f,1) == '[' ) { + pull(f); /* consume leading '[' */ + goodlink = linkylabel(f, &key.tag); + } + else { + /* new markdown implicit name syntax doesn't + * require a second [] + */ + mmiotseek(f, implicit_mark); + goodlink = !(f->flags & MKD_1_COMPAT); + + if ( (f->flags & MKD_EXTRA_FOOTNOTE) && (!image) && S(name) && T(name)[0] == '^' ) + extra_footnote = 1; + } + + if ( goodlink ) { + if ( !S(key.tag) ) { + DELETE(key.tag); + T(key.tag) = T(name); + S(key.tag) = S(name); + } + + if ( ref = bsearch(&key, T(*f->footnotes), S(*f->footnotes), + sizeof key, (stfu)__mkd_footsort) ) { + if ( extra_footnote ) + status = extra_linky(f,name,ref); + else + status = linkyformat(f, name, image, ref); + } + else if ( f->flags & IS_LABEL ) + status = linkyformat(f, name, image, 0); + } + } + } + + DELETE(name); + ___mkd_freefootnote(&key); + + if ( status == 0 ) + mmiotseek(f, start); + + return status; +} + + +/* write a character to output, doing text escapes ( & -> &, + * > -> > < -> < ) + */ +static void +cputc(int c, MMIOT *f) +{ + switch (c) { + case '&': Qstring("&", f); break; + case '>': Qstring(">", f); break; + case '<': Qstring("<", f); break; + default : Qchar(c, f); break; + } +} + + +/* + * convert an email address to a string of nonsense + */ +static void +mangle(char *s, int len, MMIOT *f) +{ + while ( len-- > 0 ) { + Qstring("&#", f); + Qprintf(f, COINTOSS() ? "x%02x;" : "%02d;", *((unsigned char*)(s++)) ); + } +} + + +/* nrticks() -- count up a row of tick marks + */ +static int +nrticks(int offset, int tickchar, MMIOT *f) +{ + int tick = 0; + + while ( peek(f, offset+tick) == tickchar ) tick++; + + return tick; +} /* nrticks */ + + +/* matchticks() -- match a certain # of ticks, and if that fails + * match the largest subset of those ticks. + * + * if a subset was matched, return the # of ticks + * that were matched. + */ +static int +matchticks(MMIOT *f, int tickchar, int ticks, int *endticks) +{ + int size, count, c; + int subsize=0, subtick=0; + + *endticks = ticks; + for (size = 0; (c=peek(f,size+ticks)) != EOF; size ++) { + if ( (c == tickchar) && ( count = nrticks(size+ticks,tickchar,f)) ) { + if ( count == ticks ) + return size; + else if ( count ) { + if ( (count > subtick) && (count < ticks) ) { + subsize = size; + subtick = count; + } + size += count; + } + } + } + if ( subsize ) { + *endticks = subtick; + return subsize; + } + return 0; +} /* matchticks */ + + +/* code() -- write a string out as code. The only characters that have + * special meaning in a code block are * `<' and `&' , which + * are /always/ expanded to < and & + */ +static void +code(MMIOT *f, char *s, int length) +{ + int i,c; + + for ( i=0; i < length; i++ ) + if ( (c = s[i]) == 003) /* ^C: expand back to 2 spaces */ + Qstring(" ", f); + else + cputc(c, f); +} /* code */ + + +/* delspan() -- write out a chunk of text, blocking with ... + */ +static void +delspan(MMIOT *f, int size) +{ + Qstring("", f); + ___mkd_reparse(cursor(f)-1, size, 0, f); + Qstring("", f); +} + + +/* codespan() -- write out a chunk of text as code, trimming one + * space off the front and/or back as appropriate. + */ +static void +codespan(MMIOT *f, int size) +{ + int i=0; + + if ( size > 1 && peek(f, size-1) == ' ' ) --size; + if ( peek(f,i) == ' ' ) ++i, --size; + + Qstring("", f); + code(f, cursor(f)+(i-1), size); + Qstring("", f); +} /* codespan */ + + +/* before letting a tag through, validate against + * MKD_NOLINKS and MKD_NOIMAGE + */ +static int +forbidden_tag(MMIOT *f) +{ + int c = toupper(peek(f, 1)); + + if ( f->flags & MKD_NOHTML ) + return 1; + + if ( c == 'A' && (f->flags & MKD_NOLINKS) && !isthisalnum(f,2) ) + return 1; + if ( c == 'I' && (f->flags & MKD_NOIMAGE) + && strncasecmp(cursor(f)+1, "MG", 2) == 0 + && !isthisalnum(f,4) ) + return 1; + return 0; +} + + +/* Check a string to see if it looks like a mail address + * "looks like a mail address" means alphanumeric + some + * specials, then a `@`, then alphanumeric + some specials, + * but with a `.` + */ +static int +maybe_address(char *p, int size) +{ + int ok = 0; + + for ( ;size && (isalnum(*p) || strchr("._-+*", *p)); ++p, --size) + ; + + if ( ! (size && *p == '@') ) + return 0; + + --size, ++p; + + if ( size && *p == '.' ) return 0; + + for ( ;size && (isalnum(*p) || strchr("._-+", *p)); ++p, --size ) + if ( *p == '.' && size > 1 ) ok = 1; + + return size ? 0 : ok; +} + + +/* The size-length token at cursor(f) is either a mailto:, an + * implicit mailto:, one of the approved url protocols, or just + * plain old text. If it's a mailto: or an approved protocol, + * linkify it, otherwise say "no" + */ +static int +process_possible_link(MMIOT *f, int size) +{ + int address= 0; + int mailto = 0; + char *text = cursor(f); + + if ( f->flags & MKD_NOLINKS ) return 0; + + if ( (size > 7) && strncasecmp(text, "mailto:", 7) == 0 ) { + /* if it says it's a mailto, it's a mailto -- who am + * I to second-guess the user? + */ + address = 1; + mailto = 7; /* 7 is the length of "mailto:"; we need this */ + } + else + address = maybe_address(text, size); + + if ( address ) { + Qstring("", f); + mangle(text+mailto, size-mailto, f); + Qstring("", f); + return 1; + } + else if ( isautoprefix(text, size) ) { + printlinkyref(f, &linkt, text, size); + Qchar('>', f); + puturl(text,size,f, 1); + Qstring("", f); + return 1; + } + return 0; +} /* process_possible_link */ + + +/* a < may be just a regular character, the start of an embedded html + * tag, or the start of an . If it's an automatic + * link, we also need to know if it's an email address because if it + * is we need to mangle it in our futile attempt to cut down on the + * spaminess of the rendered page. + */ +static int +maybe_tag_or_link(MMIOT *f) +{ + int c, size; + int maybetag = 1; + + if ( f->flags & MKD_TAGTEXT ) + return 0; + + for ( size=0; (c = peek(f, size+1)) != '>'; size++) { + if ( c == EOF ) + return 0; + else if ( c == '\\' ) { + maybetag=0; + if ( peek(f, size+2) != EOF ) + size++; + } + else if ( isspace(c) ) + break; +#if WITH_GITHUB_TAGS + else if ( ! (c == '/' || c == '-' || c == '_' || isalnum(c) ) ) +#else + else if ( ! (c == '/' || isalnum(c) ) ) +#endif + maybetag=0; + } + + if ( size ) { + if ( maybetag || (size >= 3 && strncmp(cursor(f), "!--", 3) == 0) ) { + + /* It is not a html tag unless we find the closing '>' in + * the same block. + */ + while ( (c = peek(f, size+1)) != '>' ) + if ( c == EOF ) + return 0; + else + size++; + + if ( forbidden_tag(f) ) + return 0; + + Qchar('<', f); + while ( ((c = peek(f, 1)) != EOF) && (c != '>') ) + Qchar(pull(f), f); + return 1; + } + else if ( !isspace(c) && process_possible_link(f, size) ) { + shift(f, size+1); + return 1; + } + } + + return 0; +} + + +/* autolinking means that all inline html is . A + * autolink url is alphanumerics, slashes, periods, underscores, + * the at sign, colon, and the % character. + */ +static int +maybe_autolink(MMIOT *f) +{ + register int c; + int size; + + /* greedily scan forward for the end of a legitimate link. + */ + for ( size=0; (c=peek(f, size+1)) != EOF; size++ ) + if ( c == '\\' ) { + if ( peek(f, size+2) != EOF ) + ++size; + } + else if ( isspace(c) || strchr("'\"()[]{}<>`", c) ) + break; + + if ( (size > 1) && process_possible_link(f, size) ) { + shift(f, size); + return 1; + } + return 0; +} + + +/* smartyquote code that's common for single and double quotes + */ +static int +smartyquote(int *flags, char typeofquote, MMIOT *f) +{ + int bit = (typeofquote == 's') ? 0x01 : 0x02; + + if ( bit & (*flags) ) { + if ( isthisnonword(f,1) ) { + Qprintf(f, "&r%cquo;", typeofquote); + (*flags) &= ~bit; + return 1; + } + } + else if ( isthisnonword(f,-1) && peek(f,1) != EOF ) { + Qprintf(f, "&l%cquo;", typeofquote); + (*flags) |= bit; + return 1; + } + return 0; +} + + +static int +islike(MMIOT *f, char *s) +{ + int len; + int i; + + if ( s[0] == '<' ) { + if ( !isthisnonword(f, -1) ) + return 0; + ++s; + } + + if ( !(len = strlen(s)) ) + return 0; + + if ( s[len-1] == '>' ) { + if ( !isthisnonword(f,len-1) ) + return 0; + len--; + } + + for (i=1; i < len; i++) + if (tolower(peek(f,i)) != s[i]) + return 0; + return 1; +} + + +static struct smarties { + char c0; + char *pat; + char *entity; + int shift; +} smarties[] = { + { '\'', "'s>", "rsquo", 0 }, + { '\'', "'t>", "rsquo", 0 }, + { '\'', "'re>", "rsquo", 0 }, + { '\'', "'ll>", "rsquo", 0 }, + { '\'', "'ve>", "rsquo", 0 }, + { '\'', "'m>", "rsquo", 0 }, + { '\'', "'d>", "rsquo", 0 }, + { '-', "---", "mdash", 2 }, + { '-', "--", "ndash", 1 }, + { '.', "...", "hellip", 2 }, + { '.', ". . .", "hellip", 4 }, + { '(', "(c)", "copy", 2 }, + { '(', "(r)", "reg", 2 }, + { '(', "(tm)", "trade", 3 }, + { '3', "<3/4>", "frac34", 2 }, + { '3', "<3/4ths>", "frac34", 2 }, + { '1', "<1/2>", "frac12", 2 }, + { '1', "<1/4>", "frac14", 2 }, + { '1', "<1/4th>", "frac14", 2 }, + { '&', "�", 0, 3 }, +} ; +#define NRSMART ( sizeof smarties / sizeof smarties[0] ) + + +/* Smarty-pants-style chrome for quotes, -, ellipses, and (r)(c)(tm) + */ +static int +smartypants(int c, int *flags, MMIOT *f) +{ + int i; + + if ( f->flags & (MKD_NOPANTS|MKD_TAGTEXT|IS_LABEL) ) + return 0; + + for ( i=0; i < NRSMART; i++) + if ( (c == smarties[i].c0) && islike(f, smarties[i].pat) ) { + if ( smarties[i].entity ) + Qprintf(f, "&%s;", smarties[i].entity); + shift(f, smarties[i].shift); + return 1; + } + + switch (c) { + case '<' : return 0; + case '\'': if ( smartyquote(flags, 's', f) ) return 1; + break; + + case '"': if ( smartyquote(flags, 'd', f) ) return 1; + break; + + case '`': if ( peek(f, 1) == '`' ) { + int j = 2; + + while ( (c=peek(f,j)) != EOF ) { + if ( c == '\\' ) + j += 2; + else if ( c == '`' ) + break; + else if ( c == '\'' && peek(f, j+1) == '\'' ) { + Qstring("“", f); + ___mkd_reparse(cursor(f)+1, j-2, 0, f); + Qstring("”", f); + shift(f,j+1); + return 1; + } + else ++j; + } + + } + break; + } + return 0; +} /* smartypants */ + + +/* process a body of text encased in some sort of tick marks. If it + * works, generate the output and return 1, otherwise just return 0 and + * let the caller figure it out. + */ +static int +tickhandler(MMIOT *f, int tickchar, int minticks, int allow_space, spanhandler spanner) +{ + int endticks, size; + int tick = nrticks(0, tickchar, f); + + if ( !allow_space && isspace(peek(f,tick)) ) + return 0; + + if ( (tick >= minticks) && (size = matchticks(f,tickchar,tick,&endticks)) ) { + if ( endticks < tick ) { + size += (tick - endticks); + tick = endticks; + } + + shift(f, tick); + (*spanner)(f,size); + shift(f, size+tick-1); + return 1; + } + return 0; +} + +#define tag_text(f) (f->flags & MKD_TAGTEXT) + + +static void +text(MMIOT *f) +{ + int c, j; + int rep; + int smartyflags = 0; + + while (1) { + if ( (f->flags & MKD_AUTOLINK) && isalpha(peek(f,1)) && !tag_text(f) ) + maybe_autolink(f); + + c = pull(f); + + if (c == EOF) + break; + + if ( smartypants(c, &smartyflags, f) ) + continue; + switch (c) { + case 0: break; + + case 3: Qstring(tag_text(f) ? " " : "
", f); + break; + + case '>': if ( tag_text(f) ) + Qstring(">", f); + else + Qchar(c, f); + break; + + case '"': if ( tag_text(f) ) + Qstring(""", f); + else + Qchar(c, f); + break; + + case '!': if ( peek(f,1) == '[' ) { + pull(f); + if ( tag_text(f) || !linkylinky(1, f) ) + Qstring("![", f); + } + else + Qchar(c, f); + break; + case '[': if ( tag_text(f) || !linkylinky(0, f) ) + Qchar(c, f); + break; + /* A^B -> AB */ + case '^': if ( (f->flags & (MKD_NOSUPERSCRIPT|MKD_STRICT|MKD_TAGTEXT)) + || (isthisnonword(f,-1) && peek(f,-1) != ')') + || isthisspace(f,1) ) + Qchar(c,f); + else { + char *sup = cursor(f); + int len = 0; + + if ( peek(f,1) == '(' ) { + int here = mmiottell(f); + pull(f); + + if ( (len = parenthetical('(',')',f)) <= 0 ) { + mmiotseek(f,here); + Qchar(c, f); + break; + } + sup++; + } + else { + while ( isthisalnum(f,1+len) ) + ++len; + if ( !len ) { + Qchar(c,f); + break; + } + shift(f,len); + } + Qstring("",f); + ___mkd_reparse(sup, len, 0, f); + Qstring("", f); + } + break; + case '_': + /* Underscores don't count if they're in the middle of a word */ + if ( !(f->flags & (MKD_NORELAXED|MKD_STRICT)) + && isthisalnum(f,-1) + && isthisalnum(f,1) ) { + Qchar(c, f); + break; + } + case '*': + /* Underscores & stars don't count if they're out in the middle + * of whitespace */ + if ( isthisspace(f,-1) && isthisspace(f,1) ) { + Qchar(c, f); + break; + } + /* else fall into the regular old emphasis case */ + if ( tag_text(f) ) + Qchar(c, f); + else { + for (rep = 1; peek(f,1) == c; pull(f) ) + ++rep; + Qem(f,c,rep); + } + break; + + case '~': if ( (f->flags & (MKD_NOSTRIKETHROUGH|MKD_TAGTEXT|MKD_STRICT)) || ! tickhandler(f,c,2,0, delspan) ) + Qchar(c, f); + break; + + case '`': if ( tag_text(f) || !tickhandler(f,c,1,1,codespan) ) + Qchar(c, f); + break; + + case '\\': switch ( c = pull(f) ) { + case '&': Qstring("&", f); + break; + case '<': Qstring("<", f); + break; + case '^': if ( f->flags & (MKD_STRICT|MKD_NOSUPERSCRIPT) ) { + Qchar('\\', f); + shift(f,-1); + break; + } + Qchar(c, f); + break; + + case ':': case '|': + if ( f->flags & MKD_NOTABLES ) { + Qchar('\\', f); + shift(f,-1); + break; + } + Qchar(c, f); + break; + + case '>': case '#': case '.': case '-': + case '+': case '{': case '}': case ']': + case '!': case '[': case '*': case '_': + case '\\':case '(': case ')': + case '`': Qchar(c, f); + break; + default: + Qchar('\\', f); + if ( c != EOF ) + shift(f,-1); + break; + } + break; + + case '<': if ( !maybe_tag_or_link(f) ) + Qstring("<", f); + break; + + case '&': j = (peek(f,1) == '#' ) ? 2 : 1; + while ( isthisalnum(f,j) ) + ++j; + + if ( peek(f,j) != ';' ) + Qstring("&", f); + else + Qchar(c, f); + break; + + default: Qchar(c, f); + break; + } + } + /* truncate the input string after we've finished processing it */ + S(f->in) = f->isp = 0; +} /* text */ + + +/* print a header block + */ +static void +printheader(Paragraph *pp, MMIOT *f) +{ +#if WITH_ID_ANCHOR + Qprintf(f, "hnumber); + if ( f->flags & MKD_TOC ) { + Qstring(" id=\"", f); + mkd_string_to_anchor(T(pp->text->text), + S(pp->text->text), + (mkd_sta_function_t)Qchar, f, 1); + Qchar('"', f); + } + Qchar('>', f); +#else + if ( f->flags & MKD_TOC ) { + Qstring("
text->text), + S(pp->text->text), + (mkd_sta_function_t)Qchar, f, 1); + Qstring("\">\n", f); + } + Qprintf(f, "", pp->hnumber); +#endif + push(T(pp->text->text), S(pp->text->text), f); + text(f); + Qprintf(f, "", pp->hnumber); +} + + +enum e_alignments { a_NONE, a_CENTER, a_LEFT, a_RIGHT }; + +static char* alignments[] = { "", " align=\"center\"", " align=\"left\"", + " align=\"right\"" }; + +typedef STRING(int) Istring; + +static int +splat(Line *p, char *block, Istring align, int force, MMIOT *f) +{ + int first, + idx = p->dle, + colno = 0; + + + ___mkd_tidy(&p->text); + if ( T(p->text)[S(p->text)-1] == '|' ) + --S(p->text); + + Qstring("\n", f); + while ( idx < S(p->text) ) { + first = idx; + if ( force && (colno >= S(align)-1) ) + idx = S(p->text); + else + while ( (idx < S(p->text)) && (T(p->text)[idx] != '|') ) { + if ( T(p->text)[idx] == '\\' ) + ++idx; + ++idx; + } + + Qprintf(f, "<%s%s>", + block, + alignments[ (colno < S(align)) ? T(align)[colno] : a_NONE ]); + ___mkd_reparse(T(p->text)+first, idx-first, 0, f); + Qprintf(f, "\n", block); + idx++; + colno++; + } + if ( force ) + while (colno < S(align) ) { + Qprintf(f, "<%s>\n", block, block); + ++colno; + } + Qstring("\n", f); + return colno; +} + + +static int +printtable(Paragraph *pp, MMIOT *f) +{ + /* header, dashes, then lines of content */ + + Line *hdr, *dash, *body; + Istring align; + int hcols,start; + char *p; + enum e_alignments it; + + hdr = pp->text; + dash= hdr->next; + body= dash->next; + + if ( T(hdr->text)[hdr->dle] == '|' ) { + /* trim leading pipe off all lines + */ + Line *r; + for ( r = pp->text; r; r = r->next ) + r->dle ++; + } + + /* figure out cell alignments */ + + CREATE(align); + + for (p=T(dash->text), start=dash->dle; start < S(dash->text); ) { + char first, last; + int end; + + last=first=0; + for (end=start ; (end < S(dash->text)) && p[end] != '|'; ++ end ) { + if ( p[end] == '\\' ) + ++ end; + else if ( !isspace(p[end]) ) { + if ( !first) first = p[end]; + last = p[end]; + } + } + it = ( first == ':' ) ? (( last == ':') ? a_CENTER : a_LEFT) + : (( last == ':') ? a_RIGHT : a_NONE ); + + EXPAND(align) = it; + start = 1+end; + } + + Qstring("\n", f); + Qstring("\n", f); + hcols = splat(hdr, "th", align, 0, f); + Qstring("\n", f); + + if ( hcols < S(align) ) + S(align) = hcols; + else + while ( hcols > S(align) ) + EXPAND(align) = a_NONE; + + Qstring("\n", f); + for ( ; body; body = body->next) + splat(body, "td", align, 1, f); + Qstring("\n", f); + Qstring("
\n", f); + + DELETE(align); + return 1; +} + + +static int +printblock(Paragraph *pp, MMIOT *f) +{ + Line *t = pp->text; + static char *Begin[] = { "", "

", "

" }; + static char *End[] = { "", "

","

" }; + + while (t) { + if ( S(t->text) ) { + if ( t->next && S(t->text) > 2 + && T(t->text)[S(t->text)-2] == ' ' + && T(t->text)[S(t->text)-1] == ' ' ) { + push(T(t->text), S(t->text)-2, f); + push("\003\n", 2, f); + } + else { + ___mkd_tidy(&t->text); + push(T(t->text), S(t->text), f); + if ( t->next ) + push("\n", 1, f); + } + } + t = t->next; + } + Qstring(Begin[pp->align], f); + text(f); + Qstring(End[pp->align], f); + return 1; +} + + +static void +printcode(Line *t, MMIOT *f) +{ + int blanks; + + Qstring("
", f);
+    for ( blanks = 0; t ; t = t->next ) {
+	if ( S(t->text) > t->dle ) {
+	    while ( blanks ) {
+		Qchar('\n', f);
+		--blanks;
+	    }
+	    code(f, T(t->text), S(t->text));
+	    Qchar('\n', f);
+	}
+	else blanks++;
+    }
+    Qstring("
", f); +} + + +static void +printhtml(Line *t, MMIOT *f) +{ + int blanks; + + for ( blanks=0; t ; t = t->next ) + if ( S(t->text) ) { + for ( ; blanks; --blanks ) + Qchar('\n', f); + + Qwrite(T(t->text), S(t->text), f); + Qchar('\n', f); + } + else + blanks++; +} + + +static void +htmlify(Paragraph *p, char *block, char *arguments, MMIOT *f) +{ + ___mkd_emblock(f); + if ( block ) + Qprintf(f, arguments ? "<%s %s>" : "<%s>", block, arguments); + ___mkd_emblock(f); + + while (( p = display(p, f) )) { + ___mkd_emblock(f); + Qstring("\n\n", f); + } + + if ( block ) + Qprintf(f, "", block); + ___mkd_emblock(f); +} + + +static void +definitionlist(Paragraph *p, MMIOT *f) +{ + Line *tag; + + if ( p ) { + Qstring("
\n", f); + + for ( ; p ; p = p->next) { + for ( tag = p->text; tag; tag = tag->next ) { + Qstring("
", f); + ___mkd_reparse(T(tag->text), S(tag->text), 0, f); + Qstring("
\n", f); + } + + htmlify(p->down, "dd", p->ident, f); + Qchar('\n', f); + } + + Qstring("
", f); + } +} + + +static void +listdisplay(int typ, Paragraph *p, MMIOT* f) +{ + if ( p ) { + Qprintf(f, "<%cl", (typ==UL)?'u':'o'); + if ( typ == AL ) + Qprintf(f, " type=\"a\""); + Qprintf(f, ">\n"); + + for ( ; p ; p = p->next ) { + htmlify(p->down, "li", p->ident, f); + Qchar('\n', f); + } + + Qprintf(f, "\n", (typ==UL)?'u':'o'); + } +} + + +/* dump out a Paragraph in the desired manner + */ +static Paragraph* +display(Paragraph *p, MMIOT *f) +{ + if ( !p ) return 0; + + switch ( p->typ ) { + case STYLE: + case WHITESPACE: + break; + + case HTML: + printhtml(p->text, f); + break; + + case CODE: + printcode(p->text, f); + break; + + case QUOTE: + htmlify(p->down, p->ident ? "div" : "blockquote", p->ident, f); + break; + + case UL: + case OL: + case AL: + listdisplay(p->typ, p->down, f); + break; + + case DL: + definitionlist(p->down, f); + break; + + case HR: + Qstring("
", f); + break; + + case HDR: + printheader(p, f); + break; + + case TABLE: + printtable(p, f); + break; + + case SOURCE: + htmlify(p->down, 0, 0, f); + break; + + default: + printblock(p, f); + break; + } + return p->next; +} + + +/* dump out a list of footnotes + */ +static void +mkd_extra_footnotes(MMIOT *m) +{ + int j, i; + Footnote *t; + + if ( m->reference == 0 ) + return; + + Csprintf(&m->out, "\n
\n
\n
    \n"); + + for ( i=1; i <= m->reference; i++ ) { + for ( j=0; j < S(*m->footnotes); j++ ) { + t = &T(*m->footnotes)[j]; + if ( (t->refnumber == i) && (t->flags & REFERENCED) ) { + Csprintf(&m->out, "
  1. \n

    ", + p_or_nothing(m), t->refnumber); + Csreparse(&m->out, T(t->title), S(t->title), 0); + Csprintf(&m->out, "", + p_or_nothing(m), t->refnumber); + Csprintf(&m->out, "

  2. \n"); + } + } + } + Csprintf(&m->out, "
\n
\n"); +} + + +/* return a pointer to the compiled markdown + * document. + */ +int +mkd_document(Document *p, char **res) +{ + int size; + + if ( p && p->compiled ) { + if ( ! p->html ) { + htmlify(p->code, 0, 0, p->ctx); + if ( p->ctx->flags & MKD_EXTRA_FOOTNOTE ) + mkd_extra_footnotes(p->ctx); + p->html = 1; + } + + size = S(p->ctx->out); + + if ( (size == 0) || T(p->ctx->out)[size-1] ) + EXPAND(p->ctx->out) = 0; + + *res = T(p->ctx->out); + return size; + } + return EOF; +} + diff --git a/markdown/discount/html5.c b/markdown/discount/html5.c new file mode 100644 index 000000000..de91b901c --- /dev/null +++ b/markdown/discount/html5.c @@ -0,0 +1,22 @@ +/* block-level tags for passing html5 blocks through the blender + */ +#include "tags.h" + +void +mkd_with_html5_tags() +{ + static int populated = 0; + + if ( populated ) return; + populated = 1; + + mkd_define_tag("ASIDE", 0); + mkd_define_tag("FOOTER", 0); + mkd_define_tag("HEADER", 0); + mkd_define_tag("HGROUP", 0); + mkd_define_tag("NAV", 0); + mkd_define_tag("SECTION", 0); + mkd_define_tag("ARTICLE", 0); + + mkd_sort_tags(); +} diff --git a/markdown/discount/markdown.c b/markdown/discount/markdown.c new file mode 100644 index 000000000..6f1705ad9 --- /dev/null +++ b/markdown/discount/markdown.c @@ -0,0 +1,1302 @@ +/* markdown: a C implementation of John Gruber's Markdown markup language. + * + * Copyright (C) 2007 David L Parsons. + * The redistribution terms are provided in the COPYRIGHT file that must + * be distributed with this source code. + */ +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "cstring.h" +#include "markdown.h" +#include "amalloc.h" +#include "tags.h" + +typedef int (*stfu)(const void*,const void*); + +typedef ANCHOR(Paragraph) ParagraphRoot; + +static Paragraph *Pp(ParagraphRoot *, Line *, int); +static Paragraph *compile(Line *, int, MMIOT *); + +/* case insensitive string sort for Footnote tags. + */ +int +__mkd_footsort(Footnote *a, Footnote *b) +{ + int i; + char ac, bc; + + if ( S(a->tag) != S(b->tag) ) + return S(a->tag) - S(b->tag); + + for ( i=0; i < S(a->tag); i++) { + ac = tolower(T(a->tag)[i]); + bc = tolower(T(b->tag)[i]); + + if ( isspace(ac) && isspace(bc) ) + continue; + if ( ac != bc ) + return ac - bc; + } + return 0; +} + + +/* find the first blank character after position + */ +static int +nextblank(Line *t, int i) +{ + while ( (i < S(t->text)) && !isspace(T(t->text)[i]) ) + ++i; + return i; +} + + +/* find the next nonblank character after position + */ +static int +nextnonblank(Line *t, int i) +{ + while ( (i < S(t->text)) && isspace(T(t->text)[i]) ) + ++i; + return i; +} + + +/* find the first nonblank character on the Line. + */ +int +mkd_firstnonblank(Line *p) +{ + return nextnonblank(p,0); +} + + +static inline int +blankline(Line *p) +{ + return ! (p && (S(p->text) > p->dle) ); +} + + +static Line * +skipempty(Line *p) +{ + while ( p && (p->dle == S(p->text)) ) + p = p->next; + return p; +} + + +void +___mkd_tidy(Cstring *t) +{ + while ( S(*t) && isspace(T(*t)[S(*t)-1]) ) + --S(*t); +} + + +static struct kw comment = { "!--", 3, 0 }; + +static struct kw * +isopentag(Line *p) +{ + int i=0, len; + char *line; + + if ( !p ) return 0; + + line = T(p->text); + len = S(p->text); + + if ( len < 3 || line[0] != '<' ) + return 0; + + if ( line[1] == '!' && line[2] == '-' && line[3] == '-' ) + /* comments need special case handling, because + * the !-- doesn't need to end in a whitespace + */ + return &comment; + + /* find how long the tag is so we can check to see if + * it's a block-level tag + */ + for ( i=1; i < len && T(p->text)[i] != '>' + && T(p->text)[i] != '/' + && !isspace(T(p->text)[i]); ++i ) + ; + + + return mkd_search_tags(T(p->text)+1, i-1); +} + + +typedef struct _flo { + Line *t; + int i; +} FLO; + +#define floindex(x) (x.i) + + +static int +flogetc(FLO *f) +{ + if ( f && f->t ) { + if ( f->i < S(f->t->text) ) + return T(f->t->text)[f->i++]; + f->t = f->t->next; + f->i = 0; + return flogetc(f); + } + return EOF; +} + + +static void +splitline(Line *t, int cutpoint) +{ + if ( t && (cutpoint < S(t->text)) ) { + Line *tmp = calloc(1, sizeof *tmp); + + tmp->next = t->next; + t->next = tmp; + + tmp->dle = t->dle; + SUFFIX(tmp->text, T(t->text)+cutpoint, S(t->text)-cutpoint); + S(t->text) = cutpoint; + } +} + +#define UNCHECK(l) ((l)->flags &= ~CHECKED) + +/* + * walk a line, seeing if it's any of half a dozen interesting regular + * types. + */ +static void +checkline(Line *l) +{ + int eol, i; + int dashes = 0, spaces = 0, + equals = 0, underscores = 0, + stars = 0, tildes = 0; + + l->flags |= CHECKED; + l->kind = chk_text; + l->count = 0; + + if (l->dle >= 4) { l->kind=chk_code; return; } + + for ( eol = S(l->text); eol > l->dle && isspace(T(l->text)[eol-1]); --eol ) + ; + + for (i=l->dle; itext)[i]; + + if ( c != ' ' ) l->count++; + + switch (c) { + case '-': dashes = 1; break; + case ' ': spaces = 1; break; + case '=': equals = 1; break; + case '_': underscores = 1; break; + case '*': stars = 1; break; + case '~': tildes = 1; break; + default: return; + } + } + + if ( dashes + equals + underscores + stars + tildes > 1 ) + return; + + if ( spaces ) { + if ( (underscores || stars || dashes) ) + l->kind = chk_hr; + return; + } + + if ( stars || underscores ) { l->kind = chk_hr; } + else if ( dashes ) { l->kind = chk_dash; } + else if ( tildes ) { l->kind = chk_tilde; } + else if ( equals ) { l->kind = chk_equal; } +} + + + +static Line * +commentblock(Paragraph *p, int *unclosed) +{ + Line *t, *ret; + char *end; + + for ( t = p->text; t ; t = t->next) { + if ( end = strstr(T(t->text), "-->") ) { + splitline(t, 3 + (end - T(t->text)) ); + ret = t->next; + t->next = 0; + return ret; + } + } + *unclosed = 1; + return t; + +} + + +static Line * +htmlblock(Paragraph *p, struct kw *tag, int *unclosed) +{ + Line *ret; + FLO f = { p->text, 0 }; + int c; + int i, closing, depth=0; + + *unclosed = 0; + + if ( tag == &comment ) + return commentblock(p, unclosed); + + if ( tag->selfclose ) { + ret = f.t->next; + f.t->next = 0; + return ret; + } + + while ( (c = flogetc(&f)) != EOF ) { + if ( c == '<' ) { + /* tag? */ + c = flogetc(&f); + if ( c == '!' ) { /* comment? */ + if ( flogetc(&f) == '-' && flogetc(&f) == '-' ) { + /* yes */ + while ( (c = flogetc(&f)) != EOF ) { + if ( c == '-' && flogetc(&f) == '-' + && flogetc(&f) == '>') + /* consumed whole comment */ + break; + } + } + } + else { + if ( closing = (c == '/') ) c = flogetc(&f); + + for ( i=0; i < tag->size; c=flogetc(&f) ) { + if ( tag->id[i++] != toupper(c) ) + break; + } + + if ( (i == tag->size) && !isalnum(c) ) { + depth = depth + (closing ? -1 : 1); + if ( depth == 0 ) { + while ( c != EOF && c != '>' ) { + /* consume trailing gunk in close tag */ + c = flogetc(&f); + } + if ( c == EOF ) + break; + if ( !f.t ) + return 0; + splitline(f.t, floindex(f)); + ret = f.t->next; + f.t->next = 0; + return ret; + } + } + } + } + } + *unclosed = 1; + return 0; +} + + +/* footnotes look like ^{0,3}[stuff]: $ + */ +static int +isfootnote(Line *t) +{ + int i; + + if ( ( (i = t->dle) > 3) || (T(t->text)[i] != '[') ) + return 0; + + for ( ++i; i < S(t->text) ; ++i ) { + if ( T(t->text)[i] == '[' ) + return 0; + else if ( T(t->text)[i] == ']' ) + return ( T(t->text)[i+1] == ':' ) ; + } + return 0; +} + + +static inline int +isquote(Line *t) +{ + return (t->dle < 4 && T(t->text)[t->dle] == '>'); +} + + +static inline int +iscode(Line *t) +{ + return (t->dle >= 4); +} + + +static inline int +ishr(Line *t) +{ + if ( ! (t->flags & CHECKED) ) + checkline(t); + + if ( t->count > 2 ) + return t->kind == chk_hr || t->kind == chk_dash || t->kind == chk_equal; + return 0; +} + + +static int +issetext(Line *t, int *htyp) +{ + Line *n; + + /* check for setext-style HEADER + * ====== + */ + + if ( (n = t->next) ) { + if ( !(n->flags & CHECKED) ) + checkline(n); + + if ( n->kind == chk_dash || n->kind == chk_equal ) { + *htyp = SETEXT; + return 1; + } + } + return 0; +} + + +static int +ishdr(Line *t, int *htyp) +{ + /* ANY leading `#`'s make this into an ETX header + */ + if ( (t->dle == 0) && (S(t->text) > 1) && (T(t->text)[0] == '#') ) { + *htyp = ETX; + return 1; + } + + /* And if not, maybe it's a SETEXT header instead + */ + return issetext(t, htyp); +} + + +static inline int +end_of_block(Line *t) +{ + int dummy; + + if ( !t ) + return 0; + + return ( (S(t->text) <= t->dle) || ishr(t) || ishdr(t, &dummy) ); +} + + +static Line* +is_discount_dt(Line *t, int *clip) +{ +#if USE_DISCOUNT_DL + if ( t && t->next + && (S(t->text) > 2) + && (t->dle == 0) + && (T(t->text)[0] == '=') + && (T(t->text)[S(t->text)-1] == '=') ) { + if ( t->next->dle >= 4 ) { + *clip = 4; + return t; + } + else + return is_discount_dt(t->next, clip); + } +#endif + return 0; +} + + +static int +is_extra_dd(Line *t) +{ + return (t->dle < 4) && (T(t->text)[t->dle] == ':') + && isspace(T(t->text)[t->dle+1]); +} + + +static Line* +is_extra_dt(Line *t, int *clip) +{ +#if USE_EXTRA_DL + + if ( t && t->next && T(t->text)[0] != '=' + && T(t->text)[S(t->text)-1] != '=') { + Line *x; + + if ( iscode(t) || end_of_block(t) ) + return 0; + + if ( (x = skipempty(t->next)) && is_extra_dd(x) ) { + *clip = x->dle+2; + return t; + } + + if ( x=is_extra_dt(t->next, clip) ) + return x; + } +#endif + return 0; +} + + +static Line* +isdefinition(Line *t, int *clip, int *kind) +{ + Line *ret; + + *kind = 1; + if ( ret = is_discount_dt(t,clip) ) + return ret; + + *kind=2; + return is_extra_dt(t,clip); +} + + +static int +islist(Line *t, int *clip, DWORD flags, int *list_type) +{ + int i, j; + char *q; + + if ( end_of_block(t) ) + return 0; + + if ( !(flags & (MKD_NODLIST|MKD_STRICT)) && isdefinition(t,clip,list_type) ) + return DL; + + if ( strchr("*-+", T(t->text)[t->dle]) && isspace(T(t->text)[t->dle+1]) ) { + i = nextnonblank(t, t->dle+1); + *clip = (i > 4) ? 4 : i; + *list_type = UL; + return AL; + } + + if ( (j = nextblank(t,t->dle)) > t->dle ) { + if ( T(t->text)[j-1] == '.' ) { + + if ( !(flags & (MKD_NOALPHALIST|MKD_STRICT)) + && (j == t->dle + 2) + && isalpha(T(t->text)[t->dle]) ) { + j = nextnonblank(t,j); + *clip = (j > 4) ? 4 : j; + *list_type = AL; + return AL; + } + + unsigned long res = strtoul(T(t->text)+t->dle, &q, 10); + if ( (q > T(t->text)+t->dle) && (q == T(t->text) + (j-1)) ) { + j = nextnonblank(t,j); + *clip = (j > 4) ? 4 : j; + *list_type = OL; + return AL; + } + } + } + return 0; +} + + +static Line * +headerblock(Paragraph *pp, int htyp) +{ + Line *ret = 0; + Line *p = pp->text; + int i, j; + + switch (htyp) { + case SETEXT: + /* p->text is header, p->next->text is -'s or ='s + */ + pp->hnumber = (T(p->next->text)[0] == '=') ? 1 : 2; + + ret = p->next->next; + ___mkd_freeLine(p->next); + p->next = 0; + break; + + case ETX: + /* p->text is ###header###, so we need to trim off + * the leading and trailing `#`'s + */ + + for (i=0; (T(p->text)[i] == T(p->text)[0]) && (i < S(p->text)-1) + && (i < 6); i++) + ; + + pp->hnumber = i; + + while ( (i < S(p->text)) && isspace(T(p->text)[i]) ) + ++i; + + CLIP(p->text, 0, i); + UNCHECK(p); + + for (j=S(p->text); (j > 1) && (T(p->text)[j-1] == '#'); --j) + ; + + while ( j && isspace(T(p->text)[j-1]) ) + --j; + + S(p->text) = j; + + ret = p->next; + p->next = 0; + break; + } + return ret; +} + + +static Line * +codeblock(Paragraph *p) +{ + Line *t = p->text, *r; + + for ( ; t; t = r ) { + CLIP(t->text,0,4); + t->dle = mkd_firstnonblank(t); + + if ( !( (r = skipempty(t->next)) && iscode(r)) ) { + ___mkd_freeLineRange(t,r); + t->next = 0; + return r; + } + } + return t; +} + + +#ifdef WITH_FENCED_CODE +static int +iscodefence(Line *r, int size) +{ + if ( !(r->flags & CHECKED) ) + checkline(r); + + return (r->kind == chk_tilde) && (r->count >= size); +} + +static Paragraph * +fencedcodeblock(ParagraphRoot *d, Line **ptr) +{ + Line *first, *r; + Paragraph *ret; + + first = (*ptr); + + /* don't allow zero-length code fences + */ + if ( (first->next == 0) || iscodefence(first->next, first->count) ) + return 0; + + /* find the closing fence, discard the fences, + * return a Paragraph with the contents + */ + for ( r = first; r && r->next; r = r->next ) + if ( iscodefence(r->next, first->count) ) { + (*ptr) = r->next->next; + ret = Pp(d, first->next, CODE); + ___mkd_freeLine(first); + ___mkd_freeLine(r->next); + r->next = 0; + return ret; + } + return 0; +} +#endif + + +static int +centered(Line *first, Line *last) +{ + + if ( first&&last ) { + int len = S(last->text); + + if ( (len > 2) && (strncmp(T(first->text), "->", 2) == 0) + && (strncmp(T(last->text)+len-2, "<-", 2) == 0) ) { + CLIP(first->text, 0, 2); + S(last->text) -= 2; + return CENTER; + } + } + return 0; +} + + +static int +endoftextblock(Line *t, int toplevelblock, DWORD flags) +{ + int z; + + if ( end_of_block(t) || isquote(t) ) + return 1; + + /* HORRIBLE STANDARDS KLUDGES: + * 1. non-toplevel paragraphs absorb adjacent code blocks + * 2. Toplevel paragraphs eat absorb adjacent list items, + * but sublevel blocks behave properly. + * (What this means is that we only need to check for code + * blocks at toplevel, and only check for list items at + * nested levels.) + */ + return toplevelblock ? 0 : islist(t,&z,flags,&z); +} + + +static Line * +textblock(Paragraph *p, int toplevel, DWORD flags) +{ + Line *t, *next; + + for ( t = p->text; t ; t = next ) { + if ( ((next = t->next) == 0) || endoftextblock(next, toplevel, flags) ) { + p->align = centered(p->text, t); + t->next = 0; + return next; + } + } + return t; +} + + +/* length of the id: or class: kind in a special div-not-quote block + */ +static int +szmarkerclass(char *p) +{ + if ( strncasecmp(p, "id:", 3) == 0 ) + return 3; + if ( strncasecmp(p, "class:", 6) == 0 ) + return 6; + return 0; +} + + +/* + * check if the first line of a quoted block is the special div-not-quote + * marker %[kind:]name% + */ +#define iscsschar(c) (isalpha(c) || (c == '-') || (c == '_') ) + +static int +isdivmarker(Line *p, int start, DWORD flags) +{ + char *s; + int last, i; + + if ( flags & (MKD_NODIVQUOTE|MKD_STRICT) ) + return 0; + + last= S(p->text) - (1 + start); + s = T(p->text) + start; + + if ( (last <= 0) || (*s != '%') || (s[last] != '%') ) + return 0; + + i = szmarkerclass(s+1); + + if ( !iscsschar(s[i+1]) ) + return 0; + while ( ++i < last ) + if ( !(isdigit(s[i]) || iscsschar(s[i])) ) + return 0; + + return 1; +} + + +/* + * accumulate a blockquote. + * + * one sick horrible thing about blockquotes is that even though + * it just takes ^> to start a quote, following lines, if quoted, + * assume that the prefix is ``> ''. This means that code needs + * to be indented *5* spaces from the leading '>', but *4* spaces + * from the start of the line. This does not appear to be + * documented in the reference implementation, but it's the + * way the markdown sample web form at Daring Fireball works. + */ +static Line * +quoteblock(Paragraph *p, DWORD flags) +{ + Line *t, *q; + int qp; + + for ( t = p->text; t ; t = q ) { + if ( isquote(t) ) { + /* clip leading spaces */ + for (qp = 0; T(t->text)[qp] != '>'; qp ++) + /* assert: the first nonblank character on this line + * will be a > + */; + /* clip '>' */ + qp++; + /* clip next space, if any */ + if ( T(t->text)[qp] == ' ' ) + qp++; + CLIP(t->text, 0, qp); + UNCHECK(t); + t->dle = mkd_firstnonblank(t); + } + + q = skipempty(t->next); + + if ( (q == 0) || ((q != t->next) && (!isquote(q) || isdivmarker(q,1,flags))) ) { + ___mkd_freeLineRange(t, q); + t = q; + break; + } + } + if ( isdivmarker(p->text,0,flags) ) { + char *prefix = "class"; + int i; + + q = p->text; + p->text = p->text->next; + + if ( (i = szmarkerclass(1+T(q->text))) == 3 ) + /* and this would be an "%id:" prefix */ + prefix="id"; + + if ( p->ident = malloc(4+strlen(prefix)+S(q->text)) ) + sprintf(p->ident, "%s=\"%.*s\"", prefix, S(q->text)-(i+2), + T(q->text)+(i+1) ); + + ___mkd_freeLine(q); + } + return t; +} + + +typedef int (*linefn)(Line *); + + +/* + * pull in a list block. A list block starts with a list marker and + * runs until the next list marker, the next non-indented paragraph, + * or EOF. You do not have to indent nonblank lines after the list + * marker, but multiple paragraphs need to start with a 4-space indent. + */ +static Line * +listitem(Paragraph *p, int indent, DWORD flags, linefn check) +{ + Line *t, *q; + int clip = indent; + int z; + + for ( t = p->text; t ; t = q) { + CLIP(t->text, 0, clip); + UNCHECK(t); + t->dle = mkd_firstnonblank(t); + + if ( (q = skipempty(t->next)) == 0 ) { + ___mkd_freeLineRange(t,q); + return 0; + } + + /* after a blank line, the next block needs to start with a line + * that's indented 4(? -- reference implementation allows a 1 + * character indent, but that has unfortunate side effects here) + * spaces, but after that the line doesn't need any indentation + */ + if ( q != t->next ) { + if (q->dle < indent) { + q = t->next; + t->next = 0; + return q; + } + /* indent at least 2, and at most as + * as far as the initial line was indented. */ + indent = clip ? clip : 2; + } + + if ( (q->dle < indent) && (ishr(q) || islist(q,&z,flags,&z) + || (check && (*check)(q))) + && !issetext(q,&z) ) { + q = t->next; + t->next = 0; + return q; + } + + clip = (q->dle > indent) ? indent : q->dle; + } + return t; +} + + +static Line * +definition_block(Paragraph *top, int clip, MMIOT *f, int kind) +{ + ParagraphRoot d = { 0, 0 }; + Paragraph *p; + Line *q = top->text, *text = 0, *labels; + int z, para; + + while (( labels = q )) { + + if ( (q = isdefinition(labels, &z, &kind)) == 0 ) + break; + + if ( (text = skipempty(q->next)) == 0 ) + break; + + if (( para = (text != q->next) )) + ___mkd_freeLineRange(q, text); + + q->next = 0; + if ( kind == 1 /* discount dl */ ) + for ( q = labels; q; q = q->next ) { + CLIP(q->text, 0, 1); + UNCHECK(q); + S(q->text)--; + } + + dd_block: + p = Pp(&d, text, LISTITEM); + + text = listitem(p, clip, f->flags, (kind==2) ? is_extra_dd : 0); + p->down = compile(p->text, 0, f); + p->text = labels; labels = 0; + + if ( para && p->down ) p->down->align = PARA; + + if ( (q = skipempty(text)) == 0 ) + break; + + if (( para = (q != text) )) { + Line anchor; + + anchor.next = text; + ___mkd_freeLineRange(&anchor,q); + text = q; + + } + + if ( kind == 2 && is_extra_dd(q) ) + goto dd_block; + } + top->text = 0; + top->down = T(d); + return text; +} + + +static Line * +enumerated_block(Paragraph *top, int clip, MMIOT *f, int list_class) +{ + ParagraphRoot d = { 0, 0 }; + Paragraph *p; + Line *q = top->text, *text; + int para = 0, z; + + while (( text = q )) { + + p = Pp(&d, text, LISTITEM); + text = listitem(p, clip, f->flags, 0); + + p->down = compile(p->text, 0, f); + p->text = 0; + + if ( para && p->down ) p->down->align = PARA; + + if ( (q = skipempty(text)) == 0 + || islist(q, &clip, f->flags, &z) != list_class ) + break; + + if ( para = (q != text) ) { + Line anchor; + + anchor.next = text; + ___mkd_freeLineRange(&anchor, q); + + if ( p->down ) p->down->align = PARA; + } + } + top->text = 0; + top->down = T(d); + return text; +} + + +static int +tgood(char c) +{ + switch (c) { + case '\'': + case '"': return c; + case '(': return ')'; + } + return 0; +} + + +/* + * add a new (image or link) footnote to the footnote table + */ +static Line* +addfootnote(Line *p, MMIOT* f) +{ + int j, i; + int c; + Line *np = p->next; + + Footnote *foot = &EXPAND(*f->footnotes); + + CREATE(foot->tag); + CREATE(foot->link); + CREATE(foot->title); + foot->flags = foot->height = foot->width = 0; + + for (j=i=p->dle+1; T(p->text)[j] != ']'; j++) + EXPAND(foot->tag) = T(p->text)[j]; + + EXPAND(foot->tag) = 0; + S(foot->tag)--; + j = nextnonblank(p, j+2); + + if ( (f->flags & MKD_EXTRA_FOOTNOTE) && (T(foot->tag)[0] == '^') ) { + while ( j < S(p->text) ) + EXPAND(foot->title) = T(p->text)[j++]; + goto skip_to_end; + } + + while ( (j < S(p->text)) && !isspace(T(p->text)[j]) ) + EXPAND(foot->link) = T(p->text)[j++]; + EXPAND(foot->link) = 0; + S(foot->link)--; + j = nextnonblank(p,j); + + if ( T(p->text)[j] == '=' ) { + sscanf(T(p->text)+j, "=%dx%d", &foot->width, &foot->height); + while ( (j < S(p->text)) && !isspace(T(p->text)[j]) ) + ++j; + j = nextnonblank(p,j); + } + + + if ( (j >= S(p->text)) && np && np->dle && tgood(T(np->text)[np->dle]) ) { + ___mkd_freeLine(p); + p = np; + np = p->next; + j = p->dle; + } + + if ( (c = tgood(T(p->text)[j])) ) { + /* Try to take the rest of the line as a comment; read to + * EOL, then shrink the string back to before the final + * quote. + */ + ++j; /* skip leading quote */ + + while ( j < S(p->text) ) + EXPAND(foot->title) = T(p->text)[j++]; + + while ( S(foot->title) && T(foot->title)[S(foot->title)-1] != c ) + --S(foot->title); + if ( S(foot->title) ) /* skip trailing quote */ + --S(foot->title); + EXPAND(foot->title) = 0; + --S(foot->title); + } + +skip_to_end: + ___mkd_freeLine(p); + return np; +} + + +/* + * allocate a paragraph header, link it to the + * tail of the current document + */ +static Paragraph * +Pp(ParagraphRoot *d, Line *ptr, int typ) +{ + Paragraph *ret = calloc(sizeof *ret, 1); + + ret->text = ptr; + ret->typ = typ; + + return ATTACH(*d, ret); +} + + + +static Line* +consume(Line *ptr, int *eaten) +{ + Line *next; + int blanks=0; + + for (; ptr && blankline(ptr); ptr = next, blanks++ ) { + next = ptr->next; + ___mkd_freeLine(ptr); + } + if ( ptr ) *eaten = blanks; + return ptr; +} + + +/* + * top-level compilation; break the document into + * style, html, and source blocks with footnote links + * weeded out. + */ +static Paragraph * +compile_document(Line *ptr, MMIOT *f) +{ + ParagraphRoot d = { 0, 0 }; + ANCHOR(Line) source = { 0, 0 }; + Paragraph *p = 0; + struct kw *tag; + int eaten, unclosed; + + while ( ptr ) { + if ( !(f->flags & MKD_NOHTML) && (tag = isopentag(ptr)) ) { + /* If we encounter a html/style block, compile and save all + * of the cached source BEFORE processing the html/style. + */ + if ( T(source) ) { + E(source)->next = 0; + p = Pp(&d, 0, SOURCE); + p->down = compile(T(source), 1, f); + T(source) = E(source) = 0; + } + p = Pp(&d, ptr, strcmp(tag->id, "STYLE") == 0 ? STYLE : HTML); + ptr = htmlblock(p, tag, &unclosed); + if ( unclosed ) { + p->typ = SOURCE; + p->down = compile(p->text, 1, f); + p->text = 0; + } + } + else if ( isfootnote(ptr) ) { + /* footnotes, like cats, sleep anywhere; pull them + * out of the input stream and file them away for + * later processing + */ + ptr = consume(addfootnote(ptr, f), &eaten); + } + else { + /* source; cache it up to wait for eof or the + * next html/style block + */ + ATTACH(source,ptr); + ptr = ptr->next; + } + } + if ( T(source) ) { + /* if there's any cached source at EOF, compile + * it now. + */ + E(source)->next = 0; + p = Pp(&d, 0, SOURCE); + p->down = compile(T(source), 1, f); + } + return T(d); +} + + +static int +first_nonblank_before(Line *j, int dle) +{ + return (j->dle < dle) ? j->dle : dle; +} + + +static int +actually_a_table(MMIOT *f, Line *pp) +{ + Line *r; + int j; + int c; + + /* tables need to be turned on */ + if ( f->flags & (MKD_STRICT|MKD_NOTABLES) ) + return 0; + + /* tables need three lines */ + if ( !(pp && pp->next && pp->next->next) ) { + return 0; + } + + /* all lines must contain |'s */ + for (r = pp; r; r = r->next ) + if ( !(r->flags & PIPECHAR) ) { + return 0; + } + + /* if the header has a leading |, all lines must have leading |'s */ + if ( T(pp->text)[pp->dle] == '|' ) { + for ( r = pp; r; r = r->next ) + if ( T(r->text)[first_nonblank_before(r,pp->dle)] != '|' ) { + return 0; + } + } + + /* second line must be only whitespace, -, |, or : */ + r = pp->next; + + for ( j=r->dle; j < S(r->text); ++j ) { + c = T(r->text)[j]; + + if ( !(isspace(c)||(c=='-')||(c==':')||(c=='|')) ) { + return 0; + } + } + + return 1; +} + + +/* + * break a collection of markdown input into + * blocks of lists, code, html, and text to + * be marked up. + */ +static Paragraph * +compile(Line *ptr, int toplevel, MMIOT *f) +{ + ParagraphRoot d = { 0, 0 }; + Paragraph *p = 0; + Line *r; + int para = toplevel; + int blocks = 0; + int hdr_type, list_type, list_class, indent; + + ptr = consume(ptr, ¶); + + while ( ptr ) { + if ( iscode(ptr) ) { + p = Pp(&d, ptr, CODE); + + if ( f->flags & MKD_1_COMPAT) { + /* HORRIBLE STANDARDS KLUDGE: the first line of every block + * has trailing whitespace trimmed off. + */ + ___mkd_tidy(&p->text->text); + } + + ptr = codeblock(p); + } +#if WITH_FENCED_CODE + else if ( iscodefence(ptr,3) && (p=fencedcodeblock(&d, &ptr)) ) + /* yay, it's already done */ ; +#endif + else if ( ishr(ptr) ) { + p = Pp(&d, 0, HR); + r = ptr; + ptr = ptr->next; + ___mkd_freeLine(r); + } + else if (( list_class = islist(ptr, &indent, f->flags, &list_type) )) { + if ( list_class == DL ) { + p = Pp(&d, ptr, DL); + ptr = definition_block(p, indent, f, list_type); + } + else { + p = Pp(&d, ptr, list_type); + ptr = enumerated_block(p, indent, f, list_class); + } + } + else if ( isquote(ptr) ) { + p = Pp(&d, ptr, QUOTE); + ptr = quoteblock(p, f->flags); + p->down = compile(p->text, 1, f); + p->text = 0; + } + else if ( ishdr(ptr, &hdr_type) ) { + p = Pp(&d, ptr, HDR); + ptr = headerblock(p, hdr_type); + } + else { + p = Pp(&d, ptr, MARKUP); + ptr = textblock(p, toplevel, f->flags); + /* tables are a special kind of paragraph */ + if ( actually_a_table(f, p->text) ) + p->typ = TABLE; + } + + if ( (para||toplevel) && !p->align ) + p->align = PARA; + + blocks++; + para = toplevel || (blocks > 1); + ptr = consume(ptr, ¶); + + if ( para && !p->align ) + p->align = PARA; + + } + return T(d); +} + + +/* + * the guts of the markdown() function, ripped out so I can do + * debugging. + */ + +/* + * prepare and compile `text`, returning a Paragraph tree. + */ +int +mkd_compile(Document *doc, DWORD flags) +{ + if ( !doc ) + return 0; + + if ( doc->compiled ) + return 1; + + doc->compiled = 1; + memset(doc->ctx, 0, sizeof(MMIOT) ); + doc->ctx->ref_prefix= doc->ref_prefix; + doc->ctx->cb = &(doc->cb); + doc->ctx->flags = flags & USER_FLAGS; + CREATE(doc->ctx->in); + doc->ctx->footnotes = malloc(sizeof doc->ctx->footnotes[0]); + CREATE(*doc->ctx->footnotes); + + mkd_initialize(); + + doc->code = compile_document(T(doc->content), doc->ctx); + qsort(T(*doc->ctx->footnotes), S(*doc->ctx->footnotes), + sizeof T(*doc->ctx->footnotes)[0], + (stfu)__mkd_footsort); + memset(&doc->content, 0, sizeof doc->content); + return 1; +} + diff --git a/markdown/discount/markdown.h b/markdown/discount/markdown.h new file mode 100644 index 000000000..4c7d18109 --- /dev/null +++ b/markdown/discount/markdown.h @@ -0,0 +1,189 @@ +#ifndef _MARKDOWN_D +#define _MARKDOWN_D + +#include "cstring.h" + +/* reference-style links (and images) are stored in an array + * of footnotes. + */ +typedef struct footnote { + Cstring tag; /* the tag for the reference link */ + Cstring link; /* what this footnote points to */ + Cstring title; /* what it's called (TITLE= attribute) */ + int height, width; /* dimensions (for image link) */ + int dealloc; /* deallocation needed? */ + int refnumber; + int flags; +#define EXTRA_BOOKMARK 0x01 +#define REFERENCED 0x02 +} Footnote; + +/* each input line is read into a Line, which contains the line, + * the offset of the first non-space character [this assumes + * that all tabs will be expanded to spaces!], and a pointer to + * the next line. + */ +typedef struct line { + Cstring text; + struct line *next; + int dle; /* leading indent on the line */ + int flags; /* special attributes for this line */ +#define PIPECHAR 0x01 /* line contains a | */ +#define CHECKED 0x02 + + enum { chk_text, chk_code, + chk_hr, chk_dash, + chk_tilde, chk_equal } kind; + int count; +} Line; + + +/* a paragraph is a collection of Lines, with links to the next paragraph + * and (if it's a QUOTE, UL, or OL) to the reparsed contents of this + * paragraph. + */ +typedef struct paragraph { + struct paragraph *next; /* next paragraph */ + struct paragraph *down; /* recompiled contents of this paragraph */ + struct line *text; /* all the text in this paragraph */ + char *ident; /* %id% tag for QUOTE */ + enum { WHITESPACE=0, CODE, QUOTE, MARKUP, + HTML, STYLE, DL, UL, OL, AL, LISTITEM, + HDR, HR, TABLE, SOURCE } typ; + enum { IMPLICIT=0, PARA, CENTER} align; + int hnumber; /* for typ == HDR */ +} Paragraph; + +enum { ETX, SETEXT }; /* header types */ + + +typedef struct block { + enum { bTEXT, bSTAR, bUNDER } b_type; + int b_count; + char b_char; + Cstring b_text; + Cstring b_post; +} block; + +typedef STRING(block) Qblock; + + +typedef char* (*mkd_callback_t)(const char*, const int, void*); +typedef void (*mkd_free_t)(char*, void*); + +typedef struct callback_data { + void *e_data; /* private data for callbacks */ + mkd_callback_t e_url; /* url edit callback */ + mkd_callback_t e_flags; /* extra href flags callback */ + mkd_free_t e_free; /* edit/flags callback memory deallocator */ +} Callback_data; + + +/* a magic markdown io thing holds all the data structures needed to + * do the backend processing of a markdown document + */ +typedef struct mmiot { + Cstring out; + Cstring in; + Qblock Q; + int isp; + int reference; + char *ref_prefix; + STRING(Footnote) *footnotes; + DWORD flags; +#define MKD_NOLINKS 0x00000001 +#define MKD_NOIMAGE 0x00000002 +#define MKD_NOPANTS 0x00000004 +#define MKD_NOHTML 0x00000008 +#define MKD_STRICT 0x00000010 +#define MKD_TAGTEXT 0x00000020 +#define MKD_NO_EXT 0x00000040 +#define MKD_CDATA 0x00000080 +#define MKD_NOSUPERSCRIPT 0x00000100 +#define MKD_NORELAXED 0x00000200 +#define MKD_NOTABLES 0x00000400 +#define MKD_NOSTRIKETHROUGH 0x00000800 +#define MKD_TOC 0x00001000 +#define MKD_1_COMPAT 0x00002000 +#define MKD_AUTOLINK 0x00004000 +#define MKD_SAFELINK 0x00008000 +#define MKD_NOHEADER 0x00010000 +#define MKD_TABSTOP 0x00020000 +#define MKD_NODIVQUOTE 0x00040000 +#define MKD_NOALPHALIST 0x00080000 +#define MKD_NODLIST 0x00100000 +#define MKD_EXTRA_FOOTNOTE 0x00200000 +#define IS_LABEL 0x08000000 +#define USER_FLAGS 0x0FFFFFFF +#define INPUT_MASK (MKD_NOHEADER|MKD_TABSTOP) + + Callback_data *cb; +} MMIOT; + + +/* + * the mkdio text input functions return a document structure, + * which contains a header (retrieved from the document if + * markdown was configured * with the * --enable-pandoc-header + * and the document begins with a pandoc-style header) and the + * root of the linked list of Lines. + */ +typedef struct document { + int magic; /* "I AM VALID" magic number */ +#define VALID_DOCUMENT 0x19600731 + Line *title; + Line *author; + Line *date; + ANCHOR(Line) content; /* uncompiled text, not valid after compile() */ + Paragraph *code; /* intermediate code generated by compile() */ + int compiled; /* set after mkd_compile() */ + int html; /* set after (internal) htmlify() */ + int tabstop; /* for properly expanding tabs (ick) */ + char *ref_prefix; + MMIOT *ctx; /* backend buffers, flags, and structures */ + Callback_data cb; /* callback functions & private data */ +} Document; + + +extern int mkd_firstnonblank(Line *); +extern int mkd_compile(Document *, DWORD); +extern int mkd_document(Document *, char **); +extern int mkd_generatehtml(Document *, FILE *); +extern int mkd_css(Document *, char **); +extern int mkd_generatecss(Document *, FILE *); +#define mkd_style mkd_generatecss +extern int mkd_xml(char *, int , char **); +extern int mkd_generatexml(char *, int, FILE *); +extern void mkd_cleanup(Document *); +extern int mkd_line(char *, int, char **, DWORD); +extern int mkd_generateline(char *, int, FILE*, DWORD); +#define mkd_text mkd_generateline +extern void mkd_basename(Document*, char *); + +typedef int (*mkd_sta_function_t)(const int,const void*); +extern void mkd_string_to_anchor(char*,int, mkd_sta_function_t, void*, int); + +extern Document *mkd_in(FILE *, DWORD); +extern Document *mkd_string(const char*,int, DWORD); + +extern void mkd_initialize(); +extern void mkd_shlib_destructor(); + +extern void mkd_ref_prefix(Document*, char*); + +/* internal resource handling functions. + */ +extern void ___mkd_freeLine(Line *); +extern void ___mkd_freeLines(Line *); +extern void ___mkd_freeParagraph(Paragraph *); +extern void ___mkd_freefootnote(Footnote *); +extern void ___mkd_freefootnotes(MMIOT *); +extern void ___mkd_initmmiot(MMIOT *, void *); +extern void ___mkd_freemmiot(MMIOT *, void *); +extern void ___mkd_freeLineRange(Line *, Line *); +extern void ___mkd_xml(char *, int, FILE *); +extern void ___mkd_reparse(char *, int, int, MMIOT*); +extern void ___mkd_emblock(MMIOT*); +extern void ___mkd_tidy(Cstring *); + +#endif/*_MARKDOWN_D*/ diff --git a/markdown/discount/mkdio.c b/markdown/discount/mkdio.c new file mode 100644 index 000000000..0bee521be --- /dev/null +++ b/markdown/discount/mkdio.c @@ -0,0 +1,357 @@ +/* + * mkdio -- markdown front end input functions + * + * Copyright (C) 2007 David L Parsons. + * The redistribution terms are provided in the COPYRIGHT file that must + * be distributed with this source code. + */ +#include "config.h" +#include +#include +#include + +#include "cstring.h" +#include "markdown.h" +#include "amalloc.h" + +typedef ANCHOR(Line) LineAnchor; + +/* create a new blank Document + */ +static Document* +new_Document() +{ + Document *ret = calloc(sizeof(Document), 1); + + if ( ret ) { + if (( ret->ctx = calloc(sizeof(MMIOT), 1) )) { + ret->magic = VALID_DOCUMENT; + return ret; + } + free(ret); + } + return 0; +} + + +/* add a line to the markdown input chain, expanding tabs and + * noting the presence of special characters as we go. + */ +static void +queue(Document* a, Cstring *line) +{ + Line *p = calloc(sizeof *p, 1); + unsigned char c; + int xp = 0; + int size = S(*line); + unsigned char *str = (unsigned char*)T(*line); + + CREATE(p->text); + ATTACH(a->content, p); + + while ( size-- ) { + if ( (c = *str++) == '\t' ) { + /* expand tabs into ->tabstop spaces. We use ->tabstop + * because the ENTIRE FREAKING COMPUTER WORLD uses editors + * that don't do ^T/^D, but instead use tabs for indentation, + * and, of course, set their tabs down to 4 spaces + */ + do { + EXPAND(p->text) = ' '; + } while ( ++xp % a->tabstop ); + } + else if ( c >= ' ' ) { + if ( c == '|' ) + p->flags |= PIPECHAR; + EXPAND(p->text) = c; + ++xp; + } + } + EXPAND(p->text) = 0; + S(p->text)--; + p->dle = mkd_firstnonblank(p); +} + + +/* trim leading blanks from a header line + */ +static void +header_dle(Line *p) +{ + CLIP(p->text, 0, 1); + p->dle = mkd_firstnonblank(p); +} + + +/* build a Document from any old input. + */ +typedef int (*getc_func)(void*); + +Document * +populate(getc_func getc, void* ctx, int flags) +{ + Cstring line; + Document *a = new_Document(); + int c; + int pandoc = 0; + + if ( !a ) return 0; + + a->tabstop = (flags & MKD_TABSTOP) ? 4 : TABSTOP; + + CREATE(line); + + while ( (c = (*getc)(ctx)) != EOF ) { + if ( c == '\n' ) { + if ( pandoc != EOF && pandoc < 3 ) { + if ( S(line) && (T(line)[0] == '%') ) + pandoc++; + else + pandoc = EOF; + } + queue(a, &line); + S(line) = 0; + } + else if ( isprint(c) || isspace(c) || (c & 0x80) ) + EXPAND(line) = c; + } + + if ( S(line) ) + queue(a, &line); + + DELETE(line); + + if ( (pandoc == 3) && !(flags & (MKD_NOHEADER|MKD_STRICT)) ) { + /* the first three lines started with %, so we have a header. + * clip the first three lines out of content and hang them + * off header. + */ + Line *headers = T(a->content); + + a->title = headers; header_dle(a->title); + a->author= headers->next; header_dle(a->author); + a->date = headers->next->next; header_dle(a->date); + + T(a->content) = headers->next->next->next; + } + + return a; +} + + +/* convert a file into a linked list + */ +Document * +mkd_in(FILE *f, DWORD flags) +{ + return populate((getc_func)fgetc, f, flags & INPUT_MASK); +} + + +/* return a single character out of a buffer + */ +struct string_ctx { + const char *data; /* the unread data */ + int size; /* and how much is there? */ +} ; + + +static int +strget(struct string_ctx *in) +{ + if ( !in->size ) return EOF; + + --(in->size); + + return *(in->data)++; +} + + +/* convert a block of text into a linked list + */ +Document * +mkd_string(const char *buf, int len, DWORD flags) +{ + struct string_ctx about; + + about.data = buf; + about.size = len; + + return populate((getc_func)strget, &about, flags & INPUT_MASK); +} + + +/* write the html to a file (xmlified if necessary) + */ +int +mkd_generatehtml(Document *p, FILE *output) +{ + char *doc; + int szdoc; + + if ( (szdoc = mkd_document(p, &doc)) != EOF ) { + if ( p->ctx->flags & MKD_CDATA ) + mkd_generatexml(doc, szdoc, output); + else + fwrite(doc, szdoc, 1, output); + putc('\n', output); + return 0; + } + return -1; +} + + +/* convert some markdown text to html + */ +int +markdown(Document *document, FILE *out, int flags) +{ + if ( mkd_compile(document, flags) ) { + mkd_generatehtml(document, out); + mkd_cleanup(document); + return 0; + } + return -1; +} + + +/* write out a Cstring, mangled into a form suitable for `0) && !isalpha(line[0]) ) + (*outchar)('L',out); + for ( i=0; i < size ; i++ ) { + c = line[i]; + if ( labelformat ) { + if ( isalnum(c) || (c == '_') || (c == ':') || (c == '-') || (c == '.' ) ) + (*outchar)(c, out); + else + (*outchar)('.', out); + } + else + (*outchar)(c,out); + } + + if (line) + free(line); +} + + +/* ___mkd_reparse() a line + */ +static void +mkd_parse_line(char *bfr, int size, MMIOT *f, int flags) +{ + ___mkd_initmmiot(f, 0); + f->flags = flags & USER_FLAGS; + ___mkd_reparse(bfr, size, 0, f); + ___mkd_emblock(f); +} + + +/* ___mkd_reparse() a line, returning it in malloc()ed memory + */ +int +mkd_line(char *bfr, int size, char **res, DWORD flags) +{ + MMIOT f; + int len; + + mkd_parse_line(bfr, size, &f, flags); + + if ( len = S(f.out) ) { + /* kludge alert; we know that T(f.out) is malloced memory, + * so we can just steal it away. This is awful -- there + * should be an opaque method that transparently moves + * the pointer out of the embedded Cstring. + */ + EXPAND(f.out) = 0; + *res = T(f.out); + T(f.out) = 0; + S(f.out) = ALLOCATED(f.out) = 0; + } + else { + *res = 0; + len = EOF; + } + ___mkd_freemmiot(&f, 0); + return len; +} + + +/* ___mkd_reparse() a line, writing it to a FILE + */ +int +mkd_generateline(char *bfr, int size, FILE *output, DWORD flags) +{ + MMIOT f; + + mkd_parse_line(bfr, size, &f, flags); + if ( flags & MKD_CDATA ) + mkd_generatexml(T(f.out), S(f.out), output); + else + fwrite(T(f.out), S(f.out), 1, output); + + ___mkd_freemmiot(&f, 0); + return 0; +} + + +/* set the url display callback + */ +void +mkd_e_url(Document *f, mkd_callback_t edit) +{ + if ( f ) + f->cb.e_url = edit; +} + + +/* set the url options callback + */ +void +mkd_e_flags(Document *f, mkd_callback_t edit) +{ + if ( f ) + f->cb.e_flags = edit; +} + + +/* set the url display/options deallocator + */ +void +mkd_e_free(Document *f, mkd_free_t dealloc) +{ + if ( f ) + f->cb.e_free = dealloc; +} + + +/* set the url display/options context data field + */ +void +mkd_e_data(Document *f, void *data) +{ + if ( f ) + f->cb.e_data = data; +} + + +/* set the href prefix for markdown extra style footnotes + */ +void +mkd_ref_prefix(Document *f, char *data) +{ + if ( f ) + f->ref_prefix = data; +} diff --git a/markdown/discount/mkdio.h b/markdown/discount/mkdio.h new file mode 100644 index 000000000..68813319d --- /dev/null +++ b/markdown/discount/mkdio.h @@ -0,0 +1,111 @@ +#ifndef _MKDIO_D +#define _MKDIO_D + +#include + +typedef void MMIOT; + +/* In the upstream Discount library this guint32 is a @DWORD@ and replaced + * at build time. */ +typedef guint32 mkd_flag_t; + +/* line builder for markdown() + */ +MMIOT *mkd_in(FILE*,mkd_flag_t); /* assemble input from a file */ +MMIOT *mkd_string(const char*,int,mkd_flag_t); /* assemble input from a buffer */ + +void mkd_basename(MMIOT*,char*); + +void mkd_initialize(); +void mkd_with_html5_tags(); +void mkd_shlib_destructor(); + +/* compilation, debugging, cleanup + */ +int mkd_compile(MMIOT*, mkd_flag_t); +int mkd_cleanup(MMIOT*); + +/* markup functions + */ +int mkd_dump(MMIOT*, FILE*, int, char*); +int markdown(MMIOT*, FILE*, mkd_flag_t); +int mkd_line(char *, int, char **, mkd_flag_t); +typedef int (*mkd_sta_function_t)(const int,const void*); +void mkd_string_to_anchor(char *, int, mkd_sta_function_t, void*, int); +int mkd_xhtmlpage(MMIOT*,int,FILE*); + +/* header block access + */ +char* mkd_doc_title(MMIOT*); +char* mkd_doc_author(MMIOT*); +char* mkd_doc_date(MMIOT*); + +/* compiled data access + */ +int mkd_document(MMIOT*, char**); +int mkd_toc(MMIOT*, char**); +int mkd_css(MMIOT*, char **); +int mkd_xml(char *, int, char **); + +/* write-to-file functions + */ +int mkd_generatehtml(MMIOT*,FILE*); +int mkd_generatetoc(MMIOT*,FILE*); +int mkd_generatexml(char *, int,FILE*); +int mkd_generatecss(MMIOT*,FILE*); +#define mkd_style mkd_generatecss +int mkd_generateline(char *, int, FILE*, mkd_flag_t); +#define mkd_text mkd_generateline + +/* url generator callbacks + */ +typedef char * (*mkd_callback_t)(const char*, const int, void*); +typedef void (*mkd_free_t)(char*, void*); + +void mkd_e_url(void *, mkd_callback_t); +void mkd_e_flags(void *, mkd_callback_t); +void mkd_e_free(void *, mkd_free_t ); +void mkd_e_data(void *, void *); + +/* version#. + */ +extern char markdown_version[]; +void mkd_mmiot_flags(FILE *, MMIOT *, int); +void mkd_flags_are(FILE*, mkd_flag_t, int); + +void mkd_ref_prefix(MMIOT*, char*); + + +/* special flags for markdown() and mkd_text() + */ +#define MKD_NOLINKS 0x00000001 /* don't do link processing, block tags */ +#define MKD_NOIMAGE 0x00000002 /* don't do image processing, block */ +#define MKD_NOPANTS 0x00000004 /* don't run smartypants() */ +#define MKD_NOHTML 0x00000008 /* don't allow raw html through AT ALL */ +#define MKD_STRICT 0x00000010 /* disable SUPERSCRIPT, RELAXED_EMPHASIS */ +#define MKD_TAGTEXT 0x00000020 /* process text inside an html tag; no + * , no , no html or [] expansion */ +#define MKD_NO_EXT 0x00000040 /* don't allow pseudo-protocols */ +#define MKD_NOEXT MKD_NO_EXT /* ^^^ (aliased for user convenience) */ +#define MKD_CDATA 0x00000080 /* generate code for xml ![CDATA[...]] */ +#define MKD_NOSUPERSCRIPT 0x00000100 /* no A^B */ +#define MKD_NORELAXED 0x00000200 /* emphasis happens /everywhere/ */ +#define MKD_NOTABLES 0x00000400 /* disallow tables */ +#define MKD_NOSTRIKETHROUGH 0x00000800 /* forbid ~~strikethrough~~ */ +#define MKD_TOC 0x00001000 /* do table-of-contents processing */ +#define MKD_1_COMPAT 0x00002000 /* compatibility with MarkdownTest_1.0 */ +#define MKD_AUTOLINK 0x00004000 /* make http://foo.com link even without <>s */ +#define MKD_SAFELINK 0x00008000 /* paranoid check for link protocol */ +#define MKD_NOHEADER 0x00010000 /* don't process header blocks */ +#define MKD_TABSTOP 0x00020000 /* expand tabs to 4 spaces */ +#define MKD_NODIVQUOTE 0x00040000 /* forbid >%class% blocks */ +#define MKD_NOALPHALIST 0x00080000 /* forbid alphabetic lists */ +#define MKD_NODLIST 0x00100000 /* forbid definition lists */ +#define MKD_EXTRA_FOOTNOTE 0x00200000 /* enable markdown extra-style footnotes */ +#define MKD_EMBED MKD_NOLINKS|MKD_NOIMAGE|MKD_TAGTEXT + +/* special flags for mkd_in() and mkd_string() + */ + + +#endif/*_MKDIO_D*/ diff --git a/markdown/discount/resource.c b/markdown/discount/resource.c new file mode 100644 index 000000000..1dee8e3dc --- /dev/null +++ b/markdown/discount/resource.c @@ -0,0 +1,157 @@ +/* markdown: a C implementation of John Gruber's Markdown markup language. + * + * Copyright (C) 2007 David L Parsons. + * The redistribution terms are provided in the COPYRIGHT file that must + * be distributed with this source code. + */ +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#include "cstring.h" +#include "markdown.h" +#include "amalloc.h" + +/* free a (single) line + */ +void +___mkd_freeLine(Line *ptr) +{ + DELETE(ptr->text); + free(ptr); +} + + +/* free a list of lines + */ +void +___mkd_freeLines(Line *p) +{ + if (p->next) + ___mkd_freeLines(p->next); + ___mkd_freeLine(p); +} + + +/* bye bye paragraph. + */ +void +___mkd_freeParagraph(Paragraph *p) +{ + if (p->next) + ___mkd_freeParagraph(p->next); + if (p->down) + ___mkd_freeParagraph(p->down); + if (p->text) + ___mkd_freeLines(p->text); + if (p->ident) + free(p->ident); + free(p); +} + + +/* bye bye footnote. + */ +void +___mkd_freefootnote(Footnote *f) +{ + DELETE(f->tag); + DELETE(f->link); + DELETE(f->title); +} + + +/* bye bye footnotes. + */ +void +___mkd_freefootnotes(MMIOT *f) +{ + int i; + + if ( f->footnotes ) { + for (i=0; i < S(*f->footnotes); i++) + ___mkd_freefootnote( &T(*f->footnotes)[i] ); + DELETE(*f->footnotes); + free(f->footnotes); + } +} + + +/* initialize a new MMIOT + */ +void +___mkd_initmmiot(MMIOT *f, void *footnotes) +{ + if ( f ) { + memset(f, 0, sizeof *f); + CREATE(f->in); + CREATE(f->out); + CREATE(f->Q); + if ( footnotes ) + f->footnotes = footnotes; + else { + f->footnotes = malloc(sizeof f->footnotes[0]); + CREATE(*f->footnotes); + } + } +} + + +/* free the contents of a MMIOT, but leave the object alone. + */ +void +___mkd_freemmiot(MMIOT *f, void *footnotes) +{ + if ( f ) { + DELETE(f->in); + DELETE(f->out); + DELETE(f->Q); + if ( f->footnotes != footnotes ) + ___mkd_freefootnotes(f); + memset(f, 0, sizeof *f); + } +} + + +/* free lines up to an barrier. + */ +void +___mkd_freeLineRange(Line *anchor, Line *stop) +{ + Line *r = anchor->next; + + if ( r != stop ) { + while ( r && (r->next != stop) ) + r = r->next; + if ( r ) r->next = 0; + ___mkd_freeLines(anchor->next); + } + anchor->next = 0; +} + + +/* clean up everything allocated in __mkd_compile() + */ +void +mkd_cleanup(Document *doc) +{ + if ( doc && (doc->magic == VALID_DOCUMENT) ) { + if ( doc->ctx ) { + ___mkd_freemmiot(doc->ctx, 0); + free(doc->ctx); + } + + if ( doc->code) ___mkd_freeParagraph(doc->code); + if ( doc->title) ___mkd_freeLine(doc->title); + if ( doc->author) ___mkd_freeLine(doc->author); + if ( doc->date) ___mkd_freeLine(doc->date); + if ( T(doc->content) ) ___mkd_freeLines(T(doc->content)); + memset(doc, 0, sizeof doc[0]); + free(doc); + } +} diff --git a/markdown/discount/setup.c b/markdown/discount/setup.c new file mode 100644 index 000000000..988a6aa91 --- /dev/null +++ b/markdown/discount/setup.c @@ -0,0 +1,39 @@ +/* markdown: a C implementation of John Gruber's Markdown markup language. + * + * Copyright (C) 2007 David L Parsons. + * The redistribution terms are provided in the COPYRIGHT file that must + * be distributed with this source code. + */ +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "cstring.h" +#include "markdown.h" +#include "amalloc.h" +#include "tags.h" + +static int need_to_initrng = 1; + +void +mkd_initialize() +{ + + if ( need_to_initrng ) { + need_to_initrng = 0; + INITRNG(time(0)); + } +} + + +void +mkd_shlib_destructor() +{ + mkd_deallocate_tags(); +} + diff --git a/markdown/discount/tags.c b/markdown/discount/tags.c new file mode 100644 index 000000000..b5043dd0b --- /dev/null +++ b/markdown/discount/tags.c @@ -0,0 +1,91 @@ +/* block-level tags for passing html blocks through the blender + */ +#define __WITHOUT_AMALLOC 1 +#include "cstring.h" +#include "tags.h" + +STRING(struct kw) extratags; + +/* the standard collection of tags are built and sorted when + * discount is configured, so all we need to do is pull them + * in and use them. + * + * Additional tags still need to be allocated, sorted, and deallocated. + */ +#include "blocktags" + + +/* define an additional html block tag + */ +void +mkd_define_tag(char *id, int selfclose) +{ + struct kw *p; + + /* only add the new tag if it doesn't exist in + * either the standard or extra tag tables. + */ + if ( !(p = mkd_search_tags(id, strlen(id))) ) { + p = &EXPAND(extratags); + p->id = id; + p->size = strlen(id); + p->selfclose = selfclose; + } +} + + +/* case insensitive string sort (for qsort() and bsearch() of block tags) + */ +static int +casort(struct kw *a, struct kw *b) +{ + if ( a->size != b->size ) + return a->size - b->size; + return strncasecmp(a->id, b->id, b->size); +} + + +/* stupid cast to make gcc shut up about the function types being + * passed into qsort() and bsearch() + */ +typedef int (*stfu)(const void*,const void*); + + +/* sort the list of extra html block tags for later searching + */ +void +mkd_sort_tags() +{ + qsort(T(extratags), S(extratags), sizeof(struct kw), (stfu)casort); +} + + +/* look for a token in the html block tag list + */ +struct kw* +mkd_search_tags(char *pat, int len) +{ + struct kw key; + struct kw *ret; + + key.id = pat; + key.size = len; + + if ( (ret=bsearch(&key,blocktags,NR_blocktags,sizeof key,(stfu)casort)) ) + return ret; + + if ( S(extratags) ) + return bsearch(&key,T(extratags),S(extratags),sizeof key,(stfu)casort); + + return 0; +} + + +/* destroy the extratags list (for shared libraries) + */ +void +mkd_deallocate_tags() +{ + if ( S(extratags) > 0 ) + DELETE(extratags); +} /* mkd_deallocate_tags */ diff --git a/markdown/discount/tags.h b/markdown/discount/tags.h new file mode 100644 index 000000000..72d764766 --- /dev/null +++ b/markdown/discount/tags.h @@ -0,0 +1,19 @@ +/* block-level tags for passing html blocks through the blender + */ +#ifndef _TAGS_D +#define _TAGS_D + +struct kw { + char *id; + int size; + int selfclose; +} ; + + +struct kw* mkd_search_tags(char *, int); +void mkd_prepare_tags(); +void mkd_deallocate_tags(); +void mkd_sort_tags(); +void mkd_define_tag(char *, int); + +#endif diff --git a/markdown/discount/toc.c b/markdown/discount/toc.c new file mode 100644 index 000000000..8037e360b --- /dev/null +++ b/markdown/discount/toc.c @@ -0,0 +1,114 @@ +/* + * toc -- spit out a table of contents based on header blocks + * + * Copyright (C) 2008 Jjgod Jiang, David L Parsons + * portions Copyright (C) 2011 Stefano D'Angelo + * The redistribution terms are provided in the COPYRIGHT file that must + * be distributed with this source code. + */ +#include "config.h" +#include +#include +#include + +#include "cstring.h" +#include "markdown.h" +#include "amalloc.h" + +/* write an header index + */ +int +mkd_toc(Document *p, char **doc) +{ + Paragraph *tp, *srcp; + int last_hnumber = 0; + Cstring res; + int size; + int first = 1; + + if ( !(doc && p && p->ctx) ) return -1; + + *doc = 0; + + if ( ! (p->ctx->flags & MKD_TOC) ) return 0; + + CREATE(res); + RESERVE(res, 100); + + for ( tp = p->code; tp ; tp = tp->next ) { + if ( tp->typ == SOURCE ) { + for ( srcp = tp->down; srcp; srcp = srcp->next ) { + if ( srcp->typ == HDR && srcp->text ) { + + while ( last_hnumber > srcp->hnumber ) { + if ( (last_hnumber - srcp->hnumber) > 1 ) + Csprintf(&res, "\n"); + Csprintf(&res, "\n%*s\n%*s", + last_hnumber-1, "", last_hnumber-1, ""); + --last_hnumber; + } + + if ( last_hnumber == srcp->hnumber ) + Csprintf(&res, "\n"); + else if ( (srcp->hnumber > last_hnumber) && !first ) + Csprintf(&res, "\n"); + + while ( srcp->hnumber > last_hnumber ) { + Csprintf(&res, "%*s\n%*s", + last_hnumber, "", last_hnumber, ""); + } + + if ( (size = S(res)) > 0 ) { + EXPAND(res) = 0; + /* HACK ALERT! HACK ALERT! HACK ALERT! */ + *doc = T(res); /* we know that a T(Cstring) is a character pointer + * so we can simply pick it up and carry it away, + * leaving the husk of the Ctring on the stack + * END HACK ALERT + */ + } + else + DELETE(res); + return size; +} + + +/* write an header index + */ +int +mkd_generatetoc(Document *p, FILE *out) +{ + char *buf = 0; + int sz = mkd_toc(p, &buf); + int ret = EOF; + + if ( sz > 0 ) + ret = fwrite(buf, 1, sz, out); + + if ( buf ) free(buf); + + return (ret == sz) ? ret : EOF; +} diff --git a/markdown/discount/version.c b/markdown/discount/version.c new file mode 100644 index 000000000..8e48410ca --- /dev/null +++ b/markdown/discount/version.c @@ -0,0 +1,30 @@ +#include "config.h" + +char markdown_version[] = VERSION +#if 4 != 4 + " TAB=4" +#endif +#if USE_AMALLOC + " DEBUG" +#endif +#if USE_DISCOUNT_DL +# if USE_EXTRA_DL + " DL=BOTH" +# else + " DL=DISCOUNT" +# endif +#elif USE_EXTRA_DL + " DL=EXTRA" +#else + " DL=NONE" +#endif +#if WITH_ID_ANCHOR + " ID-ANCHOR" +#endif +#if WITH_GITHUB_TAGS + " GITHUB-TAGS" +#endif +#if WITH_FENCED_CODE + " FENCED-CODE" +#endif + ; diff --git a/markdown/discount/xml.c b/markdown/discount/xml.c new file mode 100644 index 000000000..5e5838993 --- /dev/null +++ b/markdown/discount/xml.c @@ -0,0 +1,82 @@ +/* markdown: a C implementation of John Gruber's Markdown markup language. + * + * Copyright (C) 2007 David L Parsons. + * The redistribution terms are provided in the COPYRIGHT file that must + * be distributed with this source code. + */ +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#include "cstring.h" +#include "markdown.h" +#include "amalloc.h" + +/* return the xml version of a character + */ +static char * +mkd_xmlchar(unsigned char c) +{ + switch (c) { + case '<': return "<"; + case '>': return ">"; + case '&': return "&"; + case '"': return """; + case '\'': return "'"; + default: if ( isascii(c) || (c & 0x80) ) + return 0; + return ""; + } +} + + +/* write output in XML format + */ +int +mkd_generatexml(char *p, int size, FILE *out) +{ + unsigned char c; + char *entity; + + while ( size-- > 0 ) { + c = *p++; + + if ( entity = mkd_xmlchar(c) ) + fputs(entity, out); + else + fputc(c, out); + } + return 0; +} + + +/* build a xml'ed version of a string + */ +int +mkd_xml(char *p, int size, char **res) +{ + unsigned char c; + char *entity; + Cstring f; + + CREATE(f); + RESERVE(f, 100); + + while ( size-- > 0 ) { + c = *p++; + if ( entity = mkd_xmlchar(c) ) + Cswrite(&f, entity, strlen(entity)); + else + Csputc(c, &f); + } + /* HACK ALERT! HACK ALERT! HACK ALERT! */ + *res = T(f); /* we know that a T(Cstring) is a character pointer */ + /* so we can simply pick it up and carry it away, */ + return S(f); /* leaving the husk of the Ctring on the stack */ + /* END HACK ALERT */ +} diff --git a/markdown/discount/xmlpage.c b/markdown/discount/xmlpage.c new file mode 100644 index 000000000..96ed2b758 --- /dev/null +++ b/markdown/discount/xmlpage.c @@ -0,0 +1,48 @@ +/* + * xmlpage -- write a skeletal xhtml page + * + * Copyright (C) 2007 David L Parsons. + * The redistribution terms are provided in the COPYRIGHT file that must + * be distributed with this source code. + */ +#include "config.h" +#include +#include +#include + +#include "cstring.h" +#include "markdown.h" +#include "amalloc.h" + + +int +mkd_xhtmlpage(Document *p, int flags, FILE *out) +{ + char *title; + extern char *mkd_doc_title(Document *); + + if ( mkd_compile(p, flags) ) { + fprintf(out, "\n"); + fprintf(out, "\n"); + + fprintf(out, "\n"); + + fprintf(out, "\n"); + if ( title = mkd_doc_title(p) ) + fprintf(out, "%s\n", title); + mkd_generatecss(p, out); + fprintf(out, "\n"); + + fprintf(out, "\n"); + mkd_generatehtml(p, out); + fprintf(out, "\n"); + fprintf(out, "\n"); + + mkd_cleanup(p); + + return 0; + } + return -1; +} diff --git a/markdown/docs/Makefile.am b/markdown/docs/Makefile.am new file mode 100644 index 000000000..f5aa44938 --- /dev/null +++ b/markdown/docs/Makefile.am @@ -0,0 +1,2 @@ +plugindocdir = $(docdir)/markdown +plugindoc_DATA = README.md diff --git a/markdown/docs/README.md b/markdown/docs/README.md new file mode 100644 index 000000000..cf9aa47cc --- /dev/null +++ b/markdown/docs/README.md @@ -0,0 +1,55 @@ +Geany Markdown Plugin +===================== + +The Markdown plugin shows a live preview of Markdown documents in a WebKit +view. The Markdown is converted to HTML and then replaced into a +user-configurable HTML template, the result of which is loaded directly +into the WebKit view. + +There are a few settings which can be chosen from the Tools menu and they +will persist between instances of Geany. + +Template +-------- + +This option is accessible from the `Tools->Markdown->Template` menu. Templates +are read from the system-wide configuration directory and then from the user +configuration directory. Templates are just special directories containing +an `index.html` file which defines the template to use for the live preview. + +For example, the Default template's `index.html` file consists of the +following contents: + + + + + + + +The special HTML comment `` is replaced +with the Markdown contents of the editor buffer after the contents have been +converted to HTML. You can put whatever you want in the HTML template, for +example a header and/or footer or some CSS styling. + +### Template Paths + +User templates are read from Geany's configuration directory (usually +`$HOME/.config/geany/plugins/markdown/templates`. System-wide templates, +including the default `Default` and `Alternate` templates are read from +`$PREFIX/share/geany-plugins/markdown/templates`. + +### Custom Templates + +To add your own template, just copy one of the existing ones from the +system-wide templates directory into your user configuration directory. The +name of the template is taken from the name of the directory holding the +`index.html`. For example if you wanted the template to be named `FooBar` +then the `index.html` file path would be +`$HOME/.config/geany/plugins/markdown/templates/FooBar/index.html`. + +Position +-------- + +This option specifies which notebook the Markdown preview tab will appear in. +The two choices are `Sidebar` or `Message Window` for Geany's sidebar and +message window notebooks, respectively. diff --git a/markdown/src/Makefile.am b/markdown/src/Makefile.am new file mode 100644 index 000000000..c302c4645 --- /dev/null +++ b/markdown/src/Makefile.am @@ -0,0 +1,33 @@ +include $(top_srcdir)/build/vars.build.mk + +plugin = markdown + +geanyplugins_LTLIBRARIES = markdown.la + +markdown_la_SOURCES = \ + conf.c \ + md.c \ + plugin.c \ + tmpl.c \ + tmplmgr.c \ + viewer.c + +noinst_HEADERS = \ + conf.h \ + md.h \ + tmpl.h \ + tmplmgr.h \ + viewer.h + +markdown_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(MARKDOWN_CFLAGS) \ + -DMARKDOWN_DATA_DIR=\"$(pkgdatadir)/markdown\" \ + -DMARKDOWN_DOC_DIR=\"$(docdir)/markdown\" \ + -I$(top_srcdir)/markdown/discount + +markdown_la_LIBADD = \ + $(MARKDOWN_LIBS) \ + $(top_builddir)/markdown/discount/libdiscount.la + +include $(top_srcdir)/build/cppcheck.mk diff --git a/markdown/src/conf.c b/markdown/src/conf.c new file mode 100644 index 000000000..e091d8594 --- /dev/null +++ b/markdown/src/conf.c @@ -0,0 +1,177 @@ +/* + * conf.c - Part of the Geany Markdown plugin + * + * Copyright 2012 Matthew Brush + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include "conf.h" +#include "tmpl.h" +#include "tmplmgr.h" + +#define MARKDOWN_CONF_DEFAULT "[general]\n" \ + "template=Default\n" \ + "readme_shown=false\n" \ + "position=0\n" + +struct MarkdownConf { + gchar *filename; + GKeyFile *keyfile; +}; + +static void markdown_conf_init_defaults(MarkdownConf *conf) +{ + if (!g_key_file_has_group(conf->keyfile, "general") || + !g_key_file_has_key(conf->keyfile, "general", "template", NULL)) + { + g_key_file_set_string(conf->keyfile, "general", "template", "Default"); + } +} + +static void markdown_conf_init_file(MarkdownConf *conf) +{ + gchar *dirname = g_path_get_dirname(conf->filename); + if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) { + g_mkdir_with_parents(dirname, 0755); + } + if (!g_file_test(conf->filename, G_FILE_TEST_EXISTS)) { + g_file_set_contents(conf->filename, MARKDOWN_CONF_DEFAULT, -1, NULL); + } + g_free(dirname); +} + +MarkdownConf *markdown_conf_new(const gchar *conf_filename) +{ + MarkdownConf *conf = g_slice_new0(MarkdownConf); + if (conf) { + GError *error = NULL; + conf->filename = g_strdup(conf_filename); + markdown_conf_init_file(conf); + conf->keyfile = g_key_file_new(); + if (!g_key_file_load_from_file(conf->keyfile, conf->filename, + G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &error)) + { + g_warning("Error loading configuration file '%s': %s", conf->filename, + error->message); + g_error_free(error); error = NULL; + } + markdown_conf_init_defaults(conf); + } + return conf; +} + +void markdown_conf_free(MarkdownConf *conf) +{ + g_return_if_fail(conf); + g_free(conf->filename); + g_key_file_free(conf->keyfile); +} + +void markdown_conf_save(MarkdownConf *conf) +{ + g_return_if_fail(conf); + + GError *error = NULL; + gchar *contents = NULL; + gsize len = 0; + + contents = g_key_file_to_data(conf->keyfile, &len, &error); + + if (error) { + g_warning("Error getting config file data: %s", error->message); + g_error_free(error); error = NULL; + return; + } + + if (!g_file_set_contents(conf->filename, contents, len, &error)) { + g_warning("Error saving config file: %s", error->message); + g_error_free(error); error = NULL; + } + + g_free(contents); +} + +gchar *markdown_conf_get_template_name(MarkdownConf *conf) +{ + gchar *res; + GError *error = NULL; + + g_return_val_if_fail(conf, NULL); + + res = g_key_file_get_string(conf->keyfile, "general", "template", &error); + if (error) { + g_warning("Unable to get template from config file: %s", error->message); + g_error_free(error); error = NULL; + } + + return res; +} + +void markdown_conf_set_template_name(MarkdownConf *conf, const gchar *tmpl_name) +{ + g_return_if_fail(conf); + if (!tmpl_name) + g_key_file_set_string(conf->keyfile, "general", "template", "Default"); + else + g_key_file_set_string(conf->keyfile, "general", "template", tmpl_name); +} + +gboolean markdown_conf_get_readme_shown(MarkdownConf *conf) +{ + gboolean res; + GError *error = NULL; + + g_return_val_if_fail(conf, FALSE); + + res = g_key_file_get_boolean(conf->keyfile, "general", "readme_shown", &error); + if (error) { + g_warning("Unable to get whether the README.md file has been shown: %s", + error->message); + g_error_free(error); error = NULL; + } + + return res; +} + +void markdown_conf_set_readme_shown(MarkdownConf *conf, gboolean shown) +{ + g_return_if_fail(conf); + g_key_file_set_boolean(conf->keyfile, "general", "readme_shown", shown); +} + +MarkdownViewPosition markdown_conf_get_view_position(MarkdownConf *conf) +{ + gint conf_val = (gint) MARKDOWN_VIEW_POS_SIDEBAR; + GError *error = NULL; + + g_return_val_if_fail(conf, MARKDOWN_VIEW_POS_SIDEBAR); + + conf_val = g_key_file_get_integer(conf->keyfile, "general", "position", &error); + if (error) { + g_warning("Unable to get the WebKit view position: %s", error->message); + g_error_free(error); error = NULL; + } + + return (MarkdownViewPosition) conf_val; +} + +void markdown_conf_set_view_position(MarkdownConf *conf, MarkdownViewPosition pos) +{ + g_return_if_fail(conf); + g_key_file_set_integer(conf->keyfile, "general", "position", (gint) pos); +} diff --git a/markdown/src/conf.h b/markdown/src/conf.h new file mode 100644 index 000000000..97dae429d --- /dev/null +++ b/markdown/src/conf.h @@ -0,0 +1,52 @@ +/* + * conf.h - Part of the Geany Markdown plugin + * + * Copyright 2012 Matthew Brush + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef MARKDOWN_CONF_H +#define MARKDOWN_CONF_H 1 + +#include + +G_BEGIN_DECLS + +typedef enum { + MARKDOWN_VIEW_POS_SIDEBAR=0, + MARKDOWN_VIEW_POS_MSGWIN=1 +} MarkdownViewPosition; + +typedef struct MarkdownConf MarkdownConf; + +MarkdownConf *markdown_conf_new(const gchar *conf_filename); +void markdown_conf_free(MarkdownConf *conf); +void markdown_conf_save(MarkdownConf *conf); + +gchar *markdown_conf_get_template_name(MarkdownConf *conf); +void markdown_conf_set_template_name(MarkdownConf *conf, const gchar *tmpl_name); + +gboolean markdown_conf_get_readme_shown(MarkdownConf *conf); +void markdown_conf_set_readme_shown(MarkdownConf *conf, gboolean shown); + +MarkdownViewPosition markdown_conf_get_view_position(MarkdownConf *conf); +void markdown_conf_set_view_position(MarkdownConf *conf, MarkdownViewPosition pos); + + +G_END_DECLS + +#endif /* MARKDOWN_CONF_H */ diff --git a/markdown/src/md.c b/markdown/src/md.c new file mode 100644 index 000000000..c1658491d --- /dev/null +++ b/markdown/src/md.c @@ -0,0 +1,46 @@ +/* + * md.c - Part of the Geany Markdown plugin + * + * Copyright 2012 Matthew Brush + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include "markdown.h" +#include "md.h" + +gchar *markdown_to_html(const gchar *md_text) +{ + Document *md; + gchar *result = NULL; + + if (!md_text) + return g_strdup(""); + + md = mkd_string(md_text, strlen(md_text), 0); + if (md) { + if (mkd_compile(md, 0)) { + gchar *res = NULL; + mkd_document(md, &res); + result = g_strdup(res); + } + mkd_cleanup(md); + } + + return result; +} diff --git a/markdown/src/md.h b/markdown/src/md.h new file mode 100644 index 000000000..006d95057 --- /dev/null +++ b/markdown/src/md.h @@ -0,0 +1,33 @@ +/* + * md.h - Part of the Geany Markdown plugin + * + * Copyright 2012 Matthew Brush + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef MARKDOWN_MD_H +#define MARKDOWN_MD_H + +#include + +G_BEGIN_DECLS + +gchar *markdown_to_html(const gchar *md_text); + +G_END_DECLS + +#endif /* MARKDOWN_MD_H */ diff --git a/markdown/src/plugin.c b/markdown/src/plugin.c new file mode 100644 index 000000000..9ed4fc5a3 --- /dev/null +++ b/markdown/src/plugin.c @@ -0,0 +1,362 @@ +/* + * plugin.c - Part of the Geany Markdown plugin + * + * Copyright 2012 Matthew Brush + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include "viewer.h" +#include "tmplmgr.h" +#include "conf.h" + +GeanyData *geany_data; +GeanyPlugin *geany_plugin; +GeanyFunctions *geany_functions; + +PLUGIN_VERSION_CHECK(211) + +PLUGIN_SET_INFO("Markdown", + _("Real-time Markdown preview"), + "0.01", + "Matthew Brush ") + +/* Should be defined by build system, this is just a fallback */ +#ifndef MARKDOWN_DATA_DIR +# define MARKDOWN_DATA_DIR "/usr/local/share/geany-plugins/markdown" +#endif +#ifndef MARKDOWN_DOC_DIR +# define MARKDOWN_DOC_DIR "/usr/local/share/doc/geany-plugins/markdown" +#endif + +/* Global data */ +typedef struct MarkdownPlugin { + struct { + guint update_view; + guint save_conf; + } handler_ids; + GtkWidget *menu_item; + MarkdownViewer *viewer; + MarkdownConf *conf; +} MarkdownPlugin; +MarkdownPlugin markdown_plugin = { { 0, 0 }, NULL, NULL, NULL }; + +/* Forward declarations */ +static gboolean on_conf_idle_handler(MarkdownPlugin *plugin); +static void handle_conf_save_later(MarkdownPlugin *plugin); +static gboolean on_idle_handler(MarkdownPlugin *plugin); +static void handle_update_later(MarkdownPlugin *plugin); +static gboolean on_editor_notify(GObject *obj, GeanyEditor *editor, SCNotification *notif, MarkdownPlugin *plugin); +static void on_document_signal(GObject *obj, GeanyDocument *doc, MarkdownPlugin *plugin); +static void on_document_filetype_set(GObject *obj, GeanyDocument *doc, GeanyFiletype *ft_old, MarkdownPlugin *plugin); +static void on_template_menu_item_activate(GtkCheckMenuItem *item, MarkdownPlugin *plugin); +static void on_view_position_menu_item_activate(GtkCheckMenuItem *item, MarkdownPlugin *plugin); +static void on_view_readme_activate(GtkMenuItem *item, MarkdownPlugin *plugin); +static GSList *get_all_templates(void); + +/* Main plugin entry point on plugin load. */ +void plugin_init(GeanyData *data) +{ + GtkMenu *menu, *tmpl_menu, *pos_menu; + GtkWidget *itm, *tmpl_item, *pos_item; + GSList *iter, *templates; + GSList *radio_group = NULL; + gchar *conf_fn, *conf_tmpl_name, *readme_fn; + MarkdownViewPosition view_pos; + + conf_fn = g_build_filename(geany->app->configdir, "plugins", "markdown", + "markdown.conf", NULL); + markdown_plugin.conf = markdown_conf_new(conf_fn); + g_free(conf_fn); + conf_tmpl_name = markdown_conf_get_template_name(markdown_plugin.conf); + view_pos = markdown_conf_get_view_position(markdown_plugin.conf); + + switch (view_pos) { + case MARKDOWN_VIEW_POS_MSGWIN: + markdown_plugin.viewer = markdown_viewer_new( + GTK_NOTEBOOK(geany->main_widgets->message_window_notebook)); + break; + case MARKDOWN_VIEW_POS_SIDEBAR: + default: + markdown_plugin.viewer = markdown_viewer_new( + GTK_NOTEBOOK(geany->main_widgets->sidebar_notebook)); + break; + } + markdown_conf_set_view_position(markdown_plugin.conf, view_pos); + handle_conf_save_later(&markdown_plugin); + + markdown_plugin.menu_item = gtk_menu_item_new_with_label(_("Markdown")); + menu = GTK_MENU(gtk_menu_new()); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(markdown_plugin.menu_item), GTK_WIDGET(menu)); + gtk_menu_shell_append(GTK_MENU_SHELL(geany->main_widgets->tools_menu), markdown_plugin.menu_item); + + pos_item = gtk_menu_item_new_with_label(_("Position")); + pos_menu = GTK_MENU(gtk_menu_new()); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(pos_item), GTK_WIDGET(pos_menu)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), pos_item); + + itm = gtk_radio_menu_item_new_with_label(radio_group, _("Sidebar")); + radio_group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(itm)); + gtk_menu_shell_append(GTK_MENU_SHELL(pos_menu), itm); + g_object_set_data(G_OBJECT(itm), "pos", + GINT_TO_POINTER((gint) MARKDOWN_VIEW_POS_SIDEBAR)); + g_signal_connect(G_OBJECT(itm), "activate", + G_CALLBACK(on_view_position_menu_item_activate), &markdown_plugin); + if (view_pos == MARKDOWN_VIEW_POS_SIDEBAR) + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(itm), TRUE); + + itm = gtk_radio_menu_item_new_with_label(radio_group, _("Message Window")); + radio_group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(itm)); + gtk_menu_shell_append(GTK_MENU_SHELL(pos_menu), itm); + g_object_set_data(G_OBJECT(itm), "pos", + GINT_TO_POINTER((gint) MARKDOWN_VIEW_POS_MSGWIN)); + g_signal_connect(G_OBJECT(itm), "activate", + G_CALLBACK(on_view_position_menu_item_activate), &markdown_plugin); + if (view_pos == MARKDOWN_VIEW_POS_MSGWIN) + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(itm), TRUE); + /* ... */ + radio_group = NULL; /* for tmpl items */ + + tmpl_item = gtk_menu_item_new_with_label(_("Template")); + tmpl_menu = GTK_MENU(gtk_menu_new()); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(tmpl_item), GTK_WIDGET(tmpl_menu)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), tmpl_item); + + templates = get_all_templates(); + for (iter = templates; iter != NULL; iter = g_slist_next(iter)) { + MarkdownTemplate *t = (MarkdownTemplate*) iter->data; + itm = gtk_radio_menu_item_new_with_label(radio_group, + markdown_template_get_name(t)); + radio_group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(itm)); + /* Menu items take ownership of the templates */ + g_object_set_data_full(G_OBJECT(itm), "tmpl", t, (GDestroyNotify) markdown_template_free); + gtk_menu_shell_append(GTK_MENU_SHELL(tmpl_menu), itm); + g_signal_connect(G_OBJECT(itm), "activate", G_CALLBACK(on_template_menu_item_activate), + &markdown_plugin); + if (g_strcmp0(markdown_template_get_name(t), conf_tmpl_name) == 0) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(itm), TRUE); + markdown_viewer_set_template(markdown_plugin.viewer, t); + ui_set_statusbar(TRUE, _("Activated Markdown template: %s"), + markdown_template_get_name(t)); + } + } + g_slist_free(templates); + g_free(conf_tmpl_name); + + itm = gtk_menu_item_new_with_label("README.md"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), itm); + g_signal_connect(G_OBJECT(itm), "activate", G_CALLBACK(on_view_readme_activate), + &markdown_plugin); + + gtk_widget_show_all(markdown_plugin.menu_item); + + plugin_signal_connect(geany_plugin, NULL, "editor-notify", TRUE, + G_CALLBACK(on_editor_notify), &markdown_plugin); + plugin_signal_connect(geany_plugin, NULL, "document-activate", TRUE, + G_CALLBACK(on_document_signal), &markdown_plugin); + plugin_signal_connect(geany_plugin, NULL, "document-filetype-set", TRUE, + G_CALLBACK(on_document_filetype_set), &markdown_plugin); + plugin_signal_connect(geany_plugin, NULL, "document-new", TRUE, + G_CALLBACK(on_document_signal), &markdown_plugin); + plugin_signal_connect(geany_plugin, NULL, "document-open", TRUE, + G_CALLBACK(on_document_signal), &markdown_plugin); + plugin_signal_connect(geany_plugin, NULL, "document-reload", TRUE, + G_CALLBACK(on_document_signal), &markdown_plugin); + + handle_update_later(&markdown_plugin); + + /* Prevent segmentation fault when plugin is reloaded. */ + plugin_module_make_resident(geany_plugin); + + /* On the first load show the README.md file */ + if (!markdown_conf_get_readme_shown(markdown_plugin.conf)) { + readme_fn = g_build_filename(MARKDOWN_DOC_DIR, "README.md", NULL); + document_open_file(readme_fn, TRUE, NULL, NULL); + g_free(readme_fn); + markdown_conf_set_readme_shown(markdown_plugin.conf, TRUE); + handle_conf_save_later(&markdown_plugin); + } +} + +/* Cleanup resources on plugin unload. */ +void plugin_cleanup(void) +{ + markdown_conf_save(markdown_plugin.conf); + markdown_conf_free(markdown_plugin.conf); + gtk_widget_destroy(markdown_plugin.menu_item); + markdown_viewer_free(markdown_plugin.viewer); + return; +} + +/* Save configuration file when idle. */ +static gboolean on_conf_idle_handler(MarkdownPlugin *plugin) +{ + markdown_conf_save(plugin->conf); + plugin->handler_ids.save_conf = 0; + return FALSE; +} + +/* Queue a configuration file save later if one isn't queued. */ +static void handle_conf_save_later(MarkdownPlugin *plugin) +{ + if (plugin->handler_ids.save_conf == 0) { + plugin->handler_ids.save_conf = plugin_idle_add(geany_plugin, + (GSourceFunc) on_conf_idle_handler, plugin); + } +} + +/* Update markdown preview when idle. */ +static gboolean on_idle_handler(MarkdownPlugin *plugin) +{ + gchar *md_text; + GeanyDocument *doc = document_get_current(); + + /* Only handle valid Markdown documents */ + if (!DOC_VALID(doc) || g_strcmp0(doc->file_type->name, "Markdown") != 0) { + markdown_viewer_update_content(plugin->viewer, + _("The current document does not have a Markdown filetype.")); + plugin->handler_ids.update_view = 0; + return FALSE; + } + + md_text = (gchar*) scintilla_send_message(doc->editor->sci, + SCI_GETCHARACTERPOINTER, 0, 0); + markdown_viewer_update_content(plugin->viewer, md_text); + + plugin->handler_ids.update_view = 0; + + return FALSE; +} + +/* Queue update of the markdown view later if an update isn't queued. */ +static void handle_update_later(MarkdownPlugin *plugin) +{ + if (plugin->handler_ids.update_view == 0) { + plugin->handler_ids.update_view = plugin_idle_add(geany_plugin, + (GSourceFunc) on_idle_handler, plugin); + } +} + +/* Queue update of the markdown preview on editor text change. */ +static gboolean on_editor_notify(GObject *obj, GeanyEditor *editor, + SCNotification *notif, MarkdownPlugin *plugin) +{ + GeanyDocument *doc = document_get_current(); + + if (DOC_VALID(doc) && g_strcmp0(doc->file_type->name, "Markdown") == 0 && + notif->nmhdr.code == SCN_MODIFIED && + ((notif->modificationType & SC_MOD_INSERTTEXT) || (notif->modificationType & SC_MOD_DELETETEXT)) && + notif->length > 0) + { + handle_update_later(plugin); + } + + return FALSE; +} + +/* Queue update of the markdown preview on document signals (new, open, + * activate, etc.) */ +static void on_document_signal(GObject *obj, GeanyDocument *doc, MarkdownPlugin *plugin) +{ + handle_update_later(plugin); +} + +/* Queue update of the markdown preview when a document's filetype is set */ +static void on_document_filetype_set(GObject *obj, GeanyDocument *doc, GeanyFiletype *ft_old, + MarkdownPlugin *plugin) +{ + handle_update_later(plugin); +} + +/* Change the active markdown preview template when the menu item is clicked. */ +static void on_template_menu_item_activate(GtkCheckMenuItem *item, MarkdownPlugin *plugin) +{ + MarkdownTemplate *tmpl; + + { /* FIXME: this is stupid */ + static gboolean inhibit = FALSE; + if (inhibit) { return; } + inhibit = TRUE; + gtk_check_menu_item_set_active(item, !gtk_check_menu_item_get_active(item)); + inhibit = FALSE; + } + + tmpl = (MarkdownTemplate *) g_object_get_data(G_OBJECT(item), "tmpl"); + markdown_viewer_set_template(plugin->viewer, tmpl); + + handle_update_later(plugin); + + ui_set_statusbar(TRUE, _("Activated Markdown template: %s"), + markdown_template_get_name(tmpl)); + + markdown_conf_set_template_name(plugin->conf, markdown_template_get_name(tmpl)); + handle_conf_save_later(plugin); +} + +/* Change the position/location of the view (ex. sidebar, msgwin, etc.) */ +static void on_view_position_menu_item_activate(GtkCheckMenuItem *item, MarkdownPlugin *plugin) +{ + gpointer pos_as_ptr = g_object_get_data(G_OBJECT(item), "pos"); + gint pos = GPOINTER_TO_INT(pos_as_ptr); + MarkdownViewPosition old_pos = markdown_conf_get_view_position(plugin->conf); + + /* It hasn't changed positions */ + if ((gint) old_pos == pos) + return; + + switch (pos) { + case MARKDOWN_VIEW_POS_MSGWIN: + markdown_viewer_set_notebook(plugin->viewer, + GTK_NOTEBOOK(geany->main_widgets->message_window_notebook)); + break; + case MARKDOWN_VIEW_POS_SIDEBAR: + default: + markdown_viewer_set_notebook(plugin->viewer, + GTK_NOTEBOOK(geany->main_widgets->sidebar_notebook)); + break; + } + + markdown_conf_set_view_position(plugin->conf, (MarkdownViewPosition) pos); + handle_conf_save_later(plugin); +} + +static void on_view_readme_activate(GtkMenuItem *item, MarkdownPlugin *plugin) +{ + gchar *readme_fn = g_build_filename(MARKDOWN_DOC_DIR, "README.md", NULL); + document_open_file(readme_fn, TRUE, NULL, NULL); + g_free(readme_fn); +} + +/* Retrieve a list of all templates in user config dir and sys config dir */ +static GSList *get_all_templates(void) +{ + GSList *list; + gchar *usr_dir, *sys_dir; + MarkdownTemplateManager *mgr; + + usr_dir = g_build_filename(geany->app->configdir, "plugins", "markdown", "templates", NULL); + sys_dir = g_build_filename(MARKDOWN_DATA_DIR, "templates", NULL); + + mgr = markdown_template_manager_new(usr_dir, sys_dir); + list = markdown_template_manager_list_templates(mgr); + markdown_template_manager_free(mgr); + + g_free(usr_dir); + g_free(sys_dir); + + return list; +} diff --git a/markdown/src/tmpl.c b/markdown/src/tmpl.c new file mode 100644 index 000000000..1dec4f3ec --- /dev/null +++ b/markdown/src/tmpl.c @@ -0,0 +1,143 @@ +/* + * tmpl.c - Part of the Geany Markdown plugin + * + * Copyright 2012 Matthew Brush + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include "tmpl.h" + +struct MarkdownTemplate { + gchar *name; + gchar *filename; + gchar *base_dir; + gchar *text; + gsize text_len; +}; + +static void markdown_template_load_file(MarkdownTemplate *tmpl) +{ + GError *error = NULL; + + g_return_if_fail(tmpl); + + g_free(tmpl->text); + tmpl->text = NULL; + tmpl->text_len = 0; + + if (!g_file_get_contents(tmpl->filename, &(tmpl->text), &(tmpl->text_len), &error)) { + g_warning("Unable to load template file '%s': %s", tmpl->filename, + error->message); + g_error_free(error); error = NULL; + tmpl->text = g_strdup(""); + tmpl->text_len = 0; + } +} + +MarkdownTemplate *markdown_template_new(const gchar *tmpl_name, + const gchar *tmpl_file) +{ + MarkdownTemplate *tmpl = g_slice_new0(MarkdownTemplate); + if (tmpl) { + markdown_template_set_name(tmpl, tmpl_name); + markdown_template_set_filename(tmpl, tmpl_file); + } + return tmpl; +} + +void markdown_template_free(MarkdownTemplate *tmpl) +{ + if (tmpl) { + g_free(tmpl->name); + g_free(tmpl->filename); + g_free(tmpl->base_dir); + g_free(tmpl->text); + g_slice_free1(sizeof(MarkdownTemplate), tmpl); + } +} + +const gchar *markdown_template_get_name(MarkdownTemplate *tmpl) +{ + g_return_val_if_fail(tmpl, NULL); + return (const gchar *) tmpl->name; +} + +void markdown_template_set_name(MarkdownTemplate *tmpl, const gchar *name) +{ + g_return_if_fail(tmpl); + g_free(tmpl->name); + tmpl->name = name ? g_strdup(name) : g_strdup(""); +} + +const gchar *markdown_template_get_filename(MarkdownTemplate *tmpl) +{ + g_return_val_if_fail(tmpl, NULL); + return (const gchar *) tmpl->filename; +} + +const gchar *markdown_template_get_base_dir(MarkdownTemplate *tmpl) +{ + g_return_val_if_fail(tmpl, NULL); + return (const gchar *) tmpl->base_dir; +} + +void markdown_template_set_filename(MarkdownTemplate *tmpl, const gchar *filename) +{ + g_return_if_fail(tmpl); + g_free(tmpl->filename); + tmpl->filename = filename ? g_strdup(filename) : g_strdup(""); + tmpl->base_dir = filename ? g_path_get_dirname(tmpl->filename) : g_strdup(""); +} + +const gchar *markdown_template_get_text(MarkdownTemplate *tmpl, gsize *len) +{ + g_return_val_if_fail(tmpl, NULL); + + /* This is here to delay loading the file and allocating a bunch of + * memory until the template text actually needs to be read. */ + if (tmpl->text == NULL || tmpl->text_len == 0) { + markdown_template_load_file(tmpl); + } + + if (len) { + *len = tmpl->text_len; + } + + return (const gchar *) tmpl->text; +} + +gchar *markdown_template_replace(MarkdownTemplate *tmpl, const gchar *replacement, + gsize *replaced_len) +{ + gchar *repl, **parts; + const gchar *tmpl_text; + + g_return_val_if_fail(tmpl, NULL); + + tmpl_text = markdown_template_get_text(tmpl, NULL); + parts = g_strsplit(tmpl_text, MARKDOWN_TEMPLATE_STRING, 0); + repl = g_strjoinv(replacement, parts); + g_strfreev(parts); + + if (replaced_len) { + *replaced_len = strlen(repl); + } + + return repl; +} diff --git a/markdown/src/tmpl.h b/markdown/src/tmpl.h new file mode 100644 index 000000000..b533b08f5 --- /dev/null +++ b/markdown/src/tmpl.h @@ -0,0 +1,51 @@ +/* + * tmpl.h - Part of the Geany Markdown plugin + * + * Copyright 2012 Matthew Brush + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef MARKDOWN_TEMPLATE_H +#define MARKDOWN_TEMPLATE_H 1 + +G_BEGIN_DECLS + +#include + +#define MARKDOWN_TEMPLATE_STRING "" + +typedef struct MarkdownTemplate MarkdownTemplate; + +MarkdownTemplate *markdown_template_new(const gchar *tmpl_name, + const gchar *tmpl_file); + +void markdown_template_free(MarkdownTemplate *tmpl); + +const gchar *markdown_template_get_name(MarkdownTemplate *tmpl); +const gchar *markdown_template_get_filename(MarkdownTemplate *tmpl); +const gchar *markdown_template_get_base_dir(MarkdownTemplate *tmpl); +const gchar *markdown_template_get_text(MarkdownTemplate *tmpl, gsize *len); + +void markdown_template_set_name(MarkdownTemplate *tmpl, const gchar *name); +void markdown_template_set_filename(MarkdownTemplate *tmpl, const gchar *filename); + +gchar *markdown_template_replace(MarkdownTemplate *tmpl, const gchar *replacement, + gsize *replaced_len); + +G_END_DECLS + +#endif /* MARKDOWN_TEMPLATE_H */ diff --git a/markdown/src/tmplmgr.c b/markdown/src/tmplmgr.c new file mode 100644 index 000000000..f77295db9 --- /dev/null +++ b/markdown/src/tmplmgr.c @@ -0,0 +1,149 @@ +/* + * tmplmgr.c - Part of the Geany Markdown plugin + * + * Copyright 2012 Matthew Brush + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include "tmpl.h" +#include "tmplmgr.h" + +struct MarkdownTemplateManager { + gchar *user_path; + gchar *system_path; + MarkdownTemplate *template; +}; + +MarkdownTemplateManager *markdown_template_manager_new(const gchar *user_path, + const gchar *system_path) +{ + MarkdownTemplateManager *tmplmgr = g_slice_new0(MarkdownTemplateManager); + if (tmplmgr) { + tmplmgr->user_path = g_strdup(user_path); + tmplmgr->system_path = g_strdup(system_path); + } + return tmplmgr; +} + +void markdown_template_manager_free(MarkdownTemplateManager *mgr) +{ + g_return_if_fail(mgr); + g_free(mgr->user_path); + g_free(mgr->system_path); + g_slice_free(MarkdownTemplateManager, mgr); +} + +static GSList *markdown_template_manager_read_templates_from_dir( + MarkdownTemplateManager *mgr, const gchar *dirpath) +{ + GError *error = NULL; + GSList *list = NULL; + GDir *dir; + const gchar *ent; + + dir = g_dir_open(dirpath, 0, &error); + + if (!dir) { + /*g_warning("Error opening directory '%s': %s", dirpath, error->message);*/ + g_error_free(error); error = NULL; + return NULL; + } + + while ((ent = g_dir_read_name(dir)) != NULL) { + MarkdownTemplate *tmpl; + gchar *path, *tmpl_name, *tmpl_file; + if (g_strcmp0(ent, ".") == 0 || g_strcmp0(ent, "..") == 0) + continue; + path = g_build_filename(dirpath, ent, NULL); + tmpl_file = g_build_filename(path, "index.html", NULL); + tmpl_name = g_path_get_dirname(tmpl_file); + gchar *last_slash = strrchr(tmpl_name, '/'); + if (last_slash) { + last_slash++; + g_memmove(tmpl_name, last_slash, strlen(last_slash) + 1); + } + if (g_file_test(tmpl_file, G_FILE_TEST_EXISTS)) { + tmpl = markdown_template_new(tmpl_name, tmpl_file); + list = g_slist_prepend(list, tmpl); + } + g_free(path); + g_free(tmpl_name); + g_free(tmpl_file); + } + + return list; +} + +static gboolean markdown_template_manager_list_has_template( + MarkdownTemplateManager *mgr, GSList *list, const gchar *tmpl_name) +{ + GSList *iter; + gboolean result = FALSE; + + for (iter = list; iter != NULL; iter = g_slist_next(iter)) { + MarkdownTemplate *tmpl = (MarkdownTemplate*) iter->data; + if (g_strcmp0(markdown_template_get_name(tmpl), tmpl_name) == 0) { + result = TRUE; + break; + } + } + + return result; +} + +static GSList *markdown_template_manager_combine_lists(MarkdownTemplateManager *mgr, + GSList *user_list, GSList *system_list) +{ + GSList *list = NULL, *iter; + + for (iter = user_list; iter != NULL; iter = g_slist_next(iter)) { + MarkdownTemplate *tmpl = (MarkdownTemplate*) iter->data; + if (!markdown_template_manager_list_has_template(mgr, list, + markdown_template_get_name(tmpl))) { + list = g_slist_prepend(list, tmpl); + } + } + + for (iter = system_list; iter != NULL; iter = g_slist_next(iter)) { + MarkdownTemplate *tmpl = (MarkdownTemplate*) iter->data; + if (!markdown_template_manager_list_has_template(mgr, list, + markdown_template_get_name(tmpl))) { + list = g_slist_prepend(list, tmpl); + } + } + + return list; +} + +GSList *markdown_template_manager_list_templates(MarkdownTemplateManager *mgr) +{ + GSList *list, *user_list, *system_list; + + g_return_val_if_fail(mgr, NULL); + + user_list = markdown_template_manager_read_templates_from_dir(mgr, mgr->user_path); + system_list = markdown_template_manager_read_templates_from_dir(mgr, mgr->system_path); + + list = markdown_template_manager_combine_lists(mgr, user_list, system_list); + + g_slist_free(user_list); + g_slist_free(system_list); + + return list; +} diff --git a/markdown/src/tmplmgr.h b/markdown/src/tmplmgr.h new file mode 100644 index 000000000..46894faee --- /dev/null +++ b/markdown/src/tmplmgr.h @@ -0,0 +1,40 @@ +/* + * tmplmgr.h - Part of the Geany Markdown plugin + * + * Copyright 2012 Matthew Brush + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef MARKDOWN_TEMPLATE_MANAGER_H +#define MARKDOWN_TEMPLATE_MANAGER_H 1 + +#include + +G_BEGIN_DECLS + +#include "tmpl.h" + +typedef struct MarkdownTemplateManager MarkdownTemplateManager; + +MarkdownTemplateManager *markdown_template_manager_new(const gchar *user_path, + const gchar *system_path); +void markdown_template_manager_free(MarkdownTemplateManager *mgr); +GSList *markdown_template_manager_list_templates(MarkdownTemplateManager *mgr); + +G_END_DECLS + +#endif /* MARKDOWN_TEMPLATE_MANAGER_H */ diff --git a/markdown/src/viewer.c b/markdown/src/viewer.c new file mode 100644 index 000000000..621fb482e --- /dev/null +++ b/markdown/src/viewer.c @@ -0,0 +1,141 @@ +/* + * viewer.c - Part of the Geany Markdown plugin + * + * Copyright 2012 Matthew Brush + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include +#include "viewer.h" +#include "md.h" + +#define MARKDOWN_VIEWER_TAB_LABEL _("Markdown Preview") + +struct MarkdownViewer { + GtkScrolledWindow *scrolled_win; /* The GtkScrolledWindow containing the WebKitView */ + WebKitWebView *webview; /* The Webkit preview widget */ + GtkNotebook *notebook; /* Either the sidebar notebook or the msgwin notebook */ + MarkdownTemplate *template; /* The active preview template */ + gdouble old_pos; /* Position before reload, used to reset scroll pos. */ +}; + +MarkdownViewer *markdown_viewer_new(GtkNotebook *notebook) +{ + MarkdownViewer *tmpl = g_slice_new0(MarkdownViewer); + if (tmpl) { + tmpl->scrolled_win = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL)); + tmpl->webview = WEBKIT_WEB_VIEW(webkit_web_view_new()); + gtk_container_add(GTK_CONTAINER(tmpl->scrolled_win), GTK_WIDGET(tmpl->webview)); + gtk_scrolled_window_set_policy(tmpl->scrolled_win, GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + tmpl->notebook = notebook; + gtk_notebook_append_page(tmpl->notebook, GTK_WIDGET(tmpl->scrolled_win), + gtk_label_new(MARKDOWN_VIEWER_TAB_LABEL)); + gtk_widget_show_all(GTK_WIDGET(notebook)); + } + return tmpl; +} + +void markdown_viewer_free(MarkdownViewer *viewer) +{ + if (viewer) { + gtk_widget_destroy(GTK_WIDGET(viewer->scrolled_win)); + g_slice_free(MarkdownViewer, viewer); + } +} + +GtkNotebook *markdown_viewer_get_notebook(MarkdownViewer *viewer) +{ + g_return_val_if_fail(viewer, NULL); + return viewer->notebook; +} + +void markdown_viewer_set_notebook(MarkdownViewer *viewer, GtkNotebook *nb) +{ + gint page_num; + + g_return_if_fail(viewer); + g_return_if_fail(GTK_IS_NOTEBOOK(nb)); + + g_object_ref(G_OBJECT(viewer->scrolled_win)); + + page_num = gtk_notebook_page_num(viewer->notebook, GTK_WIDGET(viewer->scrolled_win)); + gtk_notebook_remove_page(viewer->notebook, page_num); + + viewer->notebook = nb; + + page_num = gtk_notebook_append_page(viewer->notebook, GTK_WIDGET(viewer->scrolled_win), + gtk_label_new(MARKDOWN_VIEWER_TAB_LABEL)); + + /*gtk_notebook_set_current_page(viewer->notebook, page_num);*/ + + g_object_unref(G_OBJECT(viewer->scrolled_win)); +} + +MarkdownTemplate *markdown_viewer_get_template(MarkdownViewer *viewer) +{ + g_return_val_if_fail(viewer, NULL); + return viewer->template; +} + +void markdown_viewer_set_template(MarkdownViewer *viewer, MarkdownTemplate *tmpl) +{ + g_return_if_fail(viewer && tmpl); + viewer->template = tmpl; +} + +void on_viewer_load_status_notify(GObject *obj, GParamSpec *pspec, MarkdownViewer *viewer) +{ + GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(viewer->scrolled_win); + gtk_adjustment_set_value(vadj, viewer->old_pos); + while (gtk_events_pending()) { + gtk_main_iteration(); + } +} + +void markdown_viewer_update_content(MarkdownViewer *viewer, const gchar *text) +{ + g_return_if_fail(viewer); + gchar *html = markdown_to_html(text); + gchar *new_text = markdown_template_replace(viewer->template, html, NULL); + GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(viewer->scrolled_win); + viewer->old_pos = gtk_adjustment_get_value(vadj); + g_free(html); + if (new_text) { + gchar *base_uri = g_strdup_printf("file://%s", + markdown_template_get_filename(viewer->template)); + g_signal_connect(viewer->webview, "notify::load-status", + G_CALLBACK(on_viewer_load_status_notify), viewer); + webkit_web_view_load_string(viewer->webview, new_text, "text/html", "UTF-8", base_uri); + g_free(new_text); + g_free(base_uri); + } +} + +void markdown_viewer_show(MarkdownViewer *viewer) +{ + g_return_if_fail(viewer); + gtk_widget_show(GTK_WIDGET(viewer->scrolled_win)); +} + +void markdown_viewer_hide(MarkdownViewer *viewer) +{ + g_return_if_fail(viewer); + gtk_widget_hide(GTK_WIDGET(viewer->scrolled_win)); +} diff --git a/markdown/src/viewer.h b/markdown/src/viewer.h new file mode 100644 index 000000000..22e29d18c --- /dev/null +++ b/markdown/src/viewer.h @@ -0,0 +1,48 @@ +/* + * viewer.h - Part of the Geany Markdown plugin + * + * Copyright 2012 Matthew Brush + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef MARKDOWN_VIEWER_H +#define MARKDOWN_VIEWER_H 1 + +G_BEGIN_DECLS + +#include +#include "tmpl.h" + +typedef struct MarkdownViewer MarkdownViewer; + +MarkdownViewer *markdown_viewer_new(GtkNotebook *notebook); +void markdown_viewer_free(MarkdownViewer *viewer); + +GtkNotebook *markdown_viewer_get_notebook(MarkdownViewer *viewer); +void markdown_viewer_set_notebook(MarkdownViewer *viewer, GtkNotebook *nb); + +MarkdownTemplate *markdown_viewer_get_template(MarkdownViewer *viewer); +void markdown_viewer_set_template(MarkdownViewer *viewer, MarkdownTemplate *tmpl); + +void markdown_viewer_show(MarkdownViewer *viewer); +void markdown_viewer_hide(MarkdownViewer *viewer); + +void markdown_viewer_update_content(MarkdownViewer *viewer, const gchar *text); + +G_END_DECLS + +#endif /* MARKDOWN_VIEWER_H */ diff --git a/markdown/templates/Alternate/Makefile.am b/markdown/templates/Alternate/Makefile.am new file mode 100644 index 000000000..7e155dfbc --- /dev/null +++ b/markdown/templates/Alternate/Makefile.am @@ -0,0 +1,3 @@ + +deftmpldir = $(pkgdatadir)/markdown/templates/Alternate +deftmpl_DATA = index.html diff --git a/markdown/templates/Alternate/index.html b/markdown/templates/Alternate/index.html new file mode 100644 index 000000000..4ef8583bf --- /dev/null +++ b/markdown/templates/Alternate/index.html @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/markdown/templates/Default/Makefile.am b/markdown/templates/Default/Makefile.am new file mode 100644 index 000000000..64816186e --- /dev/null +++ b/markdown/templates/Default/Makefile.am @@ -0,0 +1,3 @@ + +deftmpldir = $(pkgdatadir)/markdown/templates/Default +deftmpl_DATA = index.html diff --git a/markdown/templates/Default/index.html b/markdown/templates/Default/index.html new file mode 100644 index 000000000..562d7cecc --- /dev/null +++ b/markdown/templates/Default/index.html @@ -0,0 +1,5 @@ + + + + + diff --git a/markdown/templates/Makefile.am b/markdown/templates/Makefile.am new file mode 100644 index 000000000..ce5a2840b --- /dev/null +++ b/markdown/templates/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = Default Alternate