diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 2cc921b2..7d4356d4 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,32 +1,32 @@ # This cmake file are managing embedded 3party Cantor dependencies # 3dparty patched Discount # Embedded for a while include(ExternalProject) set (DISCOUNT_ONLY_LIBRARY ON) set (DISCOUNT_MAKE_INSTALL OFF) ExternalProject_Add( discount_project - URL ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/discount-2.2.6-patched.tar + URL ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/discount-2.2.6-patched SOURCE_SUBDIR cmake CMAKE_ARGS DISCOUNT_ONLY_LIBRARY DISCOUNT_MAKE_INSTALL CMAKE_CACHE_ARGS "-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true" PREFIX ${CMAKE_CURRENT_BINARY_DIR}/thirdparty STEP_TARGETS configure build EXCLUDE_FROM_ALL TRUE ) ExternalProject_Get_Property(discount_project source_dir) ExternalProject_Get_Property(discount_project binary_dir) add_library(Discount::Lib STATIC IMPORTED) set_target_properties(Discount::Lib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${source_dir} IMPORTED_LOCATION ${binary_dir}/libmarkdown${CMAKE_STATIC_LIBRARY_SUFFIX} POSITION_INDEPENDENT_CODE ON ) add_dependencies(Discount::Lib discount_project-build) set(Discount_FOUND TRUE) # preview.sty install(FILES thirdparty/standalone.cls DESTINATION ${KDE_INSTALL_DATADIR}/cantor/latex ) diff --git a/thirdparty/README.md b/thirdparty/README.md new file mode 100644 index 00000000..4b1a6993 --- /dev/null +++ b/thirdparty/README.md @@ -0,0 +1,20 @@ +## 3rd party libraries + +This folder contains (patched) versions of libraries and files Cantor depends on. + + +## DISCOUNT + +DISCOUNT is a implementation of Markdown markup language ([link](https://github.com/Orc/discount)). + +The version included here provides two additional patches: + +* Better LaTeX support: `$` math delimiter and `mkd_e_latex` callback (https://github.com/Orc/discount/pull/214) + +* Better recognition of the mathematical expressions between $...$, $$...$$ + + +## standalone.cls +This file provides the LaTeX class and package 'standalone' ([link](https://ctan.org/tex-archive/macros/latex/contrib/standalone)), +which allows TeX pictures or other TeX code in sub-files to be compiled standalone or as part of a main document. +This package is used for the rendering of mathematical LaTeX expressions embedded in the Cantor's worksheet. diff --git a/thirdparty/discount-2.2.6-patched.tar b/thirdparty/discount-2.2.6-patched.tar deleted file mode 100644 index 28da1cf3..00000000 Binary files a/thirdparty/discount-2.2.6-patched.tar and /dev/null differ diff --git a/thirdparty/discount-2.2.6-patched/COPYRIGHT b/thirdparty/discount-2.2.6-patched/COPYRIGHT new file mode 100644 index 00000000..cab1d3d6 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/COPYRIGHT @@ -0,0 +1,30 @@ +->Copyright (C) 2007 David Loren Parsons. +All rights reserved.<- + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of works must retain the original copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the original copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither my name (David L Parsons) nor the names of contributors to + this code may be used to endorse or promote products derived + from this work without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS 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 THE +COPYRIGHT OWNER OR CONTRIBUTORS 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/thirdparty/discount-2.2.6-patched/CREDITS b/thirdparty/discount-2.2.6-patched/CREDITS new file mode 100644 index 00000000..a806a53b --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/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.portland.or.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/thirdparty/discount-2.2.6-patched/Csio.c b/thirdparty/discount-2.2.6-patched/Csio.c new file mode 100644 index 00000000..1b418e0c --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/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, mkd_flag_t flags) +{ + MMIOT f; + ___mkd_initmmiot(&f, 0); + ___mkd_reparse(buf, size, flags, &f, 0); + ___mkd_emblock(&f); + SUFFIX(*iot, T(f.out), S(f.out)); + ___mkd_freemmiot(&f, 0); +} diff --git a/thirdparty/discount-2.2.6-patched/INSTALL b/thirdparty/discount-2.2.6-patched/INSTALL new file mode 100644 index 00000000..8e6c4dc5 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/INSTALL @@ -0,0 +1,65 @@ + + HOW TO BUILD AND INSTALL DISCOUNT + +1) Unpacking the distribution + +The DISCOUNT sources are distributed in tarballs. After extracting from +the tarball, you should end up with all the source and build files in the +directory + discount-(version) + +2) Installing the distribution + +DISCOUNT uses configure.sh to set itself up for compilation. To run +configure, just do ``./configure.sh'' and it will check your system for +build dependencies and build makefiles for you. If configure.sh finishes +without complaint, you can then do a ``make'' to compile everything and a +``make install'' to install the binaries. + +Configure.sh has a few options that can be set: + +--src=DIR where the source lives (.) +--prefix=DIR where to install the final product (/usr/local) +--execdir=DIR where to put executables (prefix/bin) +--sbindir=DIR where to put static executables (prefix/sbin) +--confdir=DIR where to put configuration information (/etc) +--libdir=DIR where to put libraries (prefix/lib) +--libexecdir=DIR where to put private executables +--mandir=DIR where to put manpages +--with-amalloc Use my paranoid malloc library to catch memory leaks +--shared Build shared libraries +--debian-glitch When mangling email addresses, do them deterministically + so the Debian regression tester won't complain +--pkg-config Build & install a pkg-config(1) .pc file for + the discount library. +--h1-title Have theme & mkd2html use the first h1 in a document + as the title if there's no pandoc header or title + specified on the command line. +--cxx-binding Wrap mkdio.h with (conditional) 'extern "C"' for c++ + binding. + +3) Testing + +``make test'' runs discount against a collection of test cases. + + +4) Installing sample programs and manpages + +The standard ``make install'' rule just installs the binaries. If you +want to install the sample programs, they are installed with +``make install.samples''; to install manpages, ``make install.man''. +A shortcut to install everything is ``make install.everything'' + + +5) Assorted platform gotchas + + 1. On NetBSD (version 8 for certain) running configure.sh by + itself will result in logging output being mixed in with diagnostic + output on the screen instead of having it written to config.log. + If, instead, you do `ksh ./configure.sh`, it will be much less + garbled (the shell defaults all fds > stderr to close on exec, + so my redirecting stdout fails after the first subprocess.) + 2. On 9Front (and maybe every other extant plan9 variant) the + system mkfile sets the `T' flag in CFLAGS; there are several + places where I typedef voids to opaque structure pointers and + this makes the build die when it attempts to link anything. diff --git a/thirdparty/discount-2.2.6-patched/Makefile.in b/thirdparty/discount-2.2.6-patched/Makefile.in new file mode 100644 index 00000000..c7a10b66 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/Makefile.in @@ -0,0 +1,191 @@ +CC=@CC@ +CFLAGS=@CFLAGS@ +LDFLAGS=@LDFLAGS@ +AR=@AR@ +RANLIB=@RANLIB@ +INSTALL_PROGRAM=@INSTALL_PROGRAM@ +INSTALL_DIR=@INSTALL_DIR@ +INSTALL_DATA=@INSTALL_DATA@ + +BUILD=$(CC) -fPIC -I. $(CFLAGS) +LINK=$(CC) -fPIC -L. $(LDFLAGS) + +.c.o: + $(BUILD) -c -o $@ $< + + +BINDIR=@exedir@ +MANDIR=@mandir@ +LIBDIR=@libdir@ +INCDIR=@prefix@/include +@MK_PKGCONFIG@PKGDIR=$(LIBDIR)/pkgconfig + +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 \ + github_flavoured.o setup.o tags.o html5.o \ + @AMALLOC@ @H1TITLE@ flags.o +TESTFRAMEWORK=echo cols branch pandoc_headers + +# modules that markdown, makepage, mkd2html, &tc use +COMMON=pgm_options.o gethopt.o notspecial.o + +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) $(DESTDIR)$(PKGDIR) + $(INSTALL_PROGRAM) $(PGMS) $(DESTDIR)$(BINDIR) + ./librarian.sh install libmarkdown VERSION $(DESTDIR)$(LIBDIR) + $(INSTALL_DATA) mkdio.h $(DESTDIR)$(INCDIR) + @MK_PKGCONFIG@$(INSTALL_DATA) $(MKDLIB).pc $(DESTDIR)$(PKGDIR) + +install.everything: install install.samples install.man + +install.samples: $(SAMPLE_PGMS) install $(DESTDIR)$(BINDIR) + $(INSTALL_DIR) $(DESTDIR)$(MANDIR)/man1 + for x in $(SAMPLE_PGMS); do \ + $(INSTALL_PROGRAM) $$x $(DESTDIR)$(BINDIR)/$(SAMPLE_PFX)$$x; \ + $(INSTALL_DATA) $$x.1 $(DESTDIR)$(MANDIR)/man1/$(SAMPLE_PFX)$$x.1; \ + done + +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;\ + 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; \ + 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 + +install.everything: install install.man + +$(DESTDIR)$(BINDIR): + $(INSTALL_DIR) $(DESTDIR)$(BINDIR) + +$(DESTDIR)$(INCDIR): + $(INSTALL_DIR) $(DESTDIR)$(INCDIR) + +$(DESTDIR)$(LIBDIR): + $(INSTALL_DIR) $(DESTDIR)$(LIBDIR) + +@MK_PKGCONFIG@$(DESTDIR)$(PKGDIR): +@MK_PKGCONFIG@ $(INSTALL_DIR) $(DESTDIR)$(PKGDIR) + +version.o: version.c VERSION branch + $(BUILD) -DBRANCH=`./branch` -DVERSION=\"`cat VERSION`\" -c version.c + +VERSION: + @true + +tags.o: tags.c cstring.h tags.h blocktags + +blocktags: mktags + ./mktags > blocktags + +mktags: mktags.o + $(LINK) -o mktags mktags.o + +# example programs +@THEME@theme: theme.o $(COMMON) $(MKDLIB) mkdio.h +@THEME@ $(LINK) -o theme theme.o $(COMMON) -lmarkdown @LIBS@ + + +mkd2html: mkd2html.o $(MKDLIB) mkdio.h gethopt.h $(COMMON) + $(LINK) -o mkd2html mkd2html.o $(COMMON) -lmarkdown @LIBS@ + +markdown: main.o $(COMMON) $(MKDLIB) + $(LINK) -o markdown main.o $(COMMON) -lmarkdown @LIBS@ + +makepage.o: makepage.c mkdio.h + $(BUILD) -c makepage.c +makepage: makepage.o $(COMMON) $(MKDLIB) + $(LINK) -o makepage makepage.o $(COMMON) -lmarkdown @LIBS@ + +pgm_options.o: pgm_options.c mkdio.h config.h + $(BUILD) -c pgm_options.c + +notspecial.o: notspecial.c + $(BUILD) -c notspecial.c + +gethopt.o: gethopt.c + $(BUILD) -c gethopt.c + +main.o: main.c mkdio.h config.h + $(BUILD) -c main.c + +$(MKDLIB): $(OBJS) + ./librarian.sh make $(MKDLIB) VERSION $(OBJS) + +verify: echo tools/checkbits.sh + @./echo -n "headers ... "; tools/checkbits.sh && echo "GOOD" + +test: $(PGMS) $(TESTFRAMEWORK) verify + @for x in $${TESTS:-tests/*.t}; do \ + @LD_LIBRARY_PATH@=`pwd` sh $$x || exit 1; \ + done + +pandoc_headers.o: tools/pandoc_headers.c config.h + $(BUILD) -c -o pandoc_headers.o tools/pandoc_headers.c +pandoc_headers: pandoc_headers.o + $(LINK) -o pandoc_headers pandoc_headers.o $(COMMON) -lmarkdown + +branch.o: tools/branch.c config.h + $(BUILD) -c -o branch.o tools/branch.c +branch: branch.o + $(LINK) -o branch branch.o + +cols.o: tools/cols.c config.h + $(BUILD) -c -o cols.o tools/cols.c +cols: cols.o + $(LINK) -o cols cols.o + +echo.o: tools/echo.c config.h + $(BUILD) -c -o echo.o tools/echo.c +echo: echo.o + $(LINK) -o echo echo.o + +clean: + rm -f $(PGMS) $(TESTFRAMEWORK) $(SAMPLE_PGMS) *.o + rm -f $(MKDLIB) `./librarian.sh files $(MKDLIB) VERSION` + +distclean spotless: clean + @DISTCLEAN@ @GENERATED_FILES@ @CONFIGURE_FILES@ ./mktags ./blocktags + +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 +setup.o: setup.c config.h cstring.h amalloc.h markdown.h +github_flavoured.o: github_flavoured.c config.h cstring.h amalloc.h markdown.h +gethopt.o: gethopt.c gethopt.h +h1title.o: h1title.c markdown.h +notspecial.o: notspecial.c config.h diff --git a/thirdparty/discount-2.2.6-patched/Plan9/README.md b/thirdparty/discount-2.2.6-patched/Plan9/README.md new file mode 100644 index 00000000..b0ec8e3e --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/Plan9/README.md @@ -0,0 +1,33 @@ +# *Discount* Markdown compiler on Plan 9 + +## Build + % CONFIG='--with-tabstops=7' mk config + % mk test + % mk install + % markdown -V + markdown: discount X.Y.Z TAB=7 + +### Configuration +To select features and extensions, `--with-tabstops=7` may be replaced by zero or more of: + +* `--enable-pandoc-header`: Use pandoc-style header blocks +* `--enable-superscript`: `A^B` becomes AB +* `--enable-amalloc`: Enable memory allocation debugging +* `--with-tabstops=`*N*: Set tabstops to *N* characters (default 4) +* `--enable-alpha-list`: Enable `(a)/(b)/(c)` list markers +* `--enable-all-features`: Turn on all stable optional features + +## Notes +1. This is not a port from POSIX to native Plan 9 APIs. The supplied +`mkfile` merely drives Discount's own `configure.sh` through Plan 9's +*APE* environment (in *pcc*(1)) to build the Discount source, then +copies the result to locations appropriate for system-wide use on +Plan 9. + +2. There are a few other *mk*(1) targets: + * `install.libs`: Discount includes a C library and header. +Installation is optional. Plan 9 binaries are statically linked. + * `install.man`: Add manual pages for *markdown* in sections 1, 2, and 6. + * `install.progs`: Extra programs. *makepage* writes complete XHTML +documents, rather than fragments. *mkd2html* is similar, but produces +HTML. diff --git a/thirdparty/discount-2.2.6-patched/Plan9/markdown.1 b/thirdparty/discount-2.2.6-patched/Plan9/markdown.1 new file mode 100644 index 00000000..b38947f9 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/Plan9/markdown.1 @@ -0,0 +1,169 @@ +.TH MARKDOWN 1 +.SH NAME +markdown \- convert Markdown text to HTML +.SH SYNOPSIS +.B markdown +[ +.B -dTV +] +[ +.BI -b " url-base +] +[ +.BI -F " bitmap +] +[ +.BI -f " flags +] +[ +.BI -o " ofile +] +[ +.BI -s " text +] +[ +.BI -t " text +] +[ +.I file +] +.SH DESCRIPTION +The +.I markdown +utility reads the +.IR Markdown (6)-formatted +.I file +(or standard input) and writes its +.SM HTML +fragment representation on standard output. +.PP +The options are: +.TF dfdoptions +.TP +.BI -b " url-base +Links in source begining with +.B / +will be prefixed with +.I url-base +in the output. +.TP +.B -d +Instead of printing an +.SM HTML +fragment, print a parse tree. +.TP +.BI -F " bitmap +Set translation flags. +.I Bitmap +is a bit map of the various configuration options described in +.IR markdown (2). +.TP +.BI -f " flags +Set or clear various translation +.IR flags , +described below. +.I Flags +are in a comma-delimited list, with an optional +.B + +(set) prefix on each flag. +.TP +.BI -o " ofile +Write the generated +.SM HTML +to +.IR ofile . +.TP +.BI -s " text +Use the +.IR markdown (2) +function to format the +.I text +on standard input. +.TP +.B -T +Under +.B -f +.BR toc , +print the table of contents as an unordered list before the usual +.SM HTML +output. +.TP +.BI -t " text +Use +.IR mkd_text +(in +.IR markdown (2)) +to format +.I text +instead of processing standard input with +.IR markdown . +.TP +.B -V +Show version number and configuration. If the version includes the string +.BR DL_TAG , +.I markdown +was configured with definition list support. If the version includes the string +.BR HEADER , +.I markdown +was configured to support pandoc header blocks. +.PD +.SS TRANSLATION FLAGS +The translation flags understood by +.B -f +are: +.TF \ noheader +.TP +.B noimage +Don't allow image tags. +.TP +.B nolinks +Don't allow links. +.TP +.B nohtml +Don't allow any embedded HTML. +.TP +.B cdata +Generate valid XML output. +.TP +.B noheader +Do not process pandoc headers. +.TP +.B notables +Do not process the syntax extension for tables. +.TP +.B tabstops +Use Markdown-standard 4-space tabstops. +.TP +.B strict +Disable superscript and relaxed emphasis. +.TP +.B relax +Enable superscript and relaxed emphasis (the default). +.TP +.B toc +Enable table of contents support, generated from headings (in +.IR markdown (6)) +in the source. +.TP +.B 1.0 +Revert to Markdown 1.0 compatibility. +.PD +.PP +For example, +.B -f nolinks,quot +tells +.I markdown +not to allow +.B +tags, and to expand double quotes. +.SH SOURCE +.B /sys/src/cmd/discount +.SH SEE ALSO +.IR markdown (2), +.IR markdown (6) +.PP +http://daringfireball.net/projects/markdown/, +``Markdown''. +.SH DIAGNOSTICS +.I Markdown +exits 0 on success and >0 if an error occurs. diff --git a/thirdparty/discount-2.2.6-patched/Plan9/markdown.2 b/thirdparty/discount-2.2.6-patched/Plan9/markdown.2 new file mode 100644 index 00000000..d5ee04c1 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/Plan9/markdown.2 @@ -0,0 +1,332 @@ +.TH MARKDOWN 2 +.SH NAME +mkd_in, mkd_string, markdown, mkd_compile, mkd_css, mkd_generatecss, +mkd_document, mkd_generatehtml, mkd_xhtmlpage, mkd_toc, mkd_generatetoc, +mkd_cleanup, mkd_doc_title, mkd_doc_author, mkd_doc_date, mkd_line, +mkd_generateline \- convert Markdown text to HTML +.SH SYNOPSIS +.ta \w'MMIOT* 'u +.B #include +.PP +.B +MMIOT* mkd_in(FILE *input, int flags) +.PP +.B +MMIOT* mkd_string(char *buf, int size, int flags) +.PP +.B +int markdown(MMIOT *doc, FILE *output, int flags) +.PP +.B +int mkd_compile(MMIOT *document, int flags) +.PP +.B +int mkd_css(MMIOT *document, char **doc) +.PP +.B +int mkd_generatecss(MMIOT *document, FILE *output) +.PP +.B +int mkd_document(MMIOT *document, char **doc) +.PP +.B +int mkd_generatehtml(MMIOT *document, FILE *output) +.PP +.B +int mkd_xhtmlpage(MMIOT *document, int flags, FILE *output) +.PP +.B +int mkd_toc(MMIOT *document, char **doc) +.PP +.B +int mkd_generatetoc(MMIOT *document, FILE *output) +.PP +.B +void mkd_cleanup(MMIOT*); +.PP +.B +char* mkd_doc_title(MMIOT*) +.PP +.B +char* mkd_doc_author(MMIOT*) +.PP +.B +char* mkd_doc_date(MMIOT*) +.PP +.B +int mkd_line(char *string, int size, char **doc, int flags) +.PP +.B +int mkd_generateline(char *string, int size, FILE *output, int flags) +.PD +.PP +.SH DESCRIPTION +These functions convert +.IR Markdown (6) +text into +.SM HTML +markup. +.PP +.I Mkd_in +reads the text referenced by pointer to +.B FILE +.I input +and returns a pointer to an +.B MMIOT +structure of the form expected by +.I markdown +and the other converters. +.I Mkd_string +accepts one +.I string +and returns a pointer to +.BR MMIOT . +.PP +After such preparation, +.I markdown +converts +.I doc +and writes the result to +.IR output , +while +.I mkd_compile +transforms +.I document +in-place. +.PP +One or more of the following +.I flags +(combined with +.BR OR ) +control +.IR markdown 's +processing of +.IR doc : +.TF MKD_NOIMAGE +.TP +.B MKD_NOIMAGE +Do not process +.B ![] +and remove +.B +tags from the output. +.TP +.B MKD_NOLINKS +Do not process +.B [] +and remove +.B +tags from the output. +.TP +.B MKD_NOPANTS +Suppress Smartypants-style replacement of quotes, dashes, or ellipses. +.TP +.B MKD_STRICT +Disable superscript and relaxed emphasis processing. +.TP +.B MKD_TAGTEXT +Process as inside an +.SM HTML +tag: no +.BR , +no +.BR , +no +.SM HTML +or +.B [] +expansion. +.TP +.B MKD_NO_EXT +Don't process pseudo-protocols (in +.IR markdown (6)). +.TP +.B MKD_CDATA +Generate code for +.SM XML +.B ![CDATA[...]] +element. +.TP +.B MKD_NOHEADER +Don't process Pandoc-style headers. +.TP +.B MKD_TABSTOP +When reading documents, expand tabs to 4 spaces, overriding any compile-time configuration. +.TP +.B MKD_TOC +Label headings for use with the +.I mkd_generatetoc +and +.I mkd_toc +functions. +.TP +.B MKD_1_COMPAT +MarkdownTest_1.0 compatibility. Trim trailing spaces from first line of code blocks and disable implicit reference links (in +.IR markdown (6)). +.TP +.B MKD_AUTOLINK +Greedy +.SM URL +generation. When set, any +.SM URL +is converted to a hyperlink, even those not encased in +.BR <> . +.TP +.B MKD_SAFELINK +Don't make hyperlinks from +.B [][] +links that have unknown +.SM URL +protocol types. +.TP +.B MKD_NOTABLES +Do not process the syntax extension for tables (in +.IR markdown (6)). +.TP +.B MKD_EMBED +All of +.BR MKD_NOLINKS , +.BR MKD_NOIMAGE , +and +.BR MKD_TAGTEXT . +.PD +.PP +This implementation supports +Pandoc-style +headers and inline +.SM CSS +.B +at the end of the line or at the beginning of a subsequent line. +.IP +Style blocks apply to the entire document regardless of where they are defined. +.TP +Image Dimensions +Image specification has been extended with an argument describing image dimensions: +.BI = height x width. +For an image 400 pixels high and 300 wide, the new syntax is: +.IP +.EX + ![Alt text](/path/to/image.jpg =400x300 "Title") +.EE +.TP +Pseudo-Protocols +Pseudo-protocols that may replace the common +.B http: +or +.B mailto: +have been added to the link syntax described above. +.IP +.BR abbr : +Text following is used as the +.B title +attribute of an +.B abbr +tag wrapping the link text. So +.B [LT](abbr:Link Text) +gives +.B LT. +.IP +.BR id : +The link text is marked up and written to the output, wrapped with +.B +and +.BR . +.IP +.BR class : + The link text is marked up and written to the output, wrapped with +.B +and +.BR . +.IP +.BR raw : +Text following is written to the output with no further processing. +The link text is discarded. +.TP +Alphabetic Lists +If +.I markdown +was configured with +.BR --enable-alpha-list , +.IP +.EX +a. this +b. is +c. an alphabetic +d. list +.EE +.IP +yields an +.SM HTML +.B ol +ordered list. +.TP +Definition Lists +If configured with +.BR --enable-dl-tag , +markup for definition lists is enabled. A definition list item is defined as +.IP +.EX +=term= + definition +.EE +.TP +Tables +Tables are specified with a pipe +.RB ( | ) +and dash +.RB ( - ) +marking. The markdown text +.IP +.EX +header0|header1 +-------|------- + textA|textB + textC|textD +.EE +.IP +will produce an +.SM HTML +.B table +of two columns and three rows. +A header row is designated by ``underlining'' with dashes. +Declare a column's alignment by affixing a colon +.RB ( : ) +to the left or right end of the dashes underlining its header. +In the output, this +yields the corresponding value for the +.B align +attribute on each +.B td +cell in the column. +A colon at both ends of a column's header dashes indicates center alignment. +.TP +Relaxed Emphasis +The rules for emphasis are changed so that a single +.B _ +will not count as an emphasis character in the middle of a word. +This is useful for documenting some code where +.B _ +appears frequently, and would normally require a backslash escape. +.PD +.SH SEE ALSO +.IR markdown (1), +.IR markdown (2) +.PP +http://daringfireball.net/projects/markdown/syntax/, +``Markdown: Syntax''. +.PP +http://daringfireball.net/projects/smartypants/, +``Smarty Pants''. +.PP +http://michelf.com/projects/php-markdown/extra/#table, +``PHP Markdown Extra: Tables''. diff --git a/thirdparty/discount-2.2.6-patched/Plan9/mkfile b/thirdparty/discount-2.2.6-patched/Plan9/mkfile new file mode 100644 index 00000000..f22e41a9 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/Plan9/mkfile @@ -0,0 +1,38 @@ +BIN=/$objtype/bin +CC='cc' +CFLAGS='-D_BSD_EXTENSION -D_C99_SNPRINTF_EXTENSION' + +markdown: + ape/psh -c 'cd .. && $CC mktags.c -o mktags && ./mktags > blocktags && make' + +none:V: markdown + +test: markdown + ape/psh -c 'cd ..&& make test' + +install: markdown + cp ../markdown $BIN/markdown + +install.progs: install + cp ../makepage $BIN/makepage + cp ../mkd2html $BIN/mkd2html + +install.libs: install + cp ../mkdio.h /sys/include/ape/mkdio.h + cp ../libmarkdown.a /$objtype/lib/ape/libmarkdown.a + +install.man: install + cp markdown.1 /sys/man/1/markdown + cp markdown.2 /sys/man/2/markdown + cp markdown.6 /sys/man/6/markdown + +installall:V: install.libs install.man install.progs + +config: + ape/psh -c 'cd .. && ./configure.sh $CONFIG' + +clean: + ape/psh -c 'cd .. && make clean' + +nuke: + ape/psh -c 'cd .. && make distclean' diff --git a/thirdparty/discount-2.2.6-patched/README b/thirdparty/discount-2.2.6-patched/README new file mode 100644 index 00000000..7bfbd044 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/README @@ -0,0 +1,16 @@ +DISCOUNT is a implementation of John Gruber & Aaron Swartz's + Markdown markup language. It implements, as far as I can tell, +all of the language as described in + +and passes the Markdown test suite at + + +DISCOUNT is free software written by David Parsons +; it is released under a BSD-style license +that allows you to do as you wish with it as long as you don't +attempt to claim it as your own work. + +Most of the programs included in the DISCOUNT distribution have +manual pages describing how they work. + +The file INSTALL describes how to build and install discount diff --git a/thirdparty/discount-2.2.6-patched/VERSION b/thirdparty/discount-2.2.6-patched/VERSION new file mode 100644 index 00000000..bda8fbec --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/VERSION @@ -0,0 +1 @@ +2.2.6 diff --git a/thirdparty/discount-2.2.6-patched/amalloc.c b/thirdparty/discount-2.2.6-patched/amalloc.c new file mode 100644 index 00000000..922db773 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/amalloc.c @@ -0,0 +1,136 @@ +/* + * debugging malloc()/realloc()/calloc()/free() that attempts + * to keep track of just what's been allocated today. + */ + +#include +#include +#include "config.h" + +#define MAGIC 0x1f2e3d4c + +struct alist { int magic, size, index; int *end; struct alist *next, *last; }; + +static struct alist list = { 0, 0, 0, 0 }; + +static int mallocs=0; +static int reallocs=0; +static int frees=0; + +static int index = 0; + +static void +die(char *msg, int index) +{ + fprintf(stderr, msg, index); + abort(); +} + + +void * +acalloc(int count, int size) +{ + struct alist *ret; + + if ( size > 1 ) { + count *= size; + size = 1; + } + + if ( ret = calloc(count + sizeof(struct alist) + sizeof(int), size) ) { + ret->magic = MAGIC; + ret->size = size * count; + ret->index = index ++; + ret->end = (int*)(count + (char*) (ret + 1)); + *(ret->end) = ~MAGIC; + 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 ) { + if ( ! (p2->end && *(p2->end) == ~MAGIC) ) + die("goddam: corrupted memory block %d in free()!\n", p2->index); + 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 ) { + if ( ! (p2->end && *(p2->end) == ~MAGIC) ) + die("goddam: corrupted memory block %d in realloc()!\n", p2->index); + save.next = p2->next; + save.last = p2->last; + p2 = realloc(p2, sizeof(int) + sizeof(*p2) + size); + + if ( p2 ) { + p2->size = size; + p2->end = (int*)(size + (char*) (p2 + 1)); + *(p2->end) = ~MAGIC; + 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/thirdparty/discount-2.2.6-patched/amalloc.h b/thirdparty/discount-2.2.6-patched/amalloc.h new file mode 100644 index 00000000..43ca9858 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/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/thirdparty/discount-2.2.6-patched/basename.c b/thirdparty/discount-2.2.6-patched/basename.c new file mode 100644 index 00000000..237022a2 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/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/thirdparty/discount-2.2.6-patched/cmake/CMakeLists.txt b/thirdparty/discount-2.2.6-patched/cmake/CMakeLists.txt new file mode 100644 index 00000000..3895fdb2 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/cmake/CMakeLists.txt @@ -0,0 +1,213 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(DISCOUNT C) + +get_filename_component(_ROOT "${CMAKE_CURRENT_LIST_DIR}" PATH) + +file(READ "${_ROOT}/VERSION" ${PROJECT_NAME}_VERSION) +string(STRIP "${${PROJECT_NAME}_VERSION}" ${PROJECT_NAME}_VERSION) + +set(${PROJECT_NAME}_WITH_TABSTOPS "4" CACHE STRING + "Set tabstops to N characters (default is 4)") +set(TABSTOP "${${PROJECT_NAME}_WITH_TABSTOPS}") + +set(${PROJECT_NAME}_MAKE_INSTALL ON CACHE BOOL + "Set to OFF to disable install rules (default is ON)") + +set(${PROJECT_NAME}_INSTALL_SAMPLES OFF CACHE BOOL + "Set to ON to install sample programs (default is OFF)") + +set(${PROJECT_NAME}_ONLY_LIBRARY OFF CACHE BOOL + "Set to ON to only build markdown library (default is OFF)") + +# Check headers +include(CheckIncludeFile) +check_include_file(libgen.h HAVE_LIBGEN_H) +check_include_file(pwd.h HAVE_PWD_H) +check_include_file(alloca.h HAVE_ALLOCA_H) +check_include_file(malloc.h HAVE_MALLOC_H) +check_include_file(sys/stat.h HAVE_STAT) + +# Types detection (from configure.inc: AC_SCALAR_TYPES ()) +include(CheckTypeSize) +check_type_size("unsigned long" SIZEOF_ULONG BUILTIN_TYPES_ONLY) +check_type_size("unsigned int" SIZEOF_UINT BUILTIN_TYPES_ONLY) +check_type_size("unsigned short" SIZEOF_USHORT BUILTIN_TYPES_ONLY) + +if(SIZEOF_ULONG EQUAL 4) + set(DWORD "unsigned long") +elseif(SIZEOF_UINT EQUAL 4) + set(DWORD "unsigned int") +else() + message(FATAL_ERROR "Could not detect DWORD type") +endif() + +if(SIZEOF_UINT EQUAL 2) + set(WORD "unsigned int") +elseif(SIZEOF_USHORT EQUAL 2) + set(WORD "unsigned short") +else() + message(FATAL_ERROR "Could not detect WORD type") +endif() + +set(BYTE "unsigned char") + +# Check symbols +include(CheckSymbolExists) +foreach(_symbol + bzero + strcasecmp _stricmp + strncasecmp _strnicmp) + string(TOUPPER ${_symbol} _SYMBOL) + check_symbol_exists(${_symbol} string.h HAVE_${_SYMBOL}) +endforeach() +check_symbol_exists(random stdlib.h HAVE_RANDOM) +check_symbol_exists(srandom stdlib.h HAVE_SRANDOM) +check_symbol_exists(getpwuid pwd.h HAVE_GETPWUID) +check_symbol_exists(basename libgen.h HAVE_BASENAME) +check_symbol_exists(fchdir unistd.h HAVE_FCHDIR) +if(HAVE_STAT) + check_symbol_exists(S_ISCHR sys/stat.h HAVE_S_ISCHR) + check_symbol_exists(S_ISFIFO sys/stat.h HAVE_S_ISFIFO) + check_symbol_exists(S_ISSOCK sys/stat.h HAVE_S_ISSOCK) +endif() + +if(NOT HAVE_BZERO) + set(DEFINE_BZERO "#define bzero(p, n) memset(p, 0, n)") +endif() + +if(NOT HAVE_STRCASECMP) + if(HAVE__STRICMP) + set(DEFINE_STRCASECMP "#define strcasecmp _stricmp") + else() + set(DEFINE_STRCASECMP "#error The symbol strcasecmp is not defined.") + endif() +endif() + +if(NOT HAVE_STRNCASECMP) + if(HAVE__STRNICMP) + set(DEFINE_STRNCASECMP "#define strncasecmp _strnicmp") + else() + set(DEFINE_STRNCASECMP "#error The symbol strncasecmp is not defined.") + endif() +endif() + +if(NOT HAVE_S_ISCHR OR NOT HAVE_S_ISFIFO OR NOT HAVE_S_ISSOCK) + set(HAVE_STAT "") +endif() + +configure_file(config.h.in + "${_ROOT}/config.h" + @ONLY) + +configure_file("${_ROOT}/version.c.in" + "${_ROOT}/version.c" + @ONLY) +set_property(SOURCE "${_ROOT}/version.c" APPEND PROPERTY COMPILE_DEFINITIONS + BRANCH="" + VERSION="${${PROJECT_NAME}_VERSION}") + +configure_file("${_ROOT}/mkdio.h.in" + "${_ROOT}/mkdio.h" + @ONLY) + +include_directories("${_ROOT}") + +add_executable(mktags + "${_ROOT}/mktags.c") + +add_custom_command(OUTPUT "${_ROOT}/blocktags" + COMMAND mktags > blocktags + WORKING_DIRECTORY "${_ROOT}") + +add_library(libmarkdown + "${_ROOT}/mkdio.c" + "${_ROOT}/markdown.c" + "${_ROOT}/dumptree.c" + "${_ROOT}/generate.c" + "${_ROOT}/resource.c" + "${_ROOT}/docheader.c" + "${_ROOT}/version.c" + "${_ROOT}/toc.c" + "${_ROOT}/css.c" + "${_ROOT}/xml.c" + "${_ROOT}/Csio.c" + "${_ROOT}/xmlpage.c" + "${_ROOT}/basename.c" + "${_ROOT}/emmatch.c" + "${_ROOT}/github_flavoured.c" + "${_ROOT}/setup.c" + "${_ROOT}/blocktags" "${_ROOT}/tags.c" + "${_ROOT}/html5.c" + "${_ROOT}/flags.c") + +set_target_properties(libmarkdown PROPERTIES + OUTPUT_NAME markdown) + +if(NOT ${PROJECT_NAME}_ONLY_LIBRARY) + add_library(common OBJECT + "${_ROOT}/pgm_options.c" + "${_ROOT}/gethopt.c") + + add_executable(markdown + "${_ROOT}/main.c" + $) + + target_link_libraries(markdown PRIVATE libmarkdown) + + add_executable(mkd2html + "${_ROOT}/mkd2html.c" + $ + "${_ROOT}/notspecial.c") + + target_link_libraries(mkd2html PRIVATE libmarkdown) + + add_executable(makepage + "${_ROOT}/makepage.c" + $) + + target_link_libraries(makepage PRIVATE libmarkdown) +endif() + +if(${PROJECT_NAME}_MAKE_INSTALL) + string(TOLOWER ${PROJECT_NAME} _PACKAGE_NAME) + include(GNUInstallDirs) + if(NOT DEFINED CMAKE_INSTALL_CMAKEDIR) + set(CMAKE_INSTALL_CMAKEDIR + "${CMAKE_INSTALL_LIBDIR}/cmake/${_PACKAGE_NAME}" + CACHE STRING "CMake packages") + endif() + install(FILES "${_ROOT}/mkdio.h" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + target_include_directories(libmarkdown INTERFACE + $ + ) + set(_TARGETS libmarkdown markdown) + if(${PROJECT_NAME}_INSTALL_SAMPLES) + list(APPEND _TARGETS mkd2html makepage) + endif() + install(TARGETS ${_TARGETS} EXPORT ${_PACKAGE_NAME}-targets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}") + install(EXPORT ${_PACKAGE_NAME}-targets + NAMESPACE ${_PACKAGE_NAME}:: + DESTINATION "${CMAKE_INSTALL_CMAKEDIR}") + include(CMakePackageConfigHelpers) + write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/${_PACKAGE_NAME}-config-version.cmake" + VERSION ${${PROJECT_NAME}_VERSION} + COMPATIBILITY AnyNewerVersion + ) + configure_file("${CMAKE_CURRENT_LIST_DIR}/discount-config.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/${_PACKAGE_NAME}-config.cmake" + @ONLY) + install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/${_PACKAGE_NAME}-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${_PACKAGE_NAME}-config-version.cmake" + DESTINATION "${CMAKE_INSTALL_CMAKEDIR}") + unset(_TARGETS) + unset(_PACKAGE_NAME) +endif() + +unset(_ROOT) diff --git a/thirdparty/discount-2.2.6-patched/cmake/config.h.in b/thirdparty/discount-2.2.6-patched/cmake/config.h.in new file mode 100644 index 00000000..e6309347 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/cmake/config.h.in @@ -0,0 +1,79 @@ +/* + * Pre-digested configuration header. + * Generated from cmake/config.h.in. + * Tested with MSVC, MinGW on Windows and with GCC on Linux. + * File prototype: msvc/config.h.vc. + */ + +#ifndef _CONFIG_D +#define _CONFIG_D 1 + +/* + * `discount` feature macros - we want them all! + */ +#ifndef WITH_ID_ANCHOR +#define WITH_ID_ANCHOR 1 +#endif +#ifndef WITH_FENCED_CODE +#define WITH_FENCED_CODE 1 +#endif +#ifndef WITH_GITHUB_TAGS +#define WITH_GITHUB_TAGS 1 +#endif +#ifndef USE_DISCOUNT_DL +#define USE_DISCOUNT_DL 1 +#endif +#ifndef USE_EXTRA_DL +#define USE_EXTRA_DL 1 +#endif + +#ifdef _MSC_VER + +/* + * The Visual C++ "C" compiler has a `__inline` keyword implemented + * in Visual Studio 2008 and later, see + * + */ +#if _MSC_VER >= 1500 /* VC 9.0, MSC_VER 15, Visual Studio 2008 */ +#define inline __inline +#else +#define inline +#endif /* _MSC_VER >= 1500 */ + +#endif /* _MSC_VER */ + +@DEFINE_BZERO@ +@DEFINE_STRCASECMP@ +@DEFINE_STRNCASECMP@ + +/* + * Beware of conflicts with , which typedef's these names. + */ +#ifndef WINVER +#define DWORD @DWORD@ +#define WORD @WORD@ +#define BYTE @BYTE@ +#endif + +#cmakedefine HAVE_PWD_H 1 +#cmakedefine HAVE_GETPWUID 1 + +#cmakedefine HAVE_LIBGEN_H 1 +#cmakedefine HAVE_BASENAME 1 + +#cmakedefine HAVE_RANDOM 1 +#cmakedefine HAVE_SRANDOM 1 + +#define INITRNG(x) srand((unsigned int)x) +#define COINTOSS() (rand()&1) + +#cmakedefine HAVE_FCHDIR 1 +#cmakedefine HAVE_ALLOCA_H 1 +#cmakedefine HAVE_MALLOC_H 1 +#cmakedefine HAVE_STAT 1 + +#define TABSTOP @TABSTOP@ + +#define DESTRUCTOR + +#endif /* _CONFIG_D */ diff --git a/thirdparty/discount-2.2.6-patched/cmake/discount-config.cmake.in b/thirdparty/discount-2.2.6-patched/cmake/discount-config.cmake.in new file mode 100644 index 00000000..3ead2cdc --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/cmake/discount-config.cmake.in @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/@_PACKAGE_NAME@-targets.cmake") diff --git a/thirdparty/discount-2.2.6-patched/configure.inc b/thirdparty/discount-2.2.6-patched/configure.inc new file mode 100755 index 00000000..fd0c9ba7 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/configure.inc @@ -0,0 +1,2014 @@ +# Copyright (c) 1999-2017 David Parsons. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 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. +# 3. My name may not be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY DAVID PARSONS ``AS IS'' AND ANY +# EXPRESS 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 +# 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. +# + + +# +# this preamble code is executed when this file is sourced and it picks +# interesting things off the command line. +# +ac_default_path="/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin" + +ac_standard="--src=DIR where the source lives (.) +--prefix=DIR where to install the final product (/usr/local) +--execdir=DIR where to put executables (prefix/bin) +--sbindir=DIR where to put static executables (prefix/sbin) +--confdir=DIR where to put configuration information (/etc) +--libdir=DIR where to put libraries (prefix/lib) +--libexecdir=DIR where to put private executables +--mandir=DIR where to put manpages" + + +# remove files created by configure on abend +# +AC_EXIT() { + rm -f $__config_files + exit ${1:-1} +} + +__fail=AC_EXIT + + +if dirname B/A 2>/dev/null >/dev/null; then +__ac_dirname() { + dirname "$1" +} +else +__ac_dirname() { + echo "$1" | sed -e 's:/[^/]*$::' +} +fi + +__remove() { + if [ \( -x "$1" \) -a "$__MACOS_DSYM" ]; then + rm -rf "$1".dSYM + fi + rm -f "$@" +} + +ac_progname=$0 +ac_configure_command= +Q=\' +for x in "$@"; do + ac_configure_command="$ac_configure_command $Q$x$Q" +done +# ac_configure_command="$*" + +__d=`__ac_dirname "$ac_progname"` +if [ "$__d" = "$ac_progname" ]; then + AC_SRCDIR=`pwd` +else + AC_SRCDIR=`cd $__d;pwd` +fi + +__ac_dir() { + if test -d "$1"; then + (cd "$1";pwd) + else + echo "$1"; + fi +} + +# +# echo w/o newline +# +echononl() +{ + ${ac_echo:-echo} "${@}$ac_echo_nonl" +} + +# +# log something to the terminal and to a logfile. +# +LOG () { + echo "$@" + echo "$@" 1>&5 +} + +# +# log something to the terminal without a newline, and to a logfile with +# a newline +# +LOGN () { + echononl "$@" 1>&5 + echo "$@" +} + +# +# log something to the terminal +# +TLOG () { + echo "$@" 1>&5 +} + +# +# log something to the terminal, no newline +# +TLOGN () { + echononl "$@" 1>&5 +} + + +# +# AC_CONTINUE tells configure not to bomb if something fails, but to +# continue blithely along +# +AC_CONTINUE () { + __fail="return" +} + + +# +# generate a .o file from sources +# +__MAKEDOTO() { + AC_PROG_CC + + if $AC_CC -c -o ngc$$.o "$@" $LIBS 2>ngc$$.err; then + __remove ngc$$.o ngc$$.err + TLOG " (found)" + return 0 + fi + __remove ngc$$.o + TLOG " (not found)" + echo "test failed: command was $AC_CC -c -o ngc$$.o" "$@" $LIBS + echo "output:" + cat ngc$$.err + __remove ngc$$.err + echo "offending sources:" + for x in "$@"; do + echo "$x:" + cat $x + done + return 1 +} + + +# +# Emulate gnu autoconf's AC_CHECK_HEADERS() function +# +AC_CHECK_HEADERS () { + + AC_PROG_CPP + + for __hdr in "$@"; do + ( echo "/* AC_CHECK_HEADERS */" + echo "#include <${__hdr}>" ) > ngc$$.c + + LOGN "looking for header $__hdr" + + if $AC_CPP_FILTER ngc$$.c >/dev/null; then + AC_DEFINE 'HAVE_'`echo $__hdr | $AC_UPPERCASE | tr './' '_'` 1 + rc=0 + LOG " (found)" + else + rc=1 + LOG " (not found)" + fi + __remove ngc$$.c + done + # return code is only meaningful if one header is checked + return $rc +} + + +# +# emulate GNU autoconf's AC_CHECK_FUNCS function +# +AC_CHECK_FUNCS () { + AC_PROG_CC + + B=`echo "$1" | sed -e 's/(.*)//'` + + case "$B" in + "$1") F="$1()"; need_proto=1 ;; + *) F="$1" ; unset need_proto ;; + esac + + shift + __remove ngc$$.c + + while [ "$1" ]; do + echo "#include <$1>" >> ngc$$.c + shift + done + + if [ "$need_proto" ]; then + echo "void $F;" >> ngc$$.c + fi + + cat >> ngc$$.c << EOF +int main() +{ + + $F; +} +EOF + + LOGN "looking for the $B function" + + if $AC_CC $AC_CFLAGS $AC_LDFLAGS -o ngc$$ ngc$$.c $LIBS; then + AC_DEFINE `echo ${2:-HAVE_$B} | $AC_UPPERCASE` 1 + TLOG " (found)" + rc=0 + else + echo "offending command was:" + cat ngc$$.c + echo "$AC_CC $AC_CFLAGS $AC_LDFLAGS -o ngc$$ ngc$$.c $LIBS" + TLOG " (not found)" + rc=1 + fi + __remove ngc$$ ngc$$.c + return $rc +} + + +# +# check to see if some structure exists +# +# usage: AC_CHECK_STRUCT structure {include ...} +# +AC_CHECK_STRUCT () { + struct=$1 + shift + + __remove ngc$$.c + + for include in $*; do + echo "#include <$include>" >> ngc$$.c + done + + cat >> ngc$$.c << EOF +int main() +{ + struct $struct foo; +} +EOF + + LOGN "looking for struct $struct" + + if __MAKEDOTO ngc$$.c; then + AC_DEFINE HAVE_STRUCT_`echo ${struct} | $AC_UPPERCASE` + rc=0 + else + rc=1 + fi + __remove ngc$$.c + return $rc +} + + +# +# check to see if some type exists +# +# usage: AC_CHECK_TYPE type {include ...} +# +AC_CHECK_TYPE () { + type=$1 + shift + + __remove ngc$$.c + + for include in $*; do + echo "#include <$include>" >> ngc$$.c + done + + cat >> ngc$$.c << EOF +int main() +{ + $type foo; +} +EOF + + LOGN "looking for $type type" + + if __MAKEDOTO ngc$$.c; then + AC_DEFINE HAVE_`echo ${type} | $AC_UPPERCASE` + rc=0 + else + rc=1 + fi + __remove ngc$$.c + return $rc +} + + +# +# check to see if some structure contains a field +# +# usage: AC_CHECK_FIELD structure field {include ...} +# +AC_CHECK_FIELD () { + + struct=$1 + field=$2 + shift 2 + + __remove ngc$$.c + + for include in $*;do + echo "#include <$include>" >> ngc$$.c + done + + cat >> ngc$$.c << EOF +int main() +{ + struct $struct foo; + + foo.$field; +} +EOF + + LOGN "checking that struct $struct has a $field field" + + if __MAKEDOTO ngc$$.c; then + # HAVE_STRUCT_ is for Gnu configure compatability + AC_DEFINE HAVE_STRUCT_`echo ${struct}_$field | $AC_UPPERCASE` + rc=0 + else + rc=1 + fi + __remove ngc$$.c + return $rc +} + + +# +# check that the C compiler works +# +AC_PROG_CC () { + test "$AC_CC" && return 0 + + cat > ngc$$.c << \EOF +extern void say(void*); +int main() +{ + say("hello, sailor"); +} +EOF + cat > ngf$$.c << \EOF +#include +void say(char* message) +{ + puts(message); +} +EOF + + TLOGN "checking the C compiler" + + unset AC_CFLAGS AC_LDFLAGS __MACOS_DSYM + + if [ "$CC" ] ; then + AC_CC="$CC" + elif [ "$WITH_PATH" ]; then + AC_CC=`acLookFor cc` + elif [ "`acLookFor cc`" ]; then + # don't specify the full path if the user is looking in their $PATH + # for a C compiler. + AC_CC=cc + fi + + # finally check for POSIX c89 + test "$AC_CC" || AC_CC=`acLookFor c89` + + if [ ! "$AC_CC" ]; then + TLOG " (no C compiler found)" + $__fail 1 + fi + echo "checking out the C compiler" + + $AC_CC -o ngc$$ ngc$$.c ngf$$.c + status=$? + echo "compile status = $status" + + TLOGN " ($AC_CC)" + + if [ $status -eq 0 ]; then + if $AC_CC -x c /dev/null -dM -E 2>&1 | grep '__clang__' >/dev/null; then + TLOG " yuck, you're using clang" + IS_CLANG=T + IS_BROKEN_CC=T + elif $AC_CC -v 2>&1 | grep 'gcc version' >/dev/null; then + TLOG " oh ick, it looks like gcc" + IS_GCC=T + IS_BROKEN_CC=T + else + TLOG " ok" + fi + + # check that the CFLAGS and LDFLAGS aren't bogus + + unset AC_CFLAGS AC_LDFLAGS + + if [ "$CFLAGS" ]; then + test "$CFLAGS" && echo "validating CFLAGS=${CFLAGS}" + if $AC_CC $CFLAGS -c -o ngc$$.o ngc$$.c ; then + AC_CFLAGS=${CFLAGS:-"-g"} + test "$CFLAGS" && TLOG "CFLAGS=\"${CFLAGS}\" are okay" + elif [ "$CFLAGS" ]; then + TLOG "ignoring bogus CFLAGS=\"${CFLAGS}\"" + fi + else + AC_CFLAGS=-g + fi + if [ "$LDFLAGS" ]; then + test "$LDFLAGS" && echo "validating LDFLAGS=${LDFLAGS}" + if $AC_CC $CFLAGS $LDFLAGS -o ngc$$ ngc$$.c ngf$$.c; then + AC_LDFLAGS=${LDFLAGS:-"-g"} + test "$LDFLAGS" && TLOG "LDFLAGS=\"${LDFLAGS}\" are okay" + elif [ "$LDFLAGS" ]; then + TLOG "ignoring bogus LDFLAGS=\"${LDFLAGS}\"" + fi + else + AC_LDFLAGS=${CFLAGS:-"-g"} + fi + + # macos-specific(?) test for .dSYM resource directories + $AC_CC $AC_CFLAGS $AC_LDFLAGS -o ngc$$ ngc$$.c ngf$$.c + ls -dl ngc$$* + test -d ngc$$.dSYM && __MACOS_DSYM=1 + + else + AC_FAIL " does not compile code properly" + fi + + __remove ngc$$ ngc$$.c ngc$$.o ngf$$.o ngf$$.c + + return $status +} + + +# +# acLookFor actually looks for a program, without setting anything. +# +acLookFor () { + path=${AC_PATH:-$ac_default_path} + case "X$1" in + X-[rx]) __mode=$1 + shift + ;; + *) __mode=-x + ;; + esac + oldifs="$IFS" + for program in $*; do + case "$program" in + /*) if [ $__mode $program -a -f $program ]; then + echo $program + break 2 + fi ;; + *) + IFS=":" + for x in $path; do + if [ $__mode $x/$program -a -f $x/$program ]; then + echo $x/$program + break 3 + fi + done ;; + esac + done + IFS="$oldifs" + unset __mode +} + + +# +# check that a program exists and set its path +# +MF_PATH_INCLUDE () { + SYM=$1; shift + + case X$1 in + X-[rx]) __mode=$1 + shift + ;; + *) unset __mode + ;; + esac + + TLOGN "looking for $1" + + DEST=`acLookFor $__mode $*` + + __sym=`echo "$SYM" | $AC_UPPERCASE` + if [ "$DEST" ]; then + TLOG " ($DEST)" + echo "$1 is $DEST" + AC_MAK $SYM + AC_DEFINE PATH_$__sym \""$DEST"\" + AC_SUB $__sym "$DEST" + eval CF_$SYM=$DEST + return 0 + else + #AC_SUB $__sym '' + echo "$1 is not found" + TLOG " (not found)" + return 1 + fi +} + +# +# AC_INIT starts the ball rolling +# +# After AC_INIT, fd's 1 and 2 point to config.log +# and fd 5 points to what used to be fd 1 +# +AC_INIT () { + __config_files="config.cmd config.sub config.h config.mak" + rm -f $__config_files + __cwd=`pwd` + exec 5>&1 1>"$__cwd"/config.log 2>&1 + AC_CONFIGURE_FOR=__AC_`echo $1 | sed -e 's/\..$//' | $AC_UPPERCASE | tr ' ' '_'`_D + + # check to see whether to use echo -n or echo ...\c + # + echo -n hello > $$ + echo world >> $$ + if grep "helloworld" $$ >/dev/null; then + ac_echo="echo -n" + echo "[echo -n] works" + else + ac_echo="echo" + echo 'hello\c' > $$ + echo 'world' >> $$ + if grep "helloworld" $$ >/dev/null; then + ac_echo_nonl='\c' + echo "[echo ...\\c] works" + fi + fi + rm -f $$ + + LOG "Configuring for [$1]" + _MK_LIBRARIAN=Y + + cat > "$__cwd"/config.h << EOF +/* + * configuration for $1${2:+" ($2)"}, generated `date` + * by ${LOGNAME:-`whoami`}@`hostname` + */ +#ifndef $AC_CONFIGURE_FOR +#define $AC_CONFIGURE_FOR 1 + + +EOF + + unset __share + if [ -d $AC_PREFIX/share/man ]; then + for t in 1 2 3 4 5 6 7 8 9; do + if [ -d $AC_PREFIX/share/man/man$t ]; then + __share=/share + elif [ -d $AC_PREFIX/share/man/cat$t ]; then + __share=/share + fi + done + else + __share= + fi + + if [ -d $AC_PREFIX/libexec ]; then + __libexec=libexec + else + __libexec=lib + fi + + + AC_PREFIX=${AC_PREFIX:-/usr/local} + AC_EXECDIR=${AC_EXECDIR:-$AC_PREFIX/bin} + AC_SBINDIR=${AC_SBINDIR:-$AC_PREFIX/sbin} + AC_LIBDIR=${AC_LIBDIR:-$AC_PREFIX/lib} + AC_MANDIR=${AC_MANDIR:-$AC_PREFIX$__share/man} + AC_LIBEXEC=${AC_LIBEXEC:-$AC_PREFIX/$__libexec} + AC_CONFDIR=${AC_CONFDIR:-/etc} + + AC_PATH=${WITH_PATH:-$PATH} + AC_PROG_CPP + AC_PROG_INSTALL + + ac_os=`uname -s` + _os=`echo $ac_os | $AC_UPPERCASE | sed -e 's/[^A-Z0-9_].*$//'` + AC_DEFINE OS_$_os 1 + eval OS_${_os}=1 + unset _os +} + + +# +# AC_LIBRARY checks to see if a given library exists and contains the +# given function. +# usage: AC_LIBRARY function library [alternate ...] +# +AC_LIBRARY() { + local SRC=$1 + shift + + # first see if the function can be found in any of the + # current libraries + LOGN "Looking for the ${SRC} function" + if AC_QUIET AC_CHECK_FUNCS $SRC; then + AC_DEFINE HAVE_LIB`echo $1 | sed -e 's/-l//' | $AC_UPPERCASE` + LOG "(found)" + return 0 + fi + + # then search through the supplied list of libraries + local __libs="$LIBS" + for x in "$@"; do + LIBS="$__libs $x" + if AC_QUIET AC_CHECK_FUNCS $SRC; then + AC_DEFINE HAVE_LIB`echo $1 | sed -e 's/-l//' | $AC_UPPERCASE` + LOG " (in $x)" + return 0 + fi + done + LOG " (not found)" + LIBS="$__libs" # reset LIBS if we couldn't find anything + return 1 +} + + +# +# AC_PROG_LEX checks to see if LEX exists, and if it's lex or flex. +# +AC_PROG_LEX() { + TLOGN "looking for lex " + + DEST=`acLookFor lex` + if [ "$DEST" ]; then + AC_MAK LEX + AC_DEFINE PATH_LEX \"$DEST\" + AC_SUB 'LEX' "$DEST" + echo "lex is $DEST" + else + DEST=`acLookFor flex` + if [ "$DEST" ]; then + AC_MAK FLEX + AC_DEFINE 'LEX' \"$DEST\" + AC_SUB 'LEX', "$DEST" + echo "lex is $DEST" + else + AC_SUB LEX '' + echo "neither lex or flex found" + TLOG " (not found)" + return 1 + fi + fi + TLOG "($DEST)" + + if AC_LIBRARY yywrap -ll -lfl; then + return 0 + else + TLOG "(no lex library found)" + return 1 + fi +} + + +# +# AC_PROG_YACC checks to see if YACC exists, and if it's bison or +# not. +# +AC_PROG_YACC () { + + TLOGN "looking for yacc " + + DEST=`acLookFor yacc` + if [ "$DEST" ]; then + AC_MAK YACC + AC_DEFINE PATH_YACC \"$DEST\" + AC_SUB 'YACC' "$DEST" + TLOG "($DEST)" + echo "yacc is $DEST" + else + DEST=`acLookFor bison` + if [ "$DEST" ]; then + AC_MAK BISON + AC_DEFINE 'YACC' \"$DEST\" + AC_SUB 'YACC' "$DEST -y" + echo "yacc is $DEST -y" + TLOG "($DEST -y)" + else + AC_SUB 'YACC' '' + echo "neither yacc or bison found" + TLOG " (not found)" + return 1 + fi + fi + return 0 +} + + +# +# AC_PROG looks for a program +# +AC_PROG () { + PN=`basename $1 | $AC_UPPERCASE | tr -dc $AC_UPPER_PAT` + + if set | grep -v PROG_$PN >/dev/null; then + TLOGN "looking for $1" + + __pgm=`eval echo \\$$PN` + if [ "$__pgm" ]; then + TLOGN " (defined as $__pgm)" + DEST=`acLookFor $__pgm` + else + DEST=`acLookFor $1` + fi + + if [ "$DEST" ]; then + eval PROG_$PN="$DEST" + AC_SUB $PN $DEST + TLOG " ($DEST)" + return 0 + fi + AC_SUB $PN true + TLOG " (not found)" + return 1 + fi +} + + +# +# AC_PROG_LN_S checks to see if ln exists, and, if so, if ln -s works +# +AC_PROG_LN_S () { + test "$PROG_FIND" || AC_PROG_FIND + + test "$PROG_LN_S" && return 0 + + TLOGN "looking for \"ln -s\"" + DEST=`acLookFor ln` + + if [ "$DEST" ]; then + rm -f /tmp/b$$ + $DEST -s /tmp/a$$ /tmp/b$$ + if [ "`$PROG_FIND /tmp/b$$ -type l -print`" ]; then + TLOG " ($DEST)" + echo "$DEST exists, and ln -s works" + PROG_LN_S="$DEST -s" + AC_SUB 'LN_S' "$DEST -s" + rm -f /tmp/b$$ + else + AC_SUB 'LN_S' '' + TLOG " ($DEST exists, but -s does not seem to work)" + echo "$DEST exists, but ln -s doesn't seem to work" + rm -f /tmp/b$$ + return 1 + fi + else + AC_SUB 'LN_S' '' + echo "ln not found" + TLOG " (not found)" + return 1 + fi +} + + +# +# AC_PROG_FIND looks for the find program and sets the FIND environment +# variable +# +AC_PROG_FIND () { + if test -z "$PROG_FIND"; then + MF_PATH_INCLUDE FIND find + rc=$? + PROG_FIND=$CF_FIND + return $rc + fi + return 0 +} + + +# +# AC_PROG_AWK looks for the awk program and sets the AWK environment +# variable +# +AC_PROG_AWK () { + if test -z "$AC_AWK_PROG"; then + MF_PATH_INCLUDE AWK awk + rc=$? + AC_AWK_PROG=$DEST + return $rc + fi + return 0 +} + + +# +# AC_PROG_SED looks for the sed program and sets the SED environment +# variable +# +AC_PROG_SED () { + if test -z "$AC_SED_PROG"; then + MF_PATH_INCLUDE SED sed + rc=$? + AC_SED_PROG=$DEST + return $rc + fi + return 0 +} + + +# +# AC_HEADER_SYS_WAIT looks for sys/wait.h +# +AC_HEADER_SYS_WAIT () { + AC_CHECK_HEADERS sys/wait.h || return 1 +} + +# +# AC_TYPE_PID_T checks to see if the pid_t type exists +# +AC_TYPE_PID_T () { + + AC_CHECK_TYPE pid_t sys/types.h + return $? +} + + +# +# check for the existence of __attribute__((__noreturn__)) +# +AC_CHECK_NORETURN() { + AC_PROG_CC + AC_CHECK_ATTRIBUTE noreturn +} + +AC_CHECK_ATTRIBUTE() { + local __what=`echo $1 | tr 'a-z' 'A-Z'` + + echo "extern int thing __attribute__((__"$1"__));" > ngc$$.c + + TLOGN "Checking __attribute__((__${1}__)) " + if $AC_CC -c ngc$$.c; then + TLOG "(yes)" + AC_DEFINE $__what ' __attribute__((__'$1'__))' + else + TLOG "(no)" + AC_DEFINE $__what '/**/' + fi + rm -f ngc$$.o ngc$$.c +} + + +# +# AC_C_CONST checks to see if the compiler supports the const keyword +# +AC_C_CONST () { + cat > ngc$$.c << EOF +const char me=1; +EOF + LOGN "checking for \"const\" keyword" + + if __MAKEDOTO ngc$$.c; then + rc=0 + else + AC_DEFINE 'const' '/**/' + rc=1 + fi + __remove ngc$$.c + return $rc +} + + +# +# AC_C_VOLATILE checks to see if the compiler supports the volatile keyword +# +AC_C_VOLATILE () { + echo 'f() { volatile char me=1; }' > ngc$$.c + LOGN "checking for \"volatile\" keyword" + + if __MAKEDOTO ngc$$.c; then + rc=0 + else + AC_DEFINE 'volatile' '/**/' + rc=1 + fi + __remove ngc$$.c + return $rc +} + + +# +# AC_C_INLINE checks to see if compiler supports the inline keyword +# +AC_C_INLINE() { + echo 'inline int foo() { return 1; }' > ngc$$.c + LOGN 'Checking for "inline" keyword' + if __MAKEDOTO ngc$$.c; then + rc=0 + else + AC_DEFINE inline '/**/' + rc=1 + fi + __remove ngc$$.c + return $rc +} + + +# +# AC_WHATIS tries to print out the value of a macro +# +AC_WHATIS() { + MODE=$1 # what it should be (string,int,char) + shift + MACRO=$1 # the macro name + shift + + case "$MODE" in + string) + __fmt='%s' ;; + int) + __fmt='%d' ;; + char) + __fmt='%c' ;; + *) LOG "AC_WHATIS $MODE $MACRO -- mode isn't string, int, or char" + return 1 ;; + esac + + ( echo '#include ' + + for x in "$@"; do + echo "#include <${x}>" + done + + echo "main() { printf(\"${MACRO}=\\\"${__fmt}\\\"\\n\", ${MACRO}); }" ) > _ngc$$.c + + if $AC_CC $AC_CFLAGS -o _ngc$$ _ngc$$.c; then + ./_ngc$$ + rc=0 + else + rc=1 + fi + rm -f _ngc$$ _ngc$$.c + return $rc +} + + +# +# AC_SCALAR_TYPES checks to see if the compiler can generate 2 and 4 byte ints. +# +AC_SCALAR_TYPES () { + + rc=1 + LOGN "defining WORD & DWORD scalar types" + +# if AC_QUIET AC_CHECK_HEADERS WinDef.h; then +# # windows machine; BYTE, WORD, DWORD already +# # defined +# echo "#include " >> "$__cwd"/config.h +# TLOG " (defined in WinDef.h)" +# return 0 +# fi + + # try first to define them with the (allegedly) standard + # unsigned scalar types + # + unset __i; + if AC_QUIET AC_CHECK_HEADERS inttypes.h; then + __i=inttypes.h + elif AC_QUIET AC_CHECK_HEADERS stdint.h; then + __i=stdint.h + fi + if AC_QUIET AC_CHECK_TYPE uint32_t $__i && \ + AC_QUIET AC_CHECK_TYPE uint16_t $__i && \ + AC_QUIET AC_CHECK_TYPE uint8_t $__i; then + + while [ $# -gt 0 ]; do + case "$1" in + sub) ( if [ -z "$__i" ] ; then + echo "s:@SCALAR_HEADER_INCLUDE@::g" + else + echo "s:@SCALAR_HEADER_INCLUDE@:#include <$__i>:g" + fi + echo "s:@DWORD@:uint32_t:g" + echo "s:@WORD@:uint16_t:g" + echo "s:@BYTE@:uint8_t:g" ) >> "$__cwd"/config.sub + ;; + *) ( echo "#define DWORD uint32_t" + echo "#define WORD uint16_t" + echo "#define BYTE uint8_t" ) >> "$__cwd"/config.h + ;; + esac + shift + done + TLOG " (using standard types ${__i:+in <$__i>})" + return 0 + fi + + # and if that fails do a brute-force program that does sizeof()ication + # to figure things out + # + cat > ngc$$.c << EOF +#include +#include + +int pound_define = 1; + +void +say(char *w, char *v) +{ + printf(pound_define ? "#define %s %s\n" + : "s:@%s@:%s:g\n", w, v); +} + +int +main(argc, argv) +char **argv; +{ + unsigned long v_long; + unsigned int v_int; + unsigned short v_short; + + if ( argc > 1 && strcmp(argv[1], "sub") == 0 ) + pound_define = 0; + + if (sizeof v_long == 4) + say("DWORD", "unsigned long"); + else if (sizeof v_int == 4) + say("DWORD", "unsigned int"); + else + return 1; + + if (sizeof v_int == 2) + say("WORD", "unsigned int"); + else if (sizeof v_short == 2) + say("WORD", "unsigned short"); + else + return 2; + + say("BYTE", "unsigned char"); + fprintf(stderr, "OK!"); + return 0; +} +EOF + + if $AC_CC ngc$$.c -o ngc$$; then + if [ $# -gt 0 ]; then + while [ "$1" ]; do + case "$1" in + sub)if ./ngc$$ sub >> "$__cwd"/config.sub; then + echo "s:@SCALAR_HEADER_INCLUDE@::g" >> "$__cwd"/config.sub + rc=0 + fi;; + *) if ./ngc$$ >> "$__cwd"/config.h; then + rc=0 + fi ;; + esac + shift + done + elif ./ngc$$ >> "$__cwd"/config.h; then + rc=0 + fi + if [ "$rc" != 0 ]; then + if ./ngc$$ >> "$__cwd"/config.h; then + rc=0 + fi + fi + fi + __remove ngc$$ ngc$$.c + case "$rc" in + 0) TLOG "" ;; + *) AC_FAIL " ** FAILED **" ;; + esac + return $rc +} + + +# +# AC_OUTPUT generates makefiles from makefile.in's +# +AC_OUTPUT () { + + cd "$__cwd" + AC_SUB 'LIBS' "$LIBS" + + if test "$__MACOS_DSYM"; then + # deal with extra OSX droppings, if they exist + AC_SUB 'DISTCLEAN' 'rm -fr' + AC_SUB 'GENERATED_FILES' "*.dSYM $*" + else + AC_SUB 'DISTCLEAN' 'rm -f' + AC_SUB 'GENERATED_FILES' "$*" + fi + + AC_SUB 'CC' "$AC_CC" + AC_SUB 'CFLAGS' "$AC_CFLAGS" + AC_SUB 'LDFLAGS' "$AC_LDFLAGS" + AC_SUB 'CPPFLAGS' "$CPPFLAGS" + AC_SUB 'srcdir' "$AC_SRCDIR" + AC_SUB 'prefix' "$AC_PREFIX" + AC_SUB 'exedir' "$AC_EXECDIR" + AC_SUB 'bindir' "$AC_EXECDIR" + AC_SUB 'sbindir' "$AC_SBINDIR" + AC_SUB 'libdir' "$AC_LIBDIR" + AC_SUB 'libexec' "$AC_LIBEXEC" + AC_SUB 'confdir' "$AC_CONFDIR" + AC_SUB 'mandir' "$AC_MANDIR" + + if [ "$_MK_LIBRARIAN" ] && echo "$__config_files" | grep -v librarian.sh >/dev/null; then + # write a librarian that works with static libraries + if AC_PROG_LN_S ; then + __dolink=$PROG_LN_S + elif AC_PROG ln; then + __dolink=$PROG_LN + elif AC_PROG cp; then + __dolink=$PROG_CP + else + __dolink=: + fi + AC_PROG ar + AC_PROG ranlib + AC_SUB LD_LIBRARY_PATH HERE + __config_files="$__config_files librarian.sh" + cat > librarian.sh << EOF +#! /bin/sh +# +# Build static libraries, hiding (some) ickiness from the makefile + +ACTION=\$1; shift +LIBRARY=\$1; shift +VERSION=\$1; shift + +case "\$ACTION" in +make) # first strip out any libraries that might + # be passed in on the object line + objs= + for x in "\$@"; do + case "\$x" in + -*) ;; + *) objs="\$objs \$x" ;; + esac + done + ${PROG_AR} crv \$LIBRARY.a \$objs + ${PROG_RANLIB} \$LIBRARY.a + rm -f \$LIBRARY + ${__dolink} \$LIBRARY.a \$LIBRARY + ;; +files) echo "\${LIBRARY}.a" + ;; +install)$PROG_INSTALL -m 644 \${LIBRARY}.a \$1 + ;; +esac +EOF + chmod +x librarian.sh + fi + + AC_SUB 'CONFIGURE_FILES' "$__config_files config.log" + + if [ -r config.sub ]; then + test "$AC_SED_PROG" || AC_PROG_SED + test "$AC_SED_PROG" || return 1 + + echo >> config.h + echo "#endif/* ${AC_CONFIGURE_FOR} */" >> config.h + + rm -f config.cmd + Q=\' + cat - > config.cmd << EOF +#! /bin/sh +${CC:+CC=${Q}${CC}${Q}} ${CFLAGS:+CFLAGS=${Q}${CFLAGS}${Q}} ${LDFLAGS:+LDFLAGS=${Q}${LDFLAGS}${Q}} $ac_progname $ac_configure_command +EOF + chmod +x config.cmd + + __d=$AC_SRCDIR + for makefile in $*;do + if test -r "$__d/${makefile}.in"; then + LOG "generating $makefile" + ./config.md `__ac_dirname ./$makefile` 2>/dev/null + $AC_SED_PROG -f config.sub < "$__d/${makefile}.in" > $makefile + __config_files="$__config_files $makefile" + else + LOG "WARNING: ${makefile}.in does not exist!" + fi + done + unset __d + + else + echo + fi +} + +# +# AC_CHECK_FLOCK checks to see if flock() exists and if the LOCK_NB argument +# works properly. +# +AC_CHECK_FLOCK() { + + AC_CHECK_HEADERS sys/types.h sys/file.h fcntl.h + + cat << EOF > ngc$$.c +#include +#include +#include +#include + +int main() +{ + int x = open("ngc$$.c", O_RDWR, 0666); + int y = open("ngc$$.c", O_RDWR, 0666); + + alarm(1); + if (flock(x, LOCK_EX) != 0) + exit(1); + if (flock(y, LOCK_EX|LOCK_NB) == 0) + exit(1); + exit(0); +} +EOF + + LOGN "checking flock() sanity" + HAS_FLOCK=0 + if $AC_CC -o ngc$$ ngc$$.c ; then + if ./ngc$$ ; then + LOG " (good)" + HAS_FLOCK=1 + AC_DEFINE HAS_FLOCK + else + LOG " (bad)" + fi + else + LOG " (not found)" + fi + + __remove ngc$$ ngc$$.c + + case "$HAS_FLOCK" in + 0) return 1 ;; + *) return 0 ;; + esac +} + + +# +# AC_CHECK_RESOLVER finds out whether the berkeley resolver is +# present on this system. +# +AC_CHECK_RESOLVER () { + AC_PROG_CC + + TLOGN "looking for the Berkeley resolver library" + + __ACR_rc=0 + + cat > ngc$$.c << EOF +#include +#include +#include +#include + +int main() +{ + char bfr[256]; + + res_init(); + res_query("hello", C_IN, T_A, bfr, sizeof bfr); +} +EOF + + if $AC_CC -o ngc$$ ngc$$.c; then + TLOG " (found)" + elif $AC_CC -o ngc$$ ngc$$.c -lresolv; then + TLOG " (yes, with -lresolv)" + LIBS="$LIBS -lresolv" + elif $AC_CC -DBIND_8_COMPAT -o ngc$$ ngc$$.c; then + TLOG " (yes, with BIND_8_COMPAT)" + AC_DEFINE BIND_8_COMPAT 1 + elif $AC_CC -DBIND_8_COMPAT -o ngc$$ ngc$$.c -lresolv; then + TLOG " (yes, with BIND_8_COMPAT & -lresolv)" + LIBS="$LIBS -lresolv" + AC_DEFINE BIND_8_COMPAT 1 + else + TLOG " (not found)" + __ACR_rc=1 + fi + __remove ngc$$ ngc$$.c + return $__ACR_rc +} + + +# +# AC_CHECK_ALLOCA looks for alloca +# +AC_CHECK_ALLOCA () { + + AC_PROG_CC + AC_CHECK_HEADERS stdlib.h + + cat - > ngc$$.c << EOF +#if T +# include +#else +# include +#endif +int main() +{ + alloca(10); +} +EOF + + LOGN "looking for the alloca function" + if $AC_CC -DT ngc$$.c -o ngc$$; then + AC_DEFINE 'HAVE_ALLOCA_H' 1 + status=0 + TLOG " (found in alloca.h)" + elif $AC_CC ngc$$.c -o ngc$$; then + TLOG " (found)" + status=0 + else + TLOG " (not found)" + status=1 + fi + __remove ngc$$ ngc$$.c + return $status + +} + + +# +# AC_CHECK_BASENAME looks for a copy of basename that does NOT use +# a local static buffer to hold results in. +# +AC_CHECK_BASENAME() { + TLOGN "looking for a reentrant basename " + + cat > ngc$$.c << EOF +#include + +extern char *basename(char*); + +int main() +{ + char *a = basename("/a/test"); + char *b = basename("/a/nother"); + + return (strcmp(a,b) != 0) ? 0 : 1; + +} +EOF + + if $AC_CC -o ngc$$ ngc$$.c $LIBS; then + if ./ngc$$; then + TLOG "(found)" + AC_DEFINE 'HAVE_BASENAME' 1 + AC_CHECK_HEADERS libgen.h + else + TLOG "(broken)" + fi + else + TLOG "(not found)" + fi + __remove ngc$$ ngc$$.c +} + +# +# AC_COMPILER_PIC checks for the compiler option to produce position independent +# code. At the moment we assume gcc semantics. +# +AC_COMPILER_PIC () { + AC_PROG_CC + + LOGN "checking for C compiler option to produce PIC " + echo "int some_variable = 0;" > ngc$$.c + + if $AC_CC -c -fPIC -o ngc$$ ngc$$.c $LIBS; then + AC_CFLAGS="$AC_CFLAGS -fPIC" + LOG "(-fPIC)" + __rc=0 + else + LOG "(none)" + __rc=1 + fi + __remove ngc$$ ngc$$.c + return $__rc +} + + +# generate a macosX librarian +# +__AC_MACOS_LIBRARIAN() { + AC_SUB LD_LIBRARY_PATH DYLD_LIBRARY_PATH + __config_files="$__config_files librarian.sh" + cat > librarian.sh << EOF +#! /bin/sh +# +# Build MacOS shared libraries, hiding (some) ickiness from the makefile + +ACTION=\$1; shift +LIBRARY=\$1; shift + +eval \`awk -F. '{ printf "MAJOR=%d\n", \$1; + printf "VERSION=%d.%d.%d\n", \$1, \$2, \$3; }' \$1\` +shift + +LIBNAME=\$LIBRARY.dylib +FULLNAME=\$LIBNAME + +case "\$ACTION" in +make) FLAGS="$AC_CFLAGS -dynamiclib" + VFLAGS="-current_version \$VERSION -compatibility_version \$MAJOR" + + rm -f \$LIBRARY + if $AC_CC \$FLAGS \$VFLAGS -o \$FULLNAME "\$@"; then + $PROG_LN_S \$FULLNAME \$LIBRARY + fi + ;; +files) echo "\$FULLNAME" + ;; +install)$PROG_INSTALL -c \$FULLNAME "\$1" + ;; +esac +EOF + chmod +x librarian.sh +} + + +# Generate an ELF librarian (for Linux, freebsd) +# +__AC_ELF_LIBRARIAN() { + AC_SUB LD_LIBRARY_PATH LD_LIBRARY_PATH + # -Wl option probably works, but be paranoid anyway + _VFLAGS="$AC_PICFLAG -shared -Wl,-soname,ngc$$.so.1" + if $AC_CC $_VFLAGS -o ngc$$.so ngc$$.c; then + USE_SONAME=T + fi + LDCONFIG=`AC_PATH=/sbin:/usr/sbin:/usr/local/sbin acLookFor ldconfig` + + if [ "$LDCONFIG" ]; then + case `uname -s 2>/dev/null | $AC_UPPERCASE` in + *BSD) # *BSD ldconfig, when passed a directory, blows away the + # ld.so hints file and replaces it with one that's just + # the files in the library. It needs a `-m` flag to + # tell it to merge the new entries with the old + LDCONFIG="$LDCONFIG -m" ;; + esac + fi + + __config_files="$__config_files librarian.sh" + cat > librarian.sh << EOF +#! /bin/sh +# +# Build ELF shared libraries, hiding (some) ickiness from the makefile + +ACTION=\$1; shift +LIBRARY=\$1; shift + +eval \`awk -F. '{ printf "MAJOR=%d\n", \$1; + printf "VERSION=%d.%d.%d\n", \$1, \$2, \$3; }' \$1\` +shift + +LIBNAME=\$LIBRARY.so +FULLNAME=\$LIBNAME.\$VERSION + +case "\$ACTION" in +make) FLAGS="$AC_CFLAGS -shared" + unset VFLAGS + test "$USE_SONAME" && VFLAGS="-Wl,-soname,\$LIBNAME.\$MAJOR" + + rm -f \$LIBRARY \$LIBNAME \$LIBNAME.\$MAJOR + if $AC_CC \$FLAGS \$VFLAGS -o \$FULLNAME "\$@"; then + $PROG_LN_S \$FULLNAME \$LIBRARY + $PROG_LN_S \$FULLNAME \$LIBNAME + $PROG_LN_S \$FULLNAME \$LIBNAME.\$MAJOR + fi + ;; +files) echo "\$FULLNAME" "\$LIBNAME" "\$LIBNAME.\$MAJOR" + ;; +install)$PROG_INSTALL -c \$FULLNAME "\$1" + $PROG_LN_S -f \$FULLNAME \$1/\$LIBNAME.\$MAJOR + $PROG_LN_S -f \$FULLNAME \$1/\$LIBNAME +EOF + test "$LDCONFIG" && echo ' '$LDCONFIG '"$1"' >> librarian.sh + cat >> librarian.sh << EOF + ;; +esac +EOF + chmod +x librarian.sh +} + + +# +# AC_CC_SHLIBS checks if the C compiler can produce shared libraries +# and if it can writes a librarian that handles those libraries for us. +# +AC_CC_SHLIBS () { + AC_PROG_CC || AC_FAIL "Need a C compiler to build shared libraries" + AC_PROG_LN_S || AC_FAIL "Need to be able to make symbolic links for shared libraries" + AC_PROG_INSTALL || AC_FAIL "Need an install program to install shared libraries" + + LOGN "checking whether the C compiler can build shared libraries " + + echo "int some_variable = 0;" > ngc$$.c + + _MK_LIBRARIAN= + if uname -a | grep Darwin >/dev/null; then + # Claims to be macos? + if $AC_CC $AC_PICFLAG -dynamiclib -o ngc$$.so ngc$$.c; then + __AC_MACOS_LIBRARIAN + + LOG "(yes; macos dylib)" + __rc=0 + else + LOG "(no)" + __rc=1 + fi + elif $AC_CC $AC_PICFLAG -shared -o ngc$$.so ngc$$.c; then + __AC_ELF_LIBRARIAN + LOG "(yes; -shared)" + __rc=0 + else + _MK_LIBRARIAN=Y + LOG "(no)" + __rc=1 + fi + + __remove ngc$$.so ngc$$.c + + return $__rc +} + + +# +# AC_PROG_INSTALL finds the install program and guesses whether it's a +# Berkeley or GNU install program +# +AC_PROG_INSTALL () { + + if [ $PROG_INSTALL ]; then return; fi + + DEST=`acLookFor install` + + LOGN "looking for install" + unset IS_BSD + if [ "$DEST" ]; then + # BSD install or GNU install? Let's find out... + touch /tmp/a$$ + + $DEST /tmp/a$$ /tmp/b$$ + + if test -r /tmp/a$$; then + LOG " ($DEST)" + else + IS_BSD=1 + LOG " ($DEST) bsd install" + fi + rm -f /tmp/a$$ /tmp/b$$ + else + DEST=`acLookFor ginstall` + if [ "$DEST" ]; then + LOG " ($DEST)" + else + DEST="false" + LOG " (not found)" + fi + fi + + if [ "$IS_BSD" ]; then + PROG_INSTALL="$DEST -c" + else + PROG_INSTALL="$DEST" + fi + + # see if we can strip binaries + echo 'main() { puts("hello, sailor!"); }' > ngc$$.c + if $AC_CC -o ngc$$ ngc$$.c; then + if $PROG_INSTALL -s -m 444 ngc$$ inst$$; then + _strip="-s" + else + unset _strip + LOG "(install -s does not appear to work?)" + fi + rm -f inst$$ + fi + rm -f ngc$$ ngc$$.c + + AC_SUB 'INSTALL' "$PROG_INSTALL" + AC_SUB 'INSTALL_PROGRAM' "$PROG_INSTALL $_strip -m 755" + AC_SUB 'INSTALL_DATA' "$PROG_INSTALL -m 444" + + # finally build a little directory installer + # if mkdir -p works, use that, otherwise use install -d, + # otherwise build a script to do it by hand. + # in every case, test to see if the directory exists before + # making it. + + if mkdir -p $$a/b; then + # I like this method best. + __mkdir="mkdir -p" + rmdir $$a/b + rmdir $$a + elif $PROG_INSTALL -d $$a/b; then + __mkdir="$PROG_INSTALL -d" + rmdir $$a/b + rmdir $$a + fi + + __config_files="$__config_files config.md" + AC_SUB 'INSTALL_DIR' "$__cwd/config.md" + echo "#! /bin/sh" > ""$__cwd"/config.md" + echo "# script generated" `date` "by configure.sh" >> ""$__cwd"/config.md" + echo >> ""$__cwd"/config.md" + if [ "$__mkdir" ]; then + echo "test -d \"\$1\" || $__mkdir \"\$1\"" >> ""$__cwd"/config.md" + echo "exit $?" >> ""$__cwd"/config.md" + else + cat - >> ""$__cwd"/config.md" << \EOD +pieces=`IFS=/; for x in $1; do echo $x; done` +dir= +for x in $pieces; do + dir="$dir$x" + mkdir $dir || exit 1 + dir="$dir/" +done +exit 0 +EOD + fi + chmod +x "$__cwd"/config.md +} + +# +# acCheckCPP is a local that runs a C preprocessor with a given set of +# compiler options +# +acCheckCPP () { + cat > ngc$$.c << EOF +#define FOO BAR + +FOO +EOF + + good= + use_cflags= + if $1 $2 $AC_CFLAGS ngc$$.c > ngc$$.o; then + good=1 + use_cflags=1 + elif $1 $2 ngc$$.c > ngc$$.o; then + good=1 + fi + + if [ "$good" ]; then + if grep -v '#define' ngc$$.o | grep -s BAR >/dev/null; then + echo "CPP=[$1], CPP_PIPE=[$2${use_cflags:+ $AC_CFLAGS}]" + AC_SUB 'CPP' "$1" + AC_CPP_FILTER="$1 $2${use_cflags:+ $AC_CFLAGS}" + rm ngc$$.c ngc$$.o + return 0 + fi + fi + rm ngc$$.c ngc$$.o + return 1 +} + +# +# AC_PROG_CPP checks for cpp, then checks to see which CPPFLAGS are needed +# to run it as a filter. +# +AC_PROG_CPP () { + test "$AC_CPP_FILTER" && return + + AC_PROG_CC + + if [ "$AC_CPP_PROG" ]; then + DEST=$AC_CPP_PROG + else + __ac_path="$AC_PATH" + AC_PATH="/lib:/usr/lib:${__ac_path:-$ac_default_path}" + DEST=`acLookFor cpp` + AC_PATH="$__ac_path" + fi + + unset fail + LOGN "Looking for cpp" + + if acCheckCPP "$AC_CC" -E; then + TLOG " (using \$CC -E as a cpp pipeline)" + return 0 + fi + + if [ "$DEST" ]; then + TLOGN " ($DEST)" + acCheckCPP $DEST "$CPPFLAGS" || \ + acCheckCPP $DEST -traditional-cpp -E || \ + acCheckCPP $DEST -E || \ + acCheckCPP $DEST -traditional-cpp -pipe || \ + acCheckCPP $DEST -pipe || fail=1 + + if [ "$fail" ]; then + AC_FAIL " (can't run cpp as a pipeline)" + else + TLOG " ok" + return 0 + fi + fi + AC_FAIL " (not found)" +} + +# +# AC_FAIL spits out an error message, then __fail's +AC_FAIL() { + LOG "$*" + $__fail 1 +} + +# +# __ac_config_sed; a C program to do escaping for AC_SUB +__ac_config_sed() { + + + test -x config.sed && return + + echo "generating config.sed" + + AC_PROG_CC + +cat > ngc$$.c << \EOF +#include + +int +main(argc, argv) +int argc; +char **argv; +{ + char *p; + + if (argc != 3) + return 1; + + printf("s;@%s@;", argv[1]); + + for (p=argv[2]; *p; ++p) { + if ( *p == ';' ) + putchar('\\'); + putchar(*p); + } + + puts(";g"); + return 0; +} +EOF + + if $AC_CC -o config.sed ngc$$.c; then + rm -f ngc$$.c + __config_files="$__config_files config.sed" + else + rm -f ngc$$.c + AC_FAIL "Cannot generate config.sed helper program" + fi +} + +# +# AC_SUB writes a substitution into config.sub +AC_SUB() { + + _target="$1" + shift + + echo "target=$_target, rest=$*" + + __ac_config_sed + ./config.sed "$_target" "$*" >> "$__cwd"/config.sub +} +# +# AC_TEXT writes arbitrary text into config.h +AC_TEXT() { + echo "$@" >> "$__cwd"/config.h +} + +# +# AC_MAK writes a define into config.mak +AC_MAK() { + echo "HAVE_$1 = 1" >> "$__cwd"/config.mak +} + +# +# AC_DEFINE adds a #define to config.h +AC_DEFINE() { + echo "#define $1 ${2:-1}" >> "$__cwd"/config.h +} + +# +# AC_INCLUDE adds a #include to config.h +AC_INCLUDE() { + echo "#include \"$1\"" >> "$__cwd"/config.h +} + +# +# AC_CONFIG adds a configuration setting to all the config files +AC_CONFIG() { + AC_DEFINE "PATH_$1" \""$2"\" + AC_MAK "$1" + AC_SUB "$1" "$2" +} + +# +# AC_QUIET does something quietly +AC_QUIET() { + eval $* 5>/dev/null +} + + +AC_TR=`acLookFor tr` +if [ "$AC_TR" ]; then + # try posix-style tr + ABC=`echo abc | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ` + if [ "$ABC" = "ABC" ]; then + AC_UPPERCASE="$AC_TR abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ" + AC_UPPER_PAT="ABCDEFGHIJKLMNOPQRSTUVWXYZ" + else + ABC=`echo abc | tr a-z A-Z` + if [ "$ABC" = "ABC" ]; then + AC_UPPERCASE="$AC_TR a-z A-Z" + AC_UPPER_PAT="A-Z" + else + ABC=`echo abc | tr '[a-z]' '[A-Z]'` + if [ "$ABC" = "ABC" ]; then + AC_UPPERCASE="$AC_TR '[a-z]' '[A-Z]'" + AC_UPPER_PAT="'[A-Z]'" + else + AC_FAIL "$AC_TR cannot translate lowercase to uppercase" + return 0 + fi + fi + fi +else + AC_FAIL "configure requires a functional version of tr" +fi + +while [ $# -gt 0 ]; do + unset matched + + case X"$1" in + X--src|X--srcdir) + AC_SRCDIR=`__ac_dir "$2"` + _set_srcdir=1 + shift 2;; + + X--src=*|X--srcdir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_SRCDIR=`__ac_dir "$__d"` + _set_srcdir=1 + shift 1 ;; + + X--prefix) + AC_PREFIX=`__ac_dir "$2"` + _set_prefix=1 + shift 2;; + + X--prefix=*) + __d=`echo "$1"| sed -e 's/^[^=]*=//'` + AC_PREFIX=`__ac_dir "$__d"` + _set_prefix=1 + shift 1;; + + X--confdir) + AC_CONFDIR=`__ac_dir "$2"` + _set_confdir=1 + shift 2;; + + X--confdir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_CONFDIR=`__ac_dir "$__d"` + _set_confdir=1 + shift 1;; + + X--libexec|X--libexecdir) + AC_LIBEXEC=`__ac_dir "$2"` + _set_libexec=1 + shift 2;; + + X--libexec=*|X--libexecdir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_LIBEXEC=`__ac_dir "$__d"` + _set_libexec=1 + shift 1;; + + X--lib|X--libdir) + AC_LIBDIR=`__ac_dir "$2"` + _set_libdir=1 + shift 2;; + + X--lib=*|X--libdir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_LIBDIR=`__ac_dir "$__d"` + _set_libdir=1 + shift 1;; + + X--exec|X--execdir) + AC_EXECDIR=`__ac_dir "$2"` + _set_execdir=1 + shift 2;; + + X--exec=*|X--execdir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_EXECDIR=`__ac_dir "$__d"` + _set_execdir=1 + shift 1;; + + X--sbin|X--sbindir) + AC_SBINDIR=`__ac_dir "$2"` + _set_sbindir=1 + shift 2;; + + X--sbin=*|X--sbindir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_SBINDIR=`__ac_dir "$__d"` + _set_sbindir=1 + shift 1;; + + X--man|X--mandir) + AC_MANDIR=`__ac_dir "$2"` + _set_mandir=1 + shift 2;; + + X--man=*|X--mandir=*) + __d=`echo "$1" | sed -e 's/^[^=]*=//'` + AC_MANDIR=`__ac_dir "$__d"` + _set_mandir=1 + shift 1;; + + X--use-*=*) + _var=`echo "$1"| sed -n 's/^--use-\([A-Za-z][-A-Za-z0-9_]*\)=.*$/\1/p'` + if [ "$_var" ]; then + _val=`echo "$1" | sed -e 's/^--use-[^=]*=\(.*\)$/\1/'` + _v=`echo $_var | $AC_UPPERCASE | tr '-' '_'` + case X"$_val" in + X[Yy][Ee][Ss]|X[Tt][Rr][Uu][Ee]) eval USE_${_v}=T ;; + X[Nn][Oo]|X[Ff][Aa][Ll][Ss][Ee]) eval unset USE_${_v} ;; + *) echo "Bad value for --use-$_var ; must be yes or no" + exit 1 ;; + esac + else + echo "Bad option $1. Use --help to show options" 1>&2 + exit 1 + fi + shift 1 ;; + + X--use-*) + _var=`echo "$1"|sed -n 's/^--use-\([A-Za-z][-A-Za-z0-9_]*\)$/\1/p'` + _v=`echo $_var | $AC_UPPERCASE | tr '-' '_'` + eval USE_${_v}=T + shift 1;; + + X--with-*=*) + _var=`echo "$1"| sed -n 's/^--with-\([A-Za-z][-A-Za-z0-9_]*\)=.*$/\1/p'` + if [ "$_var" ]; then + _val=`echo "$1" | sed -e 's/^--with-[^=]*=\(.*\)$/\1/'` + _v=`echo $_var | $AC_UPPERCASE | tr '-' '_'` + eval WITH_${_v}=\"$_val\" + else + echo "Bad option $1. Use --help to show options" 1>&2 + exit 1 + fi + shift 1 ;; + + X--with-*) + _var=`echo "$1" | sed -n 's/^--with-\([A-Za-z][A-Za-z0-9_-]*\)$/\1/p'` + if [ "$_var" ]; then + _v=`echo $_var | $AC_UPPERCASE | tr '-' '_'` + eval WITH_${_v}=1 + else + echo "Bad option $1. Use --help to show options" 1>&2 + exit 1 + fi + shift 1 ;; + + X--help) + echo "$ac_standard" + test "$ac_help" && echo "$ac_help" + exit 0;; + + *) if [ "$LOCAL_AC_OPTIONS" ]; then + eval "$LOCAL_AC_OPTIONS" + else + ac_error=T + fi + if [ "$ac_error" ]; then + echo "Bad option $1. Use --help to show options" 1>&2 + exit 1 + fi ;; + esac +done + diff --git a/thirdparty/discount-2.2.6-patched/configure.sh b/thirdparty/discount-2.2.6-patched/configure.sh new file mode 100755 index 00000000..da9fa147 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/configure.sh @@ -0,0 +1,264 @@ +#! /bin/sh + +# local options: ac_help is the help message that describes them +# and LOCAL_AC_OPTIONS is the script that interprets them. LOCAL_AC_OPTIONS +# is a script that's processed with eval, so you need to be very careful to +# make certain that what you quote is what you want to quote. + +# load in the configuration file +# +ac_help='--enable-amalloc Enable memory allocation debugging +--with-tabstops=N Set tabstops to N characters (default is 4) +--shared Build shared libraries (default is static) +--pkg-config Install pkg-config(1) glue files +--cxx-binding Install header files with c++ wrappers +--github-checkbox[=input] Enable github-style checkboxes in lists + (if =input, use , otherwise + use html ballot entities)' + +LOCAL_AC_OPTIONS=' +set=`locals $*`; +if [ "$set" ]; then + eval $set + shift 1 +else + ac_error=T; +fi' + +locals() { + K=`echo $1 | $AC_UPPERCASE` + case "$K" in + --SHARED) + echo TRY_SHARED=T + ;; + --ENABLE-*) enable=`echo $K | sed -e 's/--ENABLE-//' | tr '-' '_'` + echo WITH_${enable}=T ;; + --DEBIAN-GLITCH) + echo DEBIAN_GLITCH=T + ;; + --H1-TITLE) + echo H1TITLE=T + ;; + --PKG-CONFIG) + echo PKGCONFIG=T + ;; + --CXX-BINDING) + echo CXX_BINDING=T + ;; + --GITHUB-CHECKBOX) + echo GITHUB_CHECKBOX=T + ;; + --GITHUB-CHECKBOX=INPUT) + echo GITHUB_CHECKBOX=T + echo GITHUB_CHECKBOX_AS_INPUT=T + ;; + esac +} + +VERSION=`cat VERSION` +TARGET=markdown +. ./configure.inc + +# if there's a makefile here, it's likely that it's a discount +# makefile and there's bits of an old configuration here. So +# blow everything away before we start the configuration. + +test -f Makefile && make spotless 2>/dev/null >/dev/null + +AC_INIT $TARGET +AC_SUB 'PACKAGE_NAME' lib$TARGET +AC_SUB 'PACKAGE_VERSION' $VERSION + +for banned_with in dl fenced-code id-anchor github-tags urlencoded-anchor; do + banned_with_variable_ref=\$WITH_`echo "$banned_with" | $AC_UPPERCASE | tr - _` + if [ "`eval echo "$banned_with_variable_ref"`" ]; then + LOG "Setting theme default --with-$banned_with." + fi +done + +# theme wants the old behavior of --with-(foo) +# +case "`echo "$WITH_DL" | $AC_UPPERCASE`" in + EXTRA) THEME_CF="MKD_DLEXTRA|MKD_NODLDISCOUNT";; + BOTH) THEME_CF="MKD_DLEXTRA";; +esac +test "$WITH_FENCED_CODE" && THEME_CF="${THEME_CF:+$THEME_CF|}MKD_FENCEDCODE" + +AC_DEFINE THEME_CF "$THEME_CF" + + +test "$DEBIAN_GLITCH" && AC_DEFINE 'DEBIAN_GLITCH' 1 + +AC_PROG_CC +AC_QUIET AC_PROG git && AC_DEFINE 'HAS_GIT' '1' +AC_CHECK_ATTRIBUTE destructor + +test "$TRY_SHARED" && AC_COMPILER_PIC && AC_CC_SHLIBS + +if [ "IS_BROKEN_CC" ]; then + case "$AC_CC $AC_CFLAGS" in + *-pedantic*) ;; + *) # hack around deficiencies in gcc and clang + # + AC_DEFINE 'while(x)' 'while( (x) != 0 )' + AC_DEFINE 'if(x)' 'if( (x) != 0 )' + + if [ "$IS_CLANG" ]; then + AC_CC="$AC_CC -Wno-implicit-int" + elif [ "$IS_GCC" ]; then + AC_CC="$AC_CC -Wno-return-type -Wno-implicit-int" + fi ;; + esac +fi + +AC_PROG ar || AC_FAIL "$TARGET requires ar" +AC_PROG ranlib + +# should we create a .pc for pkg-config & GNU automake +# +if [ "$PKGCONFIG" ]; then + AC_SUB MK_PKGCONFIG '' +elif AC_PROG pkg-config || AC_PROG automake ; then + PKGCONFIG=true + AC_SUB MK_PKGCONFIG '' +else + AC_SUB MK_PKGCONFIG '#' +fi + +AC_C_VOLATILE +AC_C_CONST +AC_C_INLINE +AC_SCALAR_TYPES sub hdr +AC_CHECK_BASENAME +AC_CHECK_ALLOCA + +AC_CHECK_HEADERS sys/types.h pwd.h && AC_CHECK_FUNCS getpwuid +if AC_CHECK_HEADERS sys/stat.h && AC_CHECK_FUNCS stat; then + +# need to check some of the S_ISxxx stat macros, because they may not +# exist (for notspecial.c) + +cat > ngc$$.c << EOF +#include + +main(argc, argv) +char **argv; +{ + struct stat info; + + if ( stat(argv[0], &info) != 0 ) + return 1; + + return MACRO(info.st_mode); +} +EOF + LOGN "special file macros in sys/stat.h:" + _none="none" + for x in ISSOCK ISCHR ISFIFO; do + if $AC_CC -DMACRO=S_$x -o ngc$$.o ngc$$.c; then + LOGN " S_${x}" + AC_DEFINE "HAS_${x}" '1' + unset _none + fi + done + LOG "${_none}." + __remove ngc$$.o ngc$$.c +fi + +if AC_CHECK_FUNCS srandom; then + AC_DEFINE 'INITRNG(x)' 'srandom((unsigned int)x)' +elif AC_CHECK_FUNCS srand; then + AC_DEFINE 'INITRNG(x)' 'srand((unsigned int)x)' +else + AC_DEFINE 'INITRNG(x)' '(void)1' +fi + +AC_CHECK_FUNCS 'memset((char*)0,0,0)' 'string.h' || \ + AC_CHECK_FUNCS 'memset((char*)0,0,0)' || \ + AC_FAIL "$TARGET requires memset" + +if AC_CHECK_FUNCS random; then + AC_DEFINE 'COINTOSS()' '(random()&1)' +elif AC_CHECK_FUNCS rand; then + AC_DEFINE 'COINTOSS()' '(rand()&1)' +else + AC_DEFINE 'COINTOSS()' '1' +fi + +if AC_CHECK_FUNCS strcasecmp; then + : +elif AC_CHECK_FUNCS stricmp; then + AC_DEFINE strcasecmp stricmp +else + AC_FAIL "$TARGET requires either strcasecmp() or stricmp()" +fi + +if AC_CHECK_FUNCS strncasecmp; then + : +elif AC_CHECK_FUNCS strnicmp; then + AC_DEFINE strncasecmp strnicmp +else + AC_FAIL "$TARGET requires either strncasecmp() or strnicmp()" +fi + +if AC_CHECK_FUNCS fchdir || AC_CHECK_FUNCS getcwd ; then + AC_SUB 'THEME' '' +else + AC_SUB 'THEME' '#' +fi + +if [ -z "$WITH_TABSTOPS" ]; then + TABSTOP=4 +elif [ "$WITH_TABSTOPS" -eq 1 ]; then + TABSTOP=8 +else + TABSTOP=$WITH_TABSTOPS +fi +AC_DEFINE 'TABSTOP' $TABSTOP +AC_SUB 'TABSTOP' $TABSTOP + + +if [ "$WITH_AMALLOC" ]; then + AC_DEFINE 'USE_AMALLOC' 1 + AC_SUB 'AMALLOC' 'amalloc.o' +else + AC_SUB 'AMALLOC' '' +fi + +if [ "$H1TITLE" ]; then + AC_SUB 'H1TITLE' h1title.o + AC_DEFINE USE_H1TITLE 1 +else + AC_SUB 'H1TITLE' '' +fi + +if [ "$GITHUB_CHECKBOX" ]; then + AC_DEFINE 'GITHUB_CHECKBOX' '1' + test "$GITHUB_CHECKBOX_AS_INPUT" && AC_DEFINE 'CHECKBOX_AS_INPUT' '1' +fi + + +[ "$OS_FREEBSD" -o "$OS_DRAGONFLY" ] || AC_CHECK_HEADERS malloc.h + +[ "$WITH_PANDOC_HEADER" ] && AC_DEFINE 'PANDOC_HEADER' '1' + +GENERATE="Makefile version.c mkdio.h" + +if [ "$PKGCONFIG" ]; then + GENERATE="$GENERATE libmarkdown.pc" +fi + +AC_OUTPUT $GENERATE + +if [ "$CXX_BINDING" ]; then + LOG "applying c++ glue to mkdio.h" + mv mkdio.h mkdio.h$$ + ( echo '#ifdef __cplusplus' + echo 'extern "C" {' + echo '#endif' + cat mkdio.h$$ + echo '#ifdef __cplusplus' + echo '}' + echo '#endif' ) > mkdio.h + rm mkdio.h$$ +fi diff --git a/thirdparty/discount-2.2.6-patched/css.c b/thirdparty/discount-2.2.6-patched/css.c new file mode 100644 index 00000000..fd9ede98 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/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 ) { + /* null-terminate, then strdup() into a free()able memory + * chunk + */ + EXPAND(f) = 0; + *res = strdup(T(f)); + } + DELETE(f); + return size; + } + return EOF; +} + + +/* dump any embedded styles to a file + */ +int +mkd_generatecss(Document *d, FILE *f) +{ + char *res; + int written; + int size = mkd_css(d, &res); + + written = (size > 0) ? fwrite(res,1,size,f) : 0; + + if ( res ) + free(res); + + return (written == size) ? size : EOF; +} diff --git a/thirdparty/discount-2.2.6-patched/cstring.h b/thirdparty/discount-2.2.6-patched/cstring.h new file mode 100644 index 00000000..f0b74109 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/cstring.h @@ -0,0 +1,76 @@ +/* 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) \ + S(t) -= ( ((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])), \ + (sz)) : 0 + +#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 PREFIX(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); + +#endif/*_CSTRING_D*/ diff --git a/thirdparty/discount-2.2.6-patched/docheader.c b/thirdparty/discount-2.2.6-patched/docheader.c new file mode 100644 index 00000000..2bde634b --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/docheader.c @@ -0,0 +1,54 @@ +/* + * 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; + + if ( l->dle < 0 || l->dle >= S(l->text) ) + return 0; + + 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/thirdparty/discount-2.2.6-patched/dumptree.c b/thirdparty/discount-2.2.6-patched/dumptree.c new file mode 100644 index 00000000..e3fbaf3e --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/dumptree.c @@ -0,0 +1,160 @@ +/* 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); + + if ( pp->typ == HDR ) + d += fprintf(f, "[h%d", pp->hnumber); + else + d = fprintf(f, "[%s", Pptype(pp->typ)); + if ( pp->ident ) + d += fprintf(f, " %s", pp->ident); + +#ifdef GITHUB_CHECKBOX + if ( pp->flags ) + d += fprintf(f, " %x", pp->flags); +#endif + + 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, mkd_flag_t 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); + + return 0; + } + return -1; +} diff --git a/thirdparty/discount-2.2.6-patched/emmatch.c b/thirdparty/discount-2.2.6-patched/emmatch.c new file mode 100644 index 00000000..daea9398 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/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) + * compatible 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); + + PREFIX(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/thirdparty/discount-2.2.6-patched/flags.c b/thirdparty/discount-2.2.6-patched/flags.c new file mode 100644 index 00000000..78ff3dca --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/flags.c @@ -0,0 +1,93 @@ +#include +#include "markdown.h" + +struct flagnames { + mkd_flag_t 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" }, + { MKD_NOSTYLE, "!STYLE" }, + { MKD_NODLDISCOUNT, "!DLDISCOUNT" }, + { MKD_DLEXTRA, "DLEXTRA" }, + { MKD_FENCEDCODE, "FENCEDCODE" }, + { MKD_IDANCHOR, "IDANCHOR" }, + { MKD_GITHUBTAGS, "GITHUBTAGS" }, + { MKD_URLENCODEDANCHOR, "URLENCODEDANCHOR" }, + { MKD_LATEX, "LATEX" }, + { MKD_EXPLICITLIST, "EXPLICITLIST" }, +}; +#define NR(x) (sizeof x/sizeof x[0]) + + +void +mkd_flags_are(FILE *f, mkd_flag_t 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/thirdparty/discount-2.2.6-patched/generate.c b/thirdparty/discount-2.2.6-patched/generate.c new file mode 100644 index 00000000..adfa7abc --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/generate.c @@ -0,0 +1,2107 @@ +/* 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++; +} + + +/* + * push a character into the generator input buffer + */ +static void +pushc(char c, MMIOT *f) +{ + EXPAND(f->in) = c; +} + + +/* 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)) ? (unsigned char)T(f->in)[i] : EOF; +} + + +/* pull a byte from the input buffer + */ +static inline unsigned int +pull(MMIOT *f) +{ + return ( f->isp < S(f->in) ) ? (unsigned char)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); + + if ( c == EOF ) + return 1; + if ( c & 0x80 ) + return 0; + return isspace(c) || (c < ' '); +} + + +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 + * (when setting the current cursor position we also need to flush the + * last character written cache) + */ +#define mmiotseek(f,x) ((f->isp = x), (f->last = 0)) +#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); +} + + +/* Qanchor() prints out a suitable-for-id-tag version of a string + */ +static void +Qanchor(struct line *p, MMIOT *f) +{ + mkd_string_to_anchor(T(p->text), S(p->text), + (mkd_sta_function_t)Qchar, f, 1, 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, mkd_flag_t flags, MMIOT *f, char *esc) +{ + MMIOT sub; + struct escaped e; + + ___mkd_initmmiot(&sub, f->footnotes); + + sub.flags = f->flags | flags; + sub.cb = f->cb; + sub.ref_prefix = f->ref_prefix; + + if ( esc ) { + sub.esc = &e; + e.up = f->esc; + e.text = esc; + } + else + sub.esc = f->esc; + + push(bfr, size, &sub); + pushc(0, &sub); + S(sub.in)--; + + text(&sub); + ___mkd_emblock(&sub); + + Qwrite(T(sub.out), S(sub.out), f); + /* inherit the last character printed from the reparsed + * text; this way superscripts can work when they're + * applied to something embedded in a link + */ + f->last = sub.last; + + ___mkd_freemmiot(&sub, f->footnotes); +} + + +/* + * check the escape list for special cases + */ +static int +escaped(MMIOT *f, char c) +{ + struct escaped *thing = f->esc; + + while ( thing ) { + if ( strchr(thing->text, c) ) + return 1; + thing = thing->up; + } + return 0; +} + + +/* + * 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 == MKD_EOLN ) /* untokenize hard return */ + 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 ( !is_flag_set(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 ( is_flag_set(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, 0); + + 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, 0); + else { + ref->flags |= REFERENCED; + ref->refnumber = ++ f->footnotes->reference; + Qprintf(f, "%d", + p_or_nothing(f), ref->refnumber, + p_or_nothing(f), ref->refnumber, ref->refnumber); + } + return 1; +} /* extra_linky */ + + + +/* check a url (or url fragment to see that it begins with a known good + * protocol (or no protocol at all) + */ +static int +safelink(Cstring link) +{ + char *p, *colon; + + if ( T(link) == 0 ) /* no link; safe */ + return 1; + + p = T(link); + if ( (colon = memchr(p, ':', S(link))) == 0 ) + return 1; /* no protocol specified: safe */ + + if ( !isalpha(*p) ) /* protocol/method is [alpha][alnum or '+.-'] */ + return 1; + while ( ++p < colon ) + if ( !(isalnum(*p) || *p == '.' || *p == '+' || *p == '-') ) + return 1; + + return isautoprefix(T(link), S(link)); +} + + +/* 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 ) + tag = &imaget; + else if ( tag = pseudo(ref->link) ) { + if ( is_flag_set(f->flags, MKD_NO_EXT) || is_flag_set(f->flags, MKD_SAFELINK) ) + return 0; + } + else if ( is_flag_set(f->flags, MKD_SAFELINK) && !safelink(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 ( is_flag_set(f->flags, IS_LABEL) ) + ___mkd_reparse(T(text), S(text), tag->flags, f, 0); + 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, 0); + Qchar('"', f); + } + + Qstring(tag->text_pfx, f); + ___mkd_reparse(T(text), S(text), tag->flags, f, 0); + 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 = !is_flag_set(f->flags, MKD_1_COMPAT); + + if ( is_flag_set(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->note), + S(f->footnotes->note), + sizeof key, (stfu)__mkd_footsort) ) { + if ( extra_footnote ) + status = extra_linky(f,name,ref); + else + status = linkyformat(f, name, image, ref); + } + } + } + } + + 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 ) { +#if DEBIAN_GLITCH + Qprintf(f, "&#%02d;", *((unsigned char*)(s++)) ); +#else + Qstring("&#", f); + Qprintf(f, COINTOSS() ? "x%02x;" : "%02d;", *((unsigned char*)(s++)) ); +#endif + } +} + + +/* 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]) == MKD_EOLN) /* expand back to 2 spaces */ + Qstring(" ", f); + else if ( c == '\\' && (i < length-1) && escaped(f, s[i+1]) ) + cputc(s[++i], 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, 0); + 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 ( is_flag_set(f->flags, MKD_NOHTML) ) + return 1; + + if ( c == 'A' && is_flag_set(f->flags, MKD_NOLINKS) && !isthisalnum(f,2) ) + return 1; + if ( c == 'I' && is_flag_set(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 ( is_flag_set(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 ( is_flag_set(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; + else if ( ! (c == '/' + || (is_flag_set(f->flags, MKD_GITHUBTAGS) && (c == '-' || c == '_')) + || isalnum(c) ) ) + 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 ( c & 0x80 ) /* HACK: ignore utf-8 extended characters */ + continue; + else if ( isspace(c) || strchr("'\"()[]{}<>`", c) || c == MKD_EOLN ) + 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 ( is_flag_set(f->flags, MKD_NOPANTS) + || is_flag_set(f->flags, MKD_TAGTEXT) + || is_flag_set(f->flags, 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, 0); + Qstring("”", f); + shift(f,j+1); + return 1; + } + else ++j; + } + + } + break; + } + return 0; +} /* smartypants */ + + +/* process latex with arbitrary 2-character ( $$ .. $$, \[ .. \], \( .. \) + * delimiters + */ +static int +mathhandler(MMIOT *f, int e1, int e2) +{ + int i = 0; + + while(peek(f, ++i) != EOF) { + if (peek(f, i) == e1 && peek(f, i+1) == e2) { + cputc(peek(f,-1), f); + cputc(peek(f, 0), f); + cputc(6, f); + EXPAND(f->latex) = peek(f,-1); + EXPAND(f->latex) = peek(f,0); + EXPAND(f->latex) = 6; + while ( i-- > -1 ) { + char c = pull(f); + EXPAND(f->latex) = c; + cputc(c, f); + } + EXPAND(f->latex) = 31; + return 1; + } + } + return 0; +} + +/* + * process latex with arbitrary custom delimiters + */ +static int +mathhandlerExtended(MMIOT *f, char* begin, char* end) +{ + int beginLength = strlen(begin); + int endLength = strlen(end); + + for (int i = 0; i < beginLength; i++) + if (peek(f, i) != begin[i]) + return 0; + + int i = beginLength; + while(peek(f, ++i) != EOF) { + int matchEnd = 1; + for (int j = 0; j < endLength; j++) + if (peek(f, i + j) != end[j]) + matchEnd = 0; + + if (matchEnd == 1) { + i += endLength; + + cputc(6, f); + EXPAND(f->latex) = '\\'; + EXPAND(f->latex) = 6; + + while ( --i > 0 ) + { + char c = pull(f); + EXPAND(f->latex) = c; + cputc(c, f); + } + + EXPAND(f->latex) = 31; + return 1; + } + } + return 0; +} + + +/* 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) is_flag_set(f->flags, MKD_TAGTEXT) + + +static void +text(MMIOT *f) +{ + int c, j; + int rep; + int smartyflags = 0; + + while (1) { + if ( is_flag_set(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 MKD_EOLN: + 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 ( is_flag_set(f->flags, MKD_NOSUPERSCRIPT) + || is_flag_set(f->flags, MKD_STRICT) + || is_flag_set(f->flags, MKD_TAGTEXT) + || (f->last == 0) + || ((ispunct(f->last) || isspace(f->last)) + && f->last != ')') + || 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 ( !(is_flag_set(f->flags, MKD_NORELAXED) || is_flag_set(f->flags, 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 ( is_flag_set(f->flags, MKD_NOSTRIKETHROUGH) + || is_flag_set(f->flags, MKD_STRICT) + || is_flag_set(f->flags, MKD_TAGTEXT) + || ! 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 '<': c = peek(f,1); + if ( (c == EOF) || isspace(c) ) + Qstring("<", f); + else { + /* Markdown.pl does not escape <[nonwhite] + * sequences */ + Qchar('\\', f); + shift(f, -1); + } + + break; + case '^': if ( is_flag_set(f->flags, MKD_STRICT) + || is_flag_set(f->flags, MKD_NOSUPERSCRIPT) ) { + Qchar('\\', f); + shift(f,-1); + break; + } + Qchar(c, f); + break; + + case ':': case '|': + if ( is_flag_set(f->flags, MKD_NOTABLES) ) { + Qchar('\\', f); + shift(f,-1); + break; + } + Qchar(c, f); + break; + + case EOF: Qchar('\\', f); + break; + + case '[': + case '(': + Qchar(c, f); + break; + + case '$': if ( is_flag_set(f->flags, MKD_LATEX) ) { + Qchar(c, f); + break; + } + + default: + if ( escaped(f,c) || + strchr(">#.-+{}]![*_\\()`", c) ) + Qchar(c, f); + else { + Qchar('\\', f); + shift(f, -1); + if ( is_flag_set(f->flags, MKD_LATEX) ) { + mathhandlerExtended(f, "\\begin{equation}", "\\end{equation}") + || mathhandlerExtended(f, "\\begin{equation*}", "\\end{equation*}") + || mathhandlerExtended(f, "\\begin{align}", "\\end{align}") + || mathhandlerExtended(f, "\\begin{align*}", "\\end{align*}") + || mathhandlerExtended(f, "\\begin{bmatrix}", "\\end{bmatrix}") + || mathhandlerExtended(f, "\\begin{cases}", "\\end{cases}"); + } + } + 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; + + case '$': if ( is_flag_set(f->flags, MKD_LATEX) ) { + if (peek(f, 1) == '$' ) { + pull(f); + if ( mathhandler(f, '$', '$') ) + break; + Qchar('$', f); + } + else { + int c2; + int i = 1; + + while ( ((c2=peek(f,i)) != '$') && (c2 != EOF) ) + i++; + if ( c2 != EOF ) { + Qchar('$', f); + cputc(6, f); + EXPAND(f->latex) = '$'; + EXPAND(f->latex) = 6; + while (i-- > 0 ) { + char sym = pull(f); + EXPAND(f->latex) = sym; + Qchar(sym, f); + } + EXPAND(f->latex) = 31; + break; + } + } + } + /* fall through to default */ + + default: f->last = c; + 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 ( is_flag_set(f->flags, MKD_IDANCHOR) ) { + Qprintf(f, "hnumber); + if ( is_flag_set(f->flags, MKD_TOC) ) { + Qstring(" id=\"", f); + Qanchor(pp->text, f); + Qchar('"', f); + } + Qchar('>', f); + } else { + if ( is_flag_set(f->flags, MKD_TOC) ) { + Qstring("
text, f); + Qstring("\">\n", f); + } + Qprintf(f, "", pp->hnumber); + } + 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[] = { "", " style=\"text-align:center;\"", + " style=\"text-align:left;\"", + " style=\"text-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) +{ + static char *Begin[] = { "", "

", "

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

","

" }; + Line *t = pp->text; + int align = pp->align; + + 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); + pushc(MKD_EOLN, f); + pushc('\n', f); + } + else { + ___mkd_tidy(&t->text); + push(T(t->text), S(t->text), f); + if ( t->next ) + pushc('\n', f); + } + } + t = t->next; + } + Qstring(Begin[align], f); + text(f); + Qstring(End[align], f); + return 1; +} + + +static void +printcode(Line *t, char *lang, MMIOT *f) +{ + int blanks; + + if ( f->cb->e_codefmt ) { + /* external code block formatter; copy the text into a buffer, + * call the formatter to style it, then dump that styled text + * directly to the queue + */ + char *text; + char *fmt; + int size, copy_p; + Line *p; + + for (size=0, p = t; p; p = p->next ) + size += 1+S(p->text); + + text = malloc(1+size); + + for ( copy_p = 0; t ; t = t->next ) { + memcpy(text+copy_p, T(t->text), S(t->text)); + copy_p += S(t->text); + text[copy_p++] = '\n'; + } + text[copy_p] = 0; + + fmt = (*(f->cb->e_codefmt))(text, copy_p, (lang && lang[0]) ? lang : 0); + free(text); + + if ( fmt ) { + Qwrite(fmt, strlen(fmt), f); + if ( f->cb->e_free ) + (*(f->cb->e_free))(fmt, f->cb->e_data); + return; + } + /* otherwise the external formatter failed and we need to + * fall back to the traditional codeblock format + */ + } + + 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_paragraphs(Paragraph *p, MMIOT *f) +{ + ___mkd_emblock(f); + + while (( p = display(p, f) )) { + ___mkd_emblock(f); + Qstring("\n\n", f); + } +} + + +#ifdef GITHUB_CHECKBOX +static void +li_htmlify(Paragraph *p, char *arguments, mkd_flag_t flags, MMIOT *f) +{ + ___mkd_emblock(f); + + Qprintf(f, ""); +#if CHECKBOX_AS_INPUT + if ( flags & GITHUB_CHECK ) { + Qprintf(f, ""); + } +#else + if ( flags & GITHUB_CHECK ) + Qprintf(f, flags & IS_CHECKED ? "☑" : "☐"); +#endif + + htmlify_paragraphs(p, f); + + Qprintf(f, ""); + ___mkd_emblock(f); +} +#endif + + +static void +htmlify(Paragraph *p, char *block, char *arguments, MMIOT *f) +{ + ___mkd_emblock(f); + if ( block ) + Qprintf(f, arguments ? "<%s %s>" : "<%s>", block, arguments); + + htmlify_paragraphs(p, 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, 0); + 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 ) { +#ifdef GITHUB_CHECKBOX + li_htmlify(p->down, p->ident, p->flags, f); +#else + htmlify(p->down, "li", p->ident, f); +#endif + 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, p->lang, 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->footnotes->reference == 0 ) + return; + + Csprintf(&m->out, "\n
\n
\n
    \n"); + + for ( i=1; i <= m->footnotes->reference; i++ ) { + for ( j=0; j < S(m->footnotes->note); j++ ) { + t = &T(m->footnotes->note)[j]; + if ( (t->refnumber == i) && (t->flags & REFERENCED) ) { + Csprintf(&m->out, "
  1. \n", + p_or_nothing(m), t->refnumber); + htmlify(t->text, 0, 0, m); + 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 ( is_flag_set(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] ) { + /* Add a null byte at the end of the generated html, + * but pretend it doesn't exist. + */ + EXPAND(p->ctx->out) = 0; + --S(p->ctx->out); + } + } + + *res = T(p->ctx->out); + return S(p->ctx->out); + } + return EOF; +} + +/* Return list of founded latex textes (only textes, without positions) separeted by ASCII unit separator (code - 31) + * Ugly, but works + */ +int +mkd_latextext(Document *p, char **res) +{ + int size; + + if ( p && p->compiled ) { + if ( ! p->html ) { + htmlify(p->code, 0, 0, p->ctx); + if ( is_flag_set(p->ctx->flags, MKD_EXTRA_FOOTNOTE) ) + mkd_extra_footnotes(p->ctx); + p->html = 1; + size = S(p->ctx->latex); + + if ( (size == 0) || T(p->ctx->latex)[size-1] ) { + /* Add a null byte at the end of the generated html, + * but pretend it doesn't exist. + */ + EXPAND(p->ctx->latex) = 0; + --S(p->ctx->latex); + } + } + + *res = T(p->ctx->latex); + return S(p->ctx->latex); + } + return EOF; +} diff --git a/thirdparty/discount-2.2.6-patched/gethopt.3 b/thirdparty/discount-2.2.6-patched/gethopt.3 new file mode 100644 index 00000000..0aed09e6 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/gethopt.3 @@ -0,0 +1,196 @@ +.\" Copyright (c) 1988, 1991 Regents of the University of California. +.\" Copyright (c) 2017 David Loren Parsons. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 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. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS 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 THE REGENTS OR CONTRIBUTORS 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. +.\" +.Dd Jan 23, 2017 +.Dt GETHOPT 3 +.Os Mastodon +.Sh NAME +.Nm gethopt +.Nd get option letter or word from argv +.Sh SYNOPSIS +.Fd #include "gethopt.h" + +.Bd -literal -compact +struct h_opt { + int option; + char *optword; + char optchar; + int opthasarg; + char *optdesc; +} ; +.Ed +.Ft char* +.Fn hoptarg "struct h_context* argctx" +.Ft int +.Fn hoptind "struct h_context* argctx" +.Ft int +.Fn hopterr "struct h_context* argctx" "int flag" +.Ft char +.Fn hoptopt "struct h_context* argctx" +.Ft void +.Fn hoptset "struct h_context* argctx" "int argc" "char** argv" +.Ft struct h_opt* +.Fn gethopt "struct h_context* argctx" "struct h_opt* optarray" "int nropts" + +.Sh DESCRIPTION +The +.Fn gethopt +function gets +the next +.Em known +option word or character from +.Fa argctx . +An option is +.Em known +if it has been specified in the array of accepted options +.Fa optarray . +.Pp +The option array +.Fa optarray +contains records with either an option word, character, or both, +a flag saying the option needs an argument, a short description +of the option, and an +.Va option +key (which is there for the convenience of the calling program; +.Fn gethopt +does not use it in any way.). +It does not matter to +.Fn getopt +if a following argument has leading white space. +.Pp +On return from +.Fn gethopt , +.Fn hoptarg +returns an option argument, if it is anticipated, +and the variable +.Fn hoptind +contains the index to the next +.Fa argv +argument for a subsequent call +to +.Fn gethopt . +.Pp +.Fn +gethopt +uses a (semi) opaque data blob to hold the current state, which +must be initialized by the +.Fn hoptset +function. +.Pp +The +.Fn gethopt +function +returns +.Dv HOPTERR +if a non-recognized +option is encountered, +and NULL when it reaches the end of the options on the command line.. +.Pp +The interpretation of options in the argument list may be cancelled +by +.Ql - +(single dash) or +.Ql -- +(double dash) which causes +.Fn getopt +to signal the end of argument processing and return an +.Dv NULL . +When all options have been processed (i.e., up to the first non-option +argument), +.Fn gethopt +returns +.Dv NULL . +.Sh DIAGNOSTICS +If the +.Fn gethopt +function encounters a character not found in +.Va optarray +or detects +a missing option argument +it returns +.Dv HOPTERR +(and writes an error message to the +.Em stderr +if +.Fn hopterr +is used to turn error reporting on.) +.Sh EXAMPLE +.Bd -literal -compact +struct h_opt opts[] = { + { 0, "css", 0, 1, "css file" }, + { 1, "header", 0, 1, "header file" }, + { 2, 0, 'a', 0, "option a (no arg)" }, + { 3, 0, 'b', 1, "option B (with arg)" }, + { 4, "help", '?', 0, "help message" }, +} ; + +#define NROPT (sizeof opts/sizeof opts[0]) + + +int +main(argc, argv) +char **argv; +{ + struct h_opt *ret; + struct h_context ctx; + + hoptset(&ctx, argc, argv); + hopterr(&ctx, 1); + + while (( ret = gethopt(&ctx, opts, NROPT) )) { + + if ( ret != HOPTERR ) { + if ( ret->optword ) + printf("%s", ret->optword); + else + printf("%c", ret->optchar); + + if ( ret->opthasarg ) { + if ( hoptarg(&ctx) ) + printf(" = %s", hoptarg(&ctx)); + else + printf(" with no argument?"); + } + puts(ret->optdesc ? ret->optdesc : ""); + } + } + + argc -= hoptind(&ctx); + argv += hoptind(&ctx); + +.Ed +.Sh HISTORY +The +.Fn gethopt +function was a quick hack to replace manually parsing full-word arguments +in +.Va discount . diff --git a/thirdparty/discount-2.2.6-patched/gethopt.c b/thirdparty/discount-2.2.6-patched/gethopt.c new file mode 100644 index 00000000..4c6e4ced --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/gethopt.c @@ -0,0 +1,286 @@ +/* + * gehopt; options processing with both single-character and whole-word + * options both introduced with - + */ + +#include +#include + +#include "gethopt.h" + + +void +hoptset(ctx, argc, argv) +struct h_context *ctx; +int argc; +char **argv; +{ + memset(ctx, 0, sizeof *ctx); + ctx->argc = argc; + ctx->argv = argv; + ctx->optind = 1; +} + + +char * +hoptarg(ctx) +struct h_context *ctx; +{ + return ctx->optarg; +} + +int +hoptind(ctx) +struct h_context *ctx; +{ + return ctx->optind; +} + +char +hoptopt(ctx) +struct h_context *ctx; +{ + return ctx->optopt; +} + + +int +hopterr(ctx,val) +struct h_context *ctx; +{ + int old = ctx->opterr; + + ctx->opterr = !!val; + return old; +} + + +struct h_opt * +gethopt(ctx, opts, nropts) +struct h_context *ctx; +struct h_opt *opts; +int nropts; +{ + int i; + int dashes; + + + if ( (ctx == 0) || ctx->optend || (ctx->optind >= ctx->argc) ) + return 0; + + ctx->optarg = 0; + ctx->optopt = 0; + + if ( ctx->optchar == 0) { + /* check for leading - + */ + if ( ctx->argv[ctx->optind][0] != '-' ) { + /* out of arguments */ + ctx->optend = 1; + return 0; + } + + if ( ctx->argv[ctx->optind][1] == 0 + || strcmp(ctx->argv[ctx->optind], "--") == 0 ) { + /* option list finishes with - or -- token + */ + ctx->optend = 1; + ctx->optind++; + return 0; + } + + dashes = 1; + if ( ctx->argv[ctx->optind][dashes] == '-' ) { + /* support GNU-style long option double-dash prefix + * (if gethopt is passed an unknown option with a double-dash + * prefix, it won't match a word and then the second dash + * will be scanned as if it was a regular old single-character + * option.) + */ + dashes = 2; + } + + for ( i=0; i < nropts; i++ ) { + if ( ! opts[i].optword ) + continue; + + if (strcmp(opts[i].optword, dashes+(ctx->argv[ctx->optind]) ) == 0 ) { + if ( opts[i].opthasarg ) { + if ( ctx->argc > ctx->optind ) { + ctx->optarg = ctx->argv[ctx->optind+1]; + ctx->optind += 2; + } + else { + /* word argument with required arg at end of + *command line + */ + if ( ctx->opterr ) + fprintf(stderr, + "%s: option requires an argument -- %s\n", + ctx->argv[0], opts[i].optword); + ctx->optind ++; + return HOPTERR; + } + } + else { + ctx->optind ++; + } + return &opts[i]; + } + } + ctx->optchar = 1; + } + + ctx->optopt = ctx->argv[ctx->optind][ctx->optchar++]; + + if ( !ctx->optopt ) { + /* fell off the end of this argument */ + ctx->optind ++; + ctx->optchar = 0; + return gethopt(ctx, opts, nropts); + } + + for ( i=0; ioptopt ) { + /* found a single-char option! + */ + if ( opts[i].opthasarg ) { + if ( ctx->argv[ctx->optind][ctx->optchar] ) { + /* argument immediately follows this options (-Oc) + */ + ctx->optarg = &ctx->argv[ctx->optind][ctx->optchar]; + ctx->optind ++; + ctx->optchar = 0; + } + else if ( ctx->optind < ctx->argc-1 ) { + /* argument is next arg (-O c) + */ + ctx->optarg = &ctx->argv[ctx->optind+1][0]; + ctx->optind += 2; + ctx->optchar = 0; + } + else { + /* end of arg string (-O); set optarg to null, return + * (should it opterr on me?) + */ + ctx->optarg = 0; + ctx->optind ++; + ctx->optchar = 0; + if ( ctx->opterr ) + fprintf(stderr, + "%s: option requires an argument -- %c\n", + ctx->argv[0], opts[i].optchar); + return HOPTERR; + } + } + else { + if ( !ctx->argv[ctx->optind][ctx->optchar] ) { + ctx->optind ++; + ctx->optchar = 0; + } + } + return &opts[i]; + } + } + if ( ctx->opterr ) + fprintf(stderr, "%s: illegal option -- %c\n", ctx->argv[0], ctx->optopt); + return HOPTERR; +} + + +void +hoptusage(char *pgm, struct h_opt opts[], int nropts, char *arguments) +{ + int i; + int optcount; + + fprintf(stderr, "usage: %s", pgm); + + /* print out the options that don't have flags first */ + + for ( optcount=i=0; i < nropts; i++ ) { + if ( opts[i].optchar && !opts[i].opthasarg) { + if (optcount == 0 ) + fputs(" [-", stderr); + fputc(opts[i].optchar, stderr); + optcount++; + } + } + if ( optcount ) + fputc(']', stderr); + + /* print out the options WITH flags */ + for ( i = 0; i < nropts; i++ ) + if ( opts[i].optchar && opts[i].opthasarg) + fprintf(stderr, " [-%c %s]", opts[i].optchar, opts[i].opthasarg); + + /* print out the long options */ + for ( i = 0; i < nropts; i++ ) + if ( opts[i].optword ) { + fprintf(stderr, " [-%s", opts[i].optword); + if ( opts[i].opthasarg ) + fprintf(stderr, " %s", opts[i].opthasarg); + fputc(']', stderr); + } + + /* print out the arguments string, if any */ + + if ( arguments ) + fprintf(stderr, " %s", arguments); + + /* and we're done */ + fputc('\n', stderr); +} + + +#if DEBUG +struct h_opt opts[] = { + { 0, "css", 0, 1, "css file" }, + { 1, "header", 0, 1, "header file" }, + { 2, 0, 'a', 0, "option a (no arg)" }, + { 3, 0, 'b', 1, "option B (with arg)" }, + { 4, "help", '?', 0, "help message" }, +} ; + +#define NROPT (sizeof opts/sizeof opts[0]) + + +int +main(argc, argv) +char **argv; +{ + struct h_opt *ret; + struct h_context ctx; + int i; + + + hoptset(&ctx, argc, argv); + hopterr(&ctx, 1); + + while (( ret = gethopt(&ctx, opts, NROPT) )) { + + if ( ret != HOPTERR ) { + if ( ret->optword ) + printf("%s", ret->optword); + else + printf("%c", ret->optchar); + + if ( ret->opthasarg ) { + if ( hoptarg(&ctx) ) + printf(" with argument \"%s\"", hoptarg(&ctx)); + else + printf(" with no argument?"); + } + printf(" (%s)\n", ret->optdesc); + } + } + + argc -= hoptind(&ctx); + argv += hoptind(&ctx); + + for ( i=0; i < argc; i++ ) + printf("%d: %s\n", i, argv[i]); + return 0; +} + +#endif /*DEBUG*/ diff --git a/thirdparty/discount-2.2.6-patched/gethopt.h b/thirdparty/discount-2.2.6-patched/gethopt.h new file mode 100644 index 00000000..65817b15 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/gethopt.h @@ -0,0 +1,43 @@ +/* + * gethopt; options processing with both single-character and whole-work + * options both introduced with - + */ + +#ifndef __GETHOPT_D +#define __GETHOPT_D + +#include +#include + + +struct h_opt { + int option; + char *optword; + char optchar; + char *opthasarg; + char *optdesc; +} ; + +#define HOPTERR ((struct h_opt*)-1) + +struct h_context { + char **argv; + int argc; + int optchar; + int optind; + char *optarg; + char optopt; + int opterr:1; + int optend:1; +} ; + +extern char *hoptarg(struct h_context *); +extern int hoptind(struct h_context *); +extern char hoptopt(struct h_context *); +extern void hoptset(struct h_context *, int, char **); +extern int hopterr(struct h_context *, int); +extern struct h_opt *gethopt(struct h_context *, struct h_opt*, int); + +extern void hoptusage(char *, struct h_opt*, int, char *); + +#endif/*__GETHOPT_D*/ diff --git a/thirdparty/discount-2.2.6-patched/github_flavoured.c b/thirdparty/discount-2.2.6-patched/github_flavoured.c new file mode 100644 index 00000000..019f7838 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/github_flavoured.c @@ -0,0 +1,101 @@ + +/* + * github_flavoured -- implement the obnoxious "returns are hard newlines" + * feature in github flavoured markdown. + * + * Copyright (C) 2012 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" + +/* build a Document from any old input. + */ +typedef int (*getc_func)(void*); + +Document * +gfm_populate(getc_func getc, void* ctx, int flags) +{ + Cstring line; + Document *a = __mkd_new_Document(); + int c; + int pandoc = 0; + + if ( !a ) return 0; + + a->tabstop = is_flag_set(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; + } + + if (pandoc == EOF) { + EXPAND(line) = ' '; + EXPAND(line) = ' '; + } + __mkd_enqueue(a, &line); + S(line) = 0; + } + else if ( isprint(c) || isspace(c) || (c & 0x80) ) + EXPAND(line) = c; + } + + if ( S(line) ) + __mkd_enqueue(a, &line); + + DELETE(line); + + if ( (pandoc == 3) && !(is_flag_set(flags, MKD_NOHEADER) + || is_flag_set(flags, 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; __mkd_trim_line(a->title, 1); + a->author= headers->next; __mkd_trim_line(a->author, 1); + a->date = headers->next->next; __mkd_trim_line(a->date, 1); + + T(a->content) = headers->next->next->next; + } + + return a; +} + + +/* convert a block of text into a linked list + */ +Document * +gfm_string(const char *buf, int len, mkd_flag_t flags) +{ + struct string_stream about; + + about.data = buf; + about.size = len; + + return gfm_populate((getc_func)__mkd_io_strget, &about, flags & INPUT_MASK); +} + + +/* convert a file into a linked list + */ +Document * +gfm_in(FILE *f, mkd_flag_t flags) +{ + return gfm_populate((getc_func)fgetc, f, flags & INPUT_MASK); +} diff --git a/thirdparty/discount-2.2.6-patched/h1title.c b/thirdparty/discount-2.2.6-patched/h1title.c new file mode 100644 index 00000000..89fd9d2a --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/h1title.c @@ -0,0 +1,36 @@ +#include +#include "markdown.h" + +static Paragraph * +mkd_h1(Paragraph *p) +{ + Paragraph *found; + + while ( p ) { + if ( p->typ == HDR && p->hnumber == 1 ) + return p; + if ( p->down && (found = mkd_h1(p->down)) ) + return found; + p = p->next; + } + return 0; +} + +char * +mkd_h1_title(Document *doc, int flags) +{ + Paragraph *title; + + if (doc && (title = mkd_h1(doc->code)) ) { + char *generated; + int size; + + /* assert that a H1 header is one line long, so that's + * the only thing needed + */ + size = mkd_line(T(title->text->text), + S(title->text->text), &generated, flags|MKD_TAGTEXT); + if ( size ) return generated; + } + return 0; +} diff --git a/thirdparty/discount-2.2.6-patched/html5.c b/thirdparty/discount-2.2.6-patched/html5.c new file mode 100644 index 00000000..870589c8 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/html5.c @@ -0,0 +1,21 @@ +/* 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("NAV", 0); + mkd_define_tag("SECTION", 0); + mkd_define_tag("ARTICLE", 0); + + mkd_sort_tags(); +} diff --git a/thirdparty/discount-2.2.6-patched/libmarkdown.pc.in b/thirdparty/discount-2.2.6-patched/libmarkdown.pc.in new file mode 100644 index 00000000..1d1082ee --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/libmarkdown.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@prefix@ +libdir=@libdir@ +includedir=@prefix@/include + +Name: @PACKAGE_NAME@ +Version: @PACKAGE_VERSION@ +Description: C implementation of John Gruber's Markdown markup language + +Libs: -L${libdir} -lmarkdown @LIBS@ +Cflags: -I${includedir} diff --git a/thirdparty/discount-2.2.6-patched/main.c b/thirdparty/discount-2.2.6-patched/main.c new file mode 100644 index 00000000..65985f22 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/main.c @@ -0,0 +1,338 @@ +/* + * markdown: convert a single markdown document into html + */ +/* + * 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 +#include + +#include "config.h" +#include "amalloc.h" +#include "pgm_options.h" +#include "tags.h" +#include "gethopt.h" + +#if HAVE_LIBGEN_H +#include +#endif + +#ifndef HAVE_BASENAME +#include + +char* +basename(char *p) +{ + char *ret = strrchr(p, '/'); + + return ret ? (1+ret) : p; +} +#endif + + +char *pgm = "markdown"; + +char * +e_flags(const char *text, const int size, void *context) +{ + return (char*)context; +} + + +void +complain(char *fmt, ...) +{ + va_list ptr; + + fprintf(stderr, "%s: ", pgm); + va_start(ptr, fmt); + vfprintf(stderr, fmt, ptr); + va_end(ptr); + fputc('\n', stderr); + fflush(stderr); +} + + +char * +anchor_format(char *input, void *ctx) +{ + int i, j, size; + char* ret; + + if ( !input ) + return NULL; + + size = strlen(input); + + ret = malloc(1+size); + + if ( !ret ) + return NULL; + + + while ( size && isspace(input[size-1]) ) + --size; + + for ( j=i=0; i < size; i++ ) { + if (isalnum(input[i]) || strchr("-_+", input[i]) ) + ret[j++] = input[i]; + else if ( input[i] == ' ' ) + ret[j++] = '-'; + } + ret[j++] = 0; + + return ret; +} + +void +free_it(char *object, void *ctx) +{ + if ( object ) + free(object); +} + +char * +external_codefmt(char *src, int len, char *lang) +{ + int extra = 0; + int i, x; + char *res; + + if ( lang == 0 ) + lang = "generic_code"; + + for ( i=0; i < len; i++) { + if ( src[i] == '&' ) + extra += 5; + else if ( src[i] == '<' || src[i] == '>' ) + extra += 4; + } + + /* 80 characters for the format wrappers */ + if ( (res = malloc(len+extra+80+strlen(lang))) ==0 ) + /* out of memory? drat! */ + return 0; + + sprintf(res, "
\n", lang);
+    x = strlen(res);
+    for ( i=0; i < len; i++ ) {
+	switch (src[i]) {
+	case '&':   strcpy(&src[x], "&");
+		    x += 5 /*strlen(&)*/ ;
+		    break;
+	case '<':   strcpy(&src[x], "<");
+		    x += 4 /*strlen(<)*/ ;
+		    break;
+	case '>':   strcpy(&src[x], ">");
+		    x += 4 /*strlen(>)*/ ;
+		    break;
+	default:    res[x++] = src[i];
+		    break;
+	}
+    }
+    strcpy(&res[x], "
\n"); + return res; +} + + +struct h_opt opts[] = { + { 0, "html5", '5', 0, "recognise html5 block elements" }, + { 0, "base", 'b', "url-base", "URL prefix" }, + { 0, "debug", 'd', 0, "debugging" }, + { 0, "version",'V', 0, "show version info" }, + { 0, 0, 'E', "flags", "url flags" }, + { 0, 0, 'F', "bitmap", "set/show hex flags" }, + { 0, 0, 'f', "{+-}flags", "set/show named flags" }, + { 0, 0, 'G', 0, "github flavoured markdown" }, + { 0, 0, 'n', 0, "don't write generated html" }, + { 0, 0, 's', "text", "format `text`" }, + { 0, "style", 'S', 0, "output +at the end of the line or a +.Em +at the beginning of a subsequent line. +.Pp +Be warned that style blocks work like footnote links -- no matter +where you define them they are valid for the entire document. +.Ss alpha lists +Alphabetic lists (like regular numeric lists, but with alphabetic +items) are supported. So: +.nf + a. this + b. is + c. an alphabetic + d. list +.fi +will produce: +.nf +
    +
  1. this
  2. +
  3. is
  4. +
  5. an alphabetic
  6. +
  7. list
  8. +
+.fi +.Ss tables +.Ar "PHP Markdown Extra" +tables are supported; input of the form +.nf + header|header + ------|------ + text | text +.fi +will produce: +.nf + + + + + + + + + + + + + +
headerheader
texttext
+.fi +The dashed line can also contain +.Em : +characters for formatting; if a +.Em : +is at the start of a column, it tells +.Nm discount +to align the cell contents to the left; if it's at the end, it +aligns right, and if there's one at the start and at the +end, it centers. +.Ss strikethrough +A strikethrough syntax is supported in much the same way that +.Ar ` +is used to define a section of code. If you enclose text with +two or more tildes, such as +.Em ~~erased text~~ +it will be written as +.Em "erased text" . +Like code sections, you may use as many +.Ar ~ +as you want, but there must be as many starting tildes as closing +tildes. +.Ss markdown extra-style footnotes +.Ar "PHP Markdown Extra" +footnotes are supported. If a footnote link begins with a +.Ar ^ , +the first use of that footnote will generate a link down to the +bottom of the rendered document, which will contain a numbered footnote +with a link back to where the footnote was called. +.Sh AUTHOR +David Parsons +.%T http://www.pell.portland.or.us/~orc/ +.Sh SEE ALSO +.Xr markdown 1 , +.Xr markdown 3 , +.Xr mkd-callbacks 3 , +.Xr mkd-functions 3 , +.Xr mkd-line 3 . +.Pp +.%T http://daringfireball.net/projects/markdown +.Pp +.%T http://michelf.com/projects/php-markdown diff --git a/thirdparty/discount-2.2.6-patched/mkd-functions.3 b/thirdparty/discount-2.2.6-patched/mkd-functions.3 new file mode 100644 index 00000000..d4bc9eb9 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/mkd-functions.3 @@ -0,0 +1,186 @@ +.\" +.Dd January 18, 2008 +.Dt MKD_FUNCTIONS 3 +.Os Mastodon +.Sh NAME +.Nm mkd_functions +.Nd access and process Markdown documents. +.Sh LIBRARY +Markdown +.Pq libmarkdown , -lmarkdown +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn mkd_compile "MMIOT *document" "int flags" +.Ft int +.Fn mkd_css "MMIOT *document" "char **doc" +.Ft int +.Fn mkd_generatecss "MMIOT *document" "FILE *output" +.Ft int +.Fn mkd_document "MMIOT *document" "char **doc" +.Ft int +.Fn mkd_generatehtml "MMIOT *document" "FILE *output" +.Ft int +.Fn mkd_xhtmlpage "MMIOT *document" "int flags" "FILE *output" +.Ft int +.Fn mkd_toc "MMIOT *document" "char **doc" +.Ft void +.Fn mkd_generatetoc "MMIOT *document" "FILE *output" +.Ft void +.Fn mkd_cleanup "MMIOT*" +.Ft char* +.Fn mkd_doc_title "MMIOT*" +.Ft char* +.Fn mkd_doc_author "MMIOT*" +.Ft char* +.Fn mkd_doc_date "MMIOT*" +.Sh DESCRIPTION +.Pp +The +.Nm markdown +format supported in this implementation includes +Pandoc-style header and inline +.Ar \ +blocks, and the standard +.Xr markdown 3 +functions do not provide access to +the data provided by either of those extensions. +These functions give you access to that data, plus +they provide a finer-grained way of converting +.Em Markdown +documents into HTML. +.Pp +Given a +.Ar MMIOT* +generated by +.Fn mkd_in +or +.Fn mkd_string , +.Fn mkd_compile +compiles the document into +.Em \ , +.Em Pandoc , +and +.Em html +sections. +.Pp +Once compiled, the document can be examined and written +by the +.Fn mkd_css , +.Fn mkd_document , +.Fn mkd_generatecss , +.Fn mkd_generatehtml , +.Fn mkd_generatetoc , +.Fn mkd_toc , +.Fn mkd_xhtmlpage , +.Fn mkd_doc_title , +.Fn mkd_doc_author , +and +.Fn mkd_doc_date +functions. +.Pp +.Fn mkd_css +allocates a string and populates it with any \ sections +provided in the document, +.Fn mkd_generatecss +writes any \ sections to the output, +.Fn mkd_document +points +.Ar text +to the text of the document and returns the +size of the document, +.Fn mkd_generatehtml +writes the rest of the document to the output, +and +.Fn mkd_doc_title , +.Fn mkd_doc_author , +.Fn mkd_doc_date +are used to read the contents of a Pandoc header, +if any. +.Pp +.Fn mkd_xhtmlpage +writes a xhtml page containing the document. The regular set of +flags can be passed. +.Pp +.Fn mkd_toc +writes a document outline, in the form of a collection of nested +lists with links to each header in the document, into a string +allocated with +.Fn malloc , +and returns the size. +.Pp +.Fn mkd_generatetoc +is like +.Fn mkd_toc , +except that it writes the document outline to the given +.Pa FILE* +argument. +.Pp +.Fn mkd_cleanup +deletes a +.Ar MMIOT* +after processing is done. +.Pp +.Fn mkd_compile +accepts the same flags that +.Fn markdown +and +.Fn mkd_string +do; +.Bl -tag -width MKD_NOSTRIKETHROUGH -compact +.It Ar MKD_NOIMAGE +Do not process `![]' and +remove +.Em \ +tags from the output. +.It Ar MKD_NOLINKS +Do not process `[]' and remove +.Em \ +tags from the output. +.It Ar MKD_NOPANTS +Do not do Smartypants-style mangling of quotes, dashes, or ellipses. +.It Ar MKD_TAGTEXT +Process the input as if you were inside a html tag. This means that +no html tags will be generated, and +.Fn mkd_compile +will attempt to escape anything that might terribly confuse a +web browser. +.It Ar MKD_NO_EXT +Do not process any markdown pseudo-protocols when +handing +.Ar [][] +links. +.It Ar MKD_NOHEADER +Do not attempt to parse any Pandoc-style headers. +.It Ar MKD_TOC +Label all headers for use with the +.Fn mkd_generatetoc +function. +.It Ar MKD_1_COMPAT +MarkdownTest_1.0 compatibility flag; trim trailing spaces from the +first line of code blocks and disable implicit reference links. +.It Ar MKD_NOSTRIKETHROUGH +Disable strikethrough support. +.El +.Sh RETURN VALUES +The function +.Fn mkd_compile +returns 1 in the case of success, or 0 if the document is already compiled. +The function +.Fn mkd_generatecss +returns the number of bytes written in the case of success, or EOF if an error +occurred. +The function +.Fn mkd_generatehtml +returns 0 on success, \-1 on failure. +.Sh SEE ALSO +.Xr markdown 1 , +.Xr markdown 3 , +.Xr mkd-line 3 , +.Xr markdown 7 , +.Xr mkd-extensions 7 , +.Xr mmap 2 . +.Pp +http://daringfireball.net/projects/markdown/syntax +.Sh BUGS +Error handling is minimal at best. diff --git a/thirdparty/discount-2.2.6-patched/mkd-line.3 b/thirdparty/discount-2.2.6-patched/mkd-line.3 new file mode 100644 index 00000000..7a354462 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/mkd-line.3 @@ -0,0 +1,41 @@ +.\" +.Dd January 18, 2008 +.Dt MKD_LINE 3 +.Os Mastodon +.Sh NAME +.Nm mkd_line +.Nd do Markdown translation of small items +.Sh LIBRARY +Markdown +.Pq libmarkdown , -lmarkdown +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn mkd_line "char *string" "int size" "char **doc" "int flags" +.Ft int +.Fn mkd_generateline "char *string" "int size" "FILE *output" "int flags" +.Sh DESCRIPTION +.Pp +Occasionally one might want to do markdown translations on fragments of +data, like the title of an weblog article, a date, or a simple signature +line. +.Nm mkd_line +and +.Nm mkd_generateline +allow you to do markdown translations on small blocks of text. +.Nm mkd_line +allocates a buffer, then writes the translated text into that buffer, +and +.Nm mkd_generateline +writes the output to the specified +.Ar FILE* . +.Sh SEE ALSO +.Xr markdown 1 , +.Xr markdown 3 , +.Xr markdown 7 , +.Xr mkd-extensions 7 , +.Xr mmap 2 . +.Pp +http://daringfireball.net/projects/markdown/syntax +.Sh BUGS +Error handling is minimal at best. diff --git a/thirdparty/discount-2.2.6-patched/mkd2html.1 b/thirdparty/discount-2.2.6-patched/mkd2html.1 new file mode 100644 index 00000000..3094b203 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/mkd2html.1 @@ -0,0 +1,52 @@ +.\" %A% +.\" +.Dd January 10, 2010 +.Dt MKD2HTML 1 +.Os MASTODON +.Sh NAME +.Nm mkd2html +.Nd markdown to html converter +.Sh SYNOPSIS +.Nm +.Op Fl css Pa file +.Op Fl header Pa string +.Op Fl footer Pa string +.Op Pa file +.Sh DESCRIPTION +.Nm +utility parses a +.Xr markdown 7 Ns -formatted +.Pa textfile +.Pq or stdin if not specified, +and generates a web page. It +reads +.Ar file +or +.Ar file.text + and writes the result in +.Ar file.html +.Pq where file is the passed argument. +.Pp +.Nm +is part of discount. +.Sh OPTIONS +.Bl -tag -width "-header string" +.It Fl css Ar file +Specifies a CSS file. +.It Fl header Ar string +Specifies a line to add to the
tag. +.It Fl footer Ar string +Specifies a line to add before the <\/body> tag. +.El +.Sh RETURN VALUES +The +.Nm +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Xr markdown 1 , +.Xr markdown 3 , +.Xr markdown 7 , +.Xr mkd-extensions 7 . +.Sh AUTHOR +.An David Parsons +.Pq Li orc@pell.portland.or.us diff --git a/thirdparty/discount-2.2.6-patched/mkd2html.c b/thirdparty/discount-2.2.6-patched/mkd2html.c new file mode 100644 index 00000000..cbe2b7a3 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/mkd2html.c @@ -0,0 +1,236 @@ +/* + * mkd2html: parse a markdown input file and generate a web page. + * + * usage: mkd2html [options] filename + * or mkd2html [options] < markdown > html + * + * options + * -css css-file + * -header line-to-add-to-
+ * -footer line-to-add-before- + * + * example: + * + * mkd2html -css /~orc/pages.css syntax + * ( read syntax OR syntax.text, write syntax.html ) + */ +/* + * 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 +#ifdef HAVE_BASENAME +# ifdef HAVE_LIBGEN_H +# include +# else +# include +# endif +#endif +#include + +#include "mkdio.h" +#include "cstring.h" +#include "amalloc.h" + +#include "gethopt.h" + +char *pgm = "mkd2html"; + +extern int notspecial(char *filename); + +#ifndef HAVE_BASENAME +char * +basename(char *path) +{ + char *p; + + if ( p = strrchr(path, '/') ) + return 1+p; + return path; +} +#endif + +void +fail(char *why, ...) +{ + va_list ptr; + + va_start(ptr,why); + fprintf(stderr, "%s: ", pgm); + vfprintf(stderr, why, ptr); + fputc('\n', stderr); + va_end(ptr); + exit(1); +} + + +enum { GFM, ADD_CSS, ADD_HEADER, ADD_FOOTER }; + +struct h_opt opts[] = { + { GFM, "gfm",'G', 0, "Github style markdown" }, + { ADD_CSS, "css", 0, "url", "Additional css for this page" }, + { ADD_HEADER, "header", 0, "header", "Additonal headers for this page" }, + { ADD_FOOTER, "footer", 0, "footer", "Additional footers for this page" }, +}; +#define NROPTS (sizeof opts/sizeof opts[0]) + +#if USE_H1TITLE +extern char* mkd_h1_title(MMIOT *); +#endif + + +int +main(argc, argv) +char **argv; +{ + char *h; + char *source = 0, *dest = 0; + MMIOT *mmiot; + int i; + int gfm = 0; + FILE *input, *output; + STRING(char*) css, headers, footers; + struct h_opt *res; + struct h_context flags; + + + CREATE(css); + CREATE(headers); + CREATE(footers); + pgm = basename(argv[0]); + + hoptset(&flags, argc, argv); + hopterr(&flags, 1); + while ( res = gethopt(&flags, opts, NROPTS) ) { + if ( res == HOPTERR ) { + hoptusage(pgm, opts, NROPTS, "source [dest]"); + exit(1); + } + + switch ( res->option ) { + case ADD_CSS: + EXPAND(css) = hoptarg(&flags); + break; + case ADD_HEADER: + EXPAND(headers) = hoptarg(&flags); + break; + case ADD_FOOTER: + EXPAND(footers) = hoptarg(&flags); + break; + case GFM: + gfm = 1; + break; + default: + fprintf(stderr, "unknown option?\n"); + break; + } + } + + argc -= hoptind(&flags); + argv += hoptind(&flags); + + switch ( argc ) { + char *p, *dot; + case 0: + input = stdin; + output = stdout; + break; + + case 1: + case 2: + dest = malloc(strlen(argv[argc-1]) + 6); + source = malloc(strlen(argv[0]) + 6); + + if ( !(source && dest) ) + fail("out of memory allocating name buffers"); + + strcpy(source, argv[0]); + strcpy(dest, argv[argc-1]); + if (( p = strrchr(source, '/') )) + p = source; + else + ++p; + + if ( (input = fopen(source, "r")) == 0 ) { + strcat(source, ".text"); + if ( (input = fopen(source, "r")) == 0 ) + fail("can't open either %s or %s", argv[0], source); + } + + if ( notspecial(dest) ) { + if (( dot = strrchr(dest, '.') )) + *dot = 0; + strcat(dest, ".html"); + } + + if ( (output = fopen(dest, "w")) == 0 ) + fail("can't write to %s", dest); + break; + + default: + hoptusage(pgm, opts, NROPTS, "source [dest]"); + exit(1); + } + + mmiot = gfm ? gfm_in(input, 0) : mkd_in(input, 0); + + if ( mmiot == 0 ) + fail("can't read %s", source ? source : "stdin"); + + if ( !mkd_compile(mmiot, 0) ) + fail("couldn't compile input"); + + + h = mkd_doc_title(mmiot); +#if USE_H1TITLE + if ( ! h ) + h = mkd_h1_title(mmiot); +#endif + + /* print a header */ + + fprintf(output, + "\n" + "\n" + "\n" + " \n", markdown_version); + + fprintf(output," \n"); + + for ( i=0; i < S(css); i++ ) + fprintf(output, " \n", T(css)[i]); + + fprintf(output," "); + if ( h ) + mkd_generateline(h, strlen(h), output, 0); + /* xhtml requires a <title> in the header, even if it doesn't + * contain anything + */ + fprintf(output, "\n"); + + for ( i=0; i < S(headers); i++ ) + fprintf(output, " %s\n", T(headers)[i]); + fprintf(output, "\n" + "\n"); + + /* print the compiled body */ + + mkd_generatehtml(mmiot, output); + + for ( i=0; i < S(footers); i++ ) + fprintf(output, "%s\n", T(footers)[i]); + + fprintf(output, "\n" + "\n"); + + mkd_cleanup(mmiot); + exit(0); +} diff --git a/thirdparty/discount-2.2.6-patched/mkdio.c b/thirdparty/discount-2.2.6-patched/mkdio.c new file mode 100644 index 00000000..78e18fe8 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/mkdio.c @@ -0,0 +1,457 @@ +/* + * 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 + */ +Document* +__mkd_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. + */ +void +__mkd_enqueue(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 characters from a line, then adjust the dle. + */ +void +__mkd_trim_line(Line *p, int clip) +{ + if ( clip >= S(p->text) ) { + S(p->text) = p->dle = 0; + T(p->text)[0] = 0; + } + else if ( clip > 0 ) { + CLIP(p->text, 0, clip); + p->dle = mkd_firstnonblank(p); + } +} + + +/* build a Document from any old input. + */ +typedef int (*getc_func)(void*); + +Document * +populate(getc_func getc, void* ctx, mkd_flag_t flags) +{ + Cstring line; + Document *a = __mkd_new_Document(); + int c; + int pandoc = 0; + + if ( !a ) return 0; + + a->tabstop = is_flag_set(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; + } + __mkd_enqueue(a, &line); + S(line) = 0; + } + else if ( isprint(c) || isspace(c) || (c & 0x80) ) + EXPAND(line) = c; + } + + if ( S(line) ) + __mkd_enqueue(a, &line); + + DELETE(line); + + if ( (pandoc == 3) && !(is_flag_set(flags, MKD_NOHEADER) || is_flag_set(flags, 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; __mkd_trim_line(a->title, 1); + a->author= headers->next; __mkd_trim_line(a->author, 1); + a->date = headers->next->next; __mkd_trim_line(a->date, 1); + + T(a->content) = headers->next->next->next; + } + + return a; +} + + +/* convert a file into a linked list + */ +Document * +mkd_in(FILE *f, mkd_flag_t flags) +{ + return populate((getc_func)fgetc, f, flags & INPUT_MASK); +} + + +/* return a single character out of a buffer + */ +int +__mkd_io_strget(struct string_stream *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, mkd_flag_t flags) +{ + struct string_stream about; + + about.data = buf; + about.size = len; + + return populate((getc_func)__mkd_io_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; + + DO_OR_DIE( szdoc = mkd_document(p,&doc) ); + if ( is_flag_set(p->ctx->flags, MKD_CDATA) ) + DO_OR_DIE( mkd_generatexml(doc, szdoc, output) ); + else if ( fwrite(doc, szdoc, 1, output) != 1 ) + return EOF; + DO_OR_DIE( putc('\n', output) ); + return 0; +} + + +/* convert some markdown text to html + */ +int +markdown(Document *document, FILE *out, mkd_flag_t flags) +{ + if ( mkd_compile(document, flags) ) { + mkd_generatehtml(document, out); + mkd_cleanup(document); + return 0; + } + return -1; +} + + +/* anchor_format a string, returning the formatted string in malloc()ed space + * MKD_URLENCODEDANCHOR is now perverted to being a html5 anchor + * + * !labelformat: print all characters + * labelformat && h4anchor: prefix nonalpha label with L, + * expand all nonalnum, _, ':', '.' to hex + * except space which maps to - + * labelformat && !h4anchor:expand space to -, other isspace() & '%' to hex + */ +static char * +mkd_anchor_format(char *s, int len, int labelformat, mkd_flag_t flags) +{ + char *res; + unsigned char c; + int i, needed, out = 0; + int h4anchor = !is_flag_set(flags, MKD_URLENCODEDANCHOR); + static const unsigned char hexchars[] = "0123456789abcdef"; + + needed = labelformat ? (4*len) : len; + + if ( (res = malloc(needed)) == NULL ) + return NULL; + + if ( h4anchor && labelformat && !isalpha(s[0]) ) + res[out++] = 'L'; + + + for ( i=0; i < len ; i++ ) { + c = s[i]; + if ( labelformat ) { + if ( h4anchor + ? (isalnum(c) || (c == '_') || (c == ':') || (c == '.' ) ) + : !(isspace(c) || c == '%') ) + res[out++] = c; + else if ( c == ' ' ) + res[out++] = '-'; + else { + res[out++] = h4anchor ? '-' : '%'; + res[out++] = hexchars[c >> 4 & 0xf]; + res[out++] = hexchars[c & 0xf]; + if ( h4anchor ) + res[out++] = '-'; + } + } + else + res[out++] = c; + } + + res[out++] = 0; + return res; +} /* mkd_anchor_format */ + + +/* write out a Cstring, mangled into a form suitable for `cb->e_anchor ) + res = (*(f->cb->e_anchor))(line, size, f->cb->e_data); + else + res = mkd_anchor_format(line, size, labelformat, f->flags); + + free(line); + + if ( !res ) + return; + + for ( i=0; res[i]; i++ ) + (*outchar)(res[i], out); + + if ( f->cb->e_anchor ) { + if ( f->cb->e_free ) + (*(f->cb->e_free))(res, f->cb->e_data); + } + else + free(res); +} + + +/* ___mkd_reparse() a line + */ +static void +mkd_parse_line(char *bfr, int size, MMIOT *f, mkd_flag_t flags) +{ + ___mkd_initmmiot(f, 0); + f->flags = flags & USER_FLAGS; + ___mkd_reparse(bfr, size, 0, f, 0); + ___mkd_emblock(f); +} + + +/* ___mkd_reparse() a line, returning it in malloc()ed memory + */ +int +mkd_line(char *bfr, int size, char **res, mkd_flag_t flags) +{ + MMIOT f; + int len; + + mkd_parse_line(bfr, size, &f, flags); + + if ( len = S(f.out) ) { + EXPAND(f.out) = 0; + /* strdup() doesn't use amalloc(), so in an amalloc()ed + * build this copies the string safely out of our memory + * paranoia arena. In a non-amalloc world, it's a spurious + * memory allocation, but it avoids unintentional hilarity + * with amalloc() + */ + *res = strdup(T(f.out)); + } + 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, mkd_flag_t flags) +{ + MMIOT f; + int status; + + mkd_parse_line(bfr, size, &f, flags); + if ( is_flag_set(flags, MKD_CDATA) ) + status = mkd_generatexml(T(f.out), S(f.out), output) != EOF; + else + status = fwrite(T(f.out), S(f.out), 1, output) == S(f.out); + + ___mkd_freemmiot(&f, 0); + return status ? 0 : EOF; +} + + +/* set the url display callback + */ +void +mkd_e_url(Document *f, mkd_callback_t edit) +{ + if ( f ) { + if ( f->cb.e_url != edit ) + f->dirty = 1; + f->cb.e_url = edit; + } +} + + +/* set the url options callback + */ +void +mkd_e_flags(Document *f, mkd_callback_t edit) +{ + if ( f ) { + if ( f->cb.e_flags != edit ) + f->dirty = 1; + f->cb.e_flags = edit; + } +} + + +/* set the anchor formatter + */ +void +mkd_e_anchor(Document *f, mkd_callback_t format) +{ + if ( f ) { + if ( f->cb.e_anchor != format ) + f->dirty = 1; + f->cb.e_anchor = format; + } +} + + +/* set the url display/options deallocator + */ +void +mkd_e_free(Document *f, mkd_free_t dealloc) +{ + if ( f ) { + if ( f->cb.e_free != dealloc ) + f->dirty = 1; + f->cb.e_free = dealloc; + } +} + + +/* set the url display/options context data field + */ +void +mkd_e_data(Document *f, void *data) +{ + if ( f ) { + if ( f->cb.e_data != data ) + f->dirty = 1; + f->cb.e_data = data; + } +} + + +/* set the code block display callback + */ +void +mkd_e_code_format(Document *f, mkd_callback_t codefmt) +{ + if ( f && (f->cb.e_codefmt != codefmt) ) { + f->dirty = 1; + f->cb.e_codefmt = codefmt; + } +} + + +/* set the href prefix for markdown extra style footnotes + */ +void +mkd_ref_prefix(Document *f, char *data) +{ + if ( f ) { + if ( f->ref_prefix != data ) + f->dirty = 1; + f->ref_prefix = data; + } +} diff --git a/thirdparty/discount-2.2.6-patched/mkdio.h.in b/thirdparty/discount-2.2.6-patched/mkdio.h.in new file mode 100644 index 00000000..efed17f9 --- /dev/null +++ b/thirdparty/discount-2.2.6-patched/mkdio.h.in @@ -0,0 +1,127 @@ +#ifndef _MKDIO_D +#define _MKDIO_D + +#include + +@SCALAR_HEADER_INCLUDE@ + +typedef void MMIOT; + +typedef @DWORD@ 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 */ + +/* line builder for github flavoured markdown + */ +MMIOT *gfm_in(FILE*,mkd_flag_t); /* assemble input from a file */ +MMIOT *gfm_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); +void mkd_cleanup(MMIOT*); + +/* markup functions + */ +int mkd_dump(MMIOT*, FILE*, mkd_flag_t, char*); +int markdown(MMIOT*, FILE*, mkd_flag_t); +int mkd_line(char *, int, char **, mkd_flag_t); +int mkd_xhtmlpage(MMIOT*,mkd_flag_t,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 **); +int mkd_latextext(MMIOT*, 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_anchor(void *, mkd_callback_t); +void mkd_e_code_format(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_NOSTYLE 0x00400000 /* don't extract ' '' + +ASK='' + +try 'multiple lines' "$ASK" '' + +try 'unclosed' '