├── discount ├── VERSION ├── config.h ├── tests │ ├── chrome.text │ ├── embedlinks.text │ ├── links.text │ ├── style.t │ ├── linkypix.t │ ├── reparse.t │ ├── para.t │ ├── footnotes.t │ ├── toc.t │ ├── paranoia.t │ ├── misc.t │ ├── backslash.t │ ├── code.t │ ├── snakepit.t │ ├── flow.t │ ├── crash.t │ ├── pseudo.t │ ├── compat.t │ ├── tabstop.t │ ├── emphasis.t │ ├── header.t │ ├── autolink.t │ ├── xml.t │ ├── peculiarities.t │ ├── dl.t │ ├── list3deep.t │ ├── pandoc.t │ ├── div.t │ ├── smarty.t │ ├── automatic.t │ ├── html.t │ ├── tables.t │ ├── list.t │ ├── linkylinky.t │ └── schiraldi.t ├── tools │ ├── echo.c │ └── cols.c ├── version.c.in ├── makepage.c ├── amalloc.h ├── README ├── Plan9 │ ├── mkfile │ ├── README │ ├── markdown.1 │ ├── markdown.2 │ └── markdown.6 ├── docheader.c ├── mkd-line.3 ├── Csio.c ├── xmlpage.c ├── CREDITS ├── css.c ├── INSTALL ├── xml.c ├── COPYRIGHT ├── toc.c ├── amalloc.c ├── cstring.h ├── mkdio.h ├── Makefile.in ├── markdown.1.in ├── markdown.3 ├── theme.1 ├── resource.c ├── dumptree.c ├── configure.sh ├── mkd2html.c ├── mkd-extensions.7 ├── mkd-functions.3 ├── main.c ├── markdown.h ├── mkdio.c ├── theme.c └── markdown.c ├── README.md ├── Rakefile ├── compile.sh └── down.ooc /discount/VERSION: -------------------------------------------------------------------------------- 1 | 1.5.5 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Run it: 2 | 3 | ./compile.sh 4 | ./down 5 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | task :default do 2 | if system("./compile.sh") 3 | exec "./down" 4 | else 5 | puts :fail 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /discount/config.h: -------------------------------------------------------------------------------- 1 | 2 | /* rdiscount extension configuration */ 3 | 4 | #undef USE_AMALLOC 5 | 6 | #define TABSTOP 4 7 | #define COINTOSS() (random()&1) 8 | #define INITRNG(x) srandom((unsigned int)x) 9 | #define RELAXED_EMPHASIS 1 10 | -------------------------------------------------------------------------------- /discount/tests/chrome.text: -------------------------------------------------------------------------------- 1 | ->###chrome with my markdown###<- 2 | 3 | 1. `(c)` -> `©` (c) 4 | 2. `(r)` -> `®` (r) 5 | 3. `(tm)` -> `™` (tm) 6 | 4. `...` -> `…` ... 7 | 5. `--` -> `&emdash;` -- 8 | 6. `-` -> `–` - (but not if it's between-words) 9 | 7. "fancy quoting" 10 | 8. 'fancy quoting (#2)' 11 | 9. don't do it unless it's a real quote. 12 | 10. `` (`) `` 13 | 14 | -------------------------------------------------------------------------------- /discount/tests/embedlinks.text: -------------------------------------------------------------------------------- 1 | * [![an image](http://dustmite.org/mite.jpg =50x50)] (http://dustmite.org) 2 | * [[an embedded link](http://wontwork.org)](http://willwork.org) 3 | * [![dustmite][]] (http:/dustmite.org) 4 | * ![dustmite][] 5 | * ![dustmite][dustmite] 6 | * [cheat me](http://I.am.cheating) 7 | 8 | [dustmite]: http://dustmite.org/mite.jpg =25x25 "here I am!" 9 | 10 | -------------------------------------------------------------------------------- /discount/tests/links.text: -------------------------------------------------------------------------------- 1 | 1. 2 | 2. [automatic] (http://automatic "automatic link") 3 | 3. [automatic](http://automatic "automatic link") 4 | 4. [automatic](http://automatic) 5 | 5. [automatic] (http://automatic) 6 | 6. [automatic] [] 7 | 7. [automatic][] 8 | 8. [my][automatic] 9 | 9. [my] [automatic] 10 | 11 | [automatic]: http://automatic "footnote" 12 | 13 | 14 | [automatic] [ 15 | -------------------------------------------------------------------------------- /discount/tools/echo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | main(argc, argv) 6 | char **argv; 7 | { 8 | int nl = 1; 9 | int i; 10 | 11 | if ( (argc > 1) && (strcmp(argv[1], "-n") == 0) ) { 12 | ++argv; 13 | --argc; 14 | nl = 0; 15 | } 16 | 17 | for ( i=1; i < argc; i++ ) { 18 | if ( i > 1 ) putchar(' '); 19 | fputs(argv[i], stdout); 20 | } 21 | if (nl) putchar('\n'); 22 | } 23 | -------------------------------------------------------------------------------- /compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ooc down.ooc -onlygen 3 | gcc -std=c99 -Wall -Idiscount -I/Users/chris/Projects/ooc/libs/headers -Iooc_tmp ooc_tmp/down/down.c ooc_tmp/sdk/lang/BasicTypes.c ooc_tmp/sdk/lang/ooclib.c ooc_tmp/sdk/lang/stdio.c discount/Csio.c discount/docheader.c discount/dumptree.c discount/generate.c discount/markdown.c discount/mkdio.c discount/resource.c discount/toc.c discount/xml.c -o down -lpthread /Users/chris/Projects/ooc/libs/osx64/libgc.a 4 | echo ok 5 | -------------------------------------------------------------------------------- /discount/version.c.in: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | char markdown_version[] = VERSION 4 | #if DL_TAG_EXTENSION 5 | " DL_TAG" 6 | #endif 7 | #if PANDOC_HEADER 8 | " HEADER" 9 | #endif 10 | #if @TABSTOP@ != 4 11 | " TAB=@TABSTOP@" 12 | #endif 13 | #if USE_AMALLOC 14 | " DEBUG" 15 | #endif 16 | #if SUPERSCRIPT 17 | " SUPERSCRIPT" 18 | #endif 19 | #if RELAXED_EMPHASIS 20 | " RELAXED" 21 | #endif 22 | #if DIV_QUOTE 23 | " DIV" 24 | #endif 25 | #if ALPHA_LIST 26 | " AL" 27 | #endif 28 | ; 29 | -------------------------------------------------------------------------------- /discount/makepage.c: -------------------------------------------------------------------------------- 1 | /* 2 | * makepage: Use mkd_xhtmlpage() to convert markdown input to a 3 | * fully-formed xhtml page. 4 | */ 5 | #include 6 | #include 7 | #include 8 | 9 | float 10 | main(argc, argv) 11 | int argc; 12 | char **argv; 13 | { 14 | MMIOT *doc; 15 | 16 | if ( (argc > 1) && !freopen(argv[1], "r", stdin) ) { 17 | perror(argv[1]); 18 | exit(1); 19 | } 20 | 21 | if ( (doc = mkd_in(stdin, 0)) == 0 ) { 22 | perror( (argc > 1) ? argv[1] : "stdin" ); 23 | exit(1); 24 | } 25 | 26 | exit(mkd_xhtmlpage(doc, 0, stdout)); 27 | } 28 | -------------------------------------------------------------------------------- /discount/tests/style.t: -------------------------------------------------------------------------------- 1 | ./echo "styles" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | ./echo -n ' ' | ./markdown|wc -c` 9 | 10 | if [ $count -eq 1 ]; then 11 | ./echo "ok" 12 | else 13 | ./echo "FAILED" 14 | rc=1 15 | fi 16 | 17 | ./echo -n ' ' 22 | 23 | count=`./echo "$ASK" | ./markdown | wc -c` 24 | 25 | if [ $count -eq 1 ]; then 26 | ./echo "ok" 27 | else 28 | ./echo "FAILED" 29 | rc=1 30 | fi 31 | 32 | exit $rc 33 | -------------------------------------------------------------------------------- /discount/amalloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * debugging malloc()/realloc()/calloc()/free() that attempts 3 | * to keep track of just what's been allocated today. 4 | */ 5 | #ifndef AMALLOC_D 6 | #define AMALLOC_D 7 | 8 | #include "config.h" 9 | 10 | #ifdef USE_AMALLOC 11 | 12 | extern void *amalloc(int); 13 | extern void *acalloc(int,int); 14 | extern void *arealloc(void*,int); 15 | extern void afree(void*); 16 | extern void adump(); 17 | 18 | #define malloc amalloc 19 | #define calloc acalloc 20 | #define realloc arealloc 21 | #define free afree 22 | 23 | #else 24 | 25 | #define adump() (void)1 26 | 27 | #endif 28 | 29 | #endif/*AMALLOC_D*/ 30 | -------------------------------------------------------------------------------- /discount/tests/linkypix.t: -------------------------------------------------------------------------------- 1 | ./echo "embedded images" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | if [ "$3" = "$Q" ]; then 18 | ./echo " ok" 19 | else 20 | ./echo " FAILED" 21 | ./echo "wanted: $3" 22 | ./echo "got : $Q" 23 | rc=1 24 | fi 25 | } 26 | 27 | try 'image with size extension' \ 28 | '![picture](pic =200x200)' \ 29 | '

picture

' 30 | 31 | exit $rc 32 | -------------------------------------------------------------------------------- /discount/tests/reparse.t: -------------------------------------------------------------------------------- 1 | ./echo "footnotes inside reparse sections" 2 | 3 | rc=0 4 | 5 | try() { 6 | unset FLAGS 7 | case "$1" in 8 | -*) FLAGS=$1 9 | shift ;; 10 | esac 11 | 12 | ./echo -n " $1" '..................................' | ./cols 36 13 | 14 | Q=`./echo "$2" | ./markdown $FLAGS` 15 | 16 | 17 | if [ "$3" = "$Q" ]; then 18 | ./echo " ok" 19 | else 20 | ./echo " FAILED" 21 | ./echo "wanted: $3" 22 | ./echo "got : $Q" 23 | rc=1 24 | fi 25 | } 26 | 27 | 28 | try 'footnote inside [] section' \ 29 | '[![foo][]](bar) 30 | 31 | [foo]: bar2' \ 32 | '

foo

' 33 | 34 | exit $rc 35 | -------------------------------------------------------------------------------- /discount/tests/para.t: -------------------------------------------------------------------------------- 1 | ./echo "paragraph blocking" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | 18 | if [ "$3" = "$Q" ]; then 19 | ./echo " ok" 20 | else 21 | ./echo " FAILED" 22 | ./echo "wanted: $3" 23 | ./echo "got : $Q" 24 | rc=1 25 | fi 26 | } 27 | 28 | try 'paragraph followed by code' \ 29 | 'a 30 | b' \ 31 | '

a

32 | 33 |
b
34 | 
' 35 | 36 | try 'single-line paragraph' 'a' '

a

' 37 | 38 | exit $rc 39 | -------------------------------------------------------------------------------- /discount/tests/footnotes.t: -------------------------------------------------------------------------------- 1 | ./echo "footnotes" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | if [ "$3" = "$Q" ]; then 18 | ./echo " ok" 19 | else 20 | ./echo " FAILED" 21 | ./echo "wanted: $3" 22 | ./echo "got : $Q" 23 | rc=1 24 | fi 25 | } 26 | 27 | try 'a line with multiple []s' '[a][] [b][]:' '

[a][] [b][]:

' 28 | try 'a valid footnote' \ 29 | '[alink][] 30 | 31 | [alink]: link_me' \ 32 | '

alink

' 33 | 34 | exit $rc 35 | -------------------------------------------------------------------------------- /discount/tests/toc.t: -------------------------------------------------------------------------------- 1 | ./echo "table-of-contents support" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | 9 | case "$1" in 10 | -*) FLAGS=$1 11 | shift ;; 12 | esac 13 | 14 | ./echo -n " $1" '..................................' | ./cols 36 15 | 16 | Q=`./echo "$2" | ./markdown $FLAGS` 17 | 18 | if [ "$3" = "$Q" ]; then 19 | ./echo " ok" 20 | else 21 | ./echo " FAILED" 22 | ./echo "wanted: $3" 23 | ./echo "got : $Q" 24 | rc=1 25 | fi 26 | } 27 | 28 | 29 | try '-T -ftoc' 'table of contents' \ 30 | '#H1 31 | hi' \ 32 | ' 33 |
    34 |
  • H1
  • 35 |
36 |

H1

37 | 38 |

hi

' 39 | 40 | 41 | exit $rc 42 | -------------------------------------------------------------------------------- /discount/tests/paranoia.t: -------------------------------------------------------------------------------- 1 | ./echo "paranoia" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | 18 | if [ "$3" = "$Q" ]; then 19 | ./echo " ok" 20 | else 21 | ./echo " FAILED" 22 | ./echo "wanted: $3" 23 | ./echo "got : $Q" 24 | rc=1 25 | fi 26 | } 27 | 28 | try -fsafelink 'bogus url (-fsafelink)' '[test](bad:protocol)' '

[test](bad:protocol)

' 29 | try -fnosafelink 'bogus url (-fnosafelink)' '[test](bad:protocol)' '

test

' 30 | 31 | exit $rc 32 | -------------------------------------------------------------------------------- /discount/tests/misc.t: -------------------------------------------------------------------------------- 1 | ./echo "misc" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | 18 | if [ "$3" = "$Q" ]; then 19 | ./echo " ok" 20 | else 21 | ./echo " FAILED" 22 | ./echo "wanted: $3" 23 | ./echo "got : $Q" 24 | rc=1 25 | fi 26 | } 27 | 28 | try 'single paragraph' 'AAA' '

AAA

' 29 | try '< -> <' '<' '

<

' 30 | try '`>` -> >' '`>`' '

>

' 31 | try '`` ` `` -> `' '`` ` ``' '

`

' 32 | 33 | exit $rc 34 | -------------------------------------------------------------------------------- /discount/README: -------------------------------------------------------------------------------- 1 | DISCOUNT is a implementation of John Gruber's Markdown markup 2 | language. It implements, as far as I can tell, all of the 3 | language as described in 4 | 5 | and passes the Markdown test suite at 6 | 7 | 8 | DISCOUNT is free software written by David Parsons ; 9 | it is released under a BSD-style license that allows you to do 10 | as you wish with it as long as you don't attempt to claim it as 11 | your own work. 12 | 13 | Most of the programs included in the DISCOUNT distribution have 14 | manual pages describing how they work. 15 | 16 | The file INSTALL describes how to build and install discount 17 | -------------------------------------------------------------------------------- /discount/tests/backslash.t: -------------------------------------------------------------------------------- 1 | ./echo "backslash escapes" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | if [ "$3" = "$Q" ]; then 18 | ./echo " ok" 19 | else 20 | ./echo " FAILED" 21 | ./echo "wanted: $3" 22 | ./echo "got: $Q" 23 | rc=1 24 | fi 25 | } 26 | 27 | try 'backslashes in []()' '[foo](http://\this\is\.a\test\(here\))' \ 28 | '

foo

' 29 | 30 | try -fautolink 'autolink url with trailing \' \ 31 | 'http://a.com/\' \ 32 | '

http://a.com/\

' 33 | 34 | 35 | exit $rc 36 | -------------------------------------------------------------------------------- /discount/tests/code.t: -------------------------------------------------------------------------------- 1 | ./echo "code blocks" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | 18 | if [ "$3" = "$Q" ]; then 19 | ./echo " ok" 20 | else 21 | ./echo " FAILED" 22 | ./echo "wanted: $3" 23 | ./echo "got : $Q" 24 | rc=1 25 | fi 26 | } 27 | 28 | try 'format for code block html' \ 29 | ' this is 30 | code' \ 31 | '
this is
32 | code
33 | 
' 34 | 35 | try 'unclosed single backtick' '`hi there' '

`hi there

' 36 | try 'unclosed double backtick' '``hi there' '

``hi there

' 37 | try 'remove space around code' '`` hi there ``' '

hi there

' 38 | 39 | exit $rc 40 | -------------------------------------------------------------------------------- /discount/Plan9/mkfile: -------------------------------------------------------------------------------- 1 | BIN=/$objtype/bin 2 | CC='cc -D_BSD_EXTENSION' 3 | 4 | markdown: 5 | ape/psh -c 'cd .. && make' 6 | 7 | none:V: markdown 8 | 9 | test: markdown 10 | ape/psh -c 'cd ..&& make test' 11 | 12 | install: markdown 13 | cp ../markdown $BIN/markdown 14 | 15 | install.progs: install 16 | cp ../makepage $BIN/makepage 17 | cp ../mkd2html $BIN/mkd2html 18 | 19 | install.libs: install 20 | cp ../mkdio.h /sys/include/ape/mkdio.h 21 | cp ../libmarkdown.a /$objtype/lib/ape/libmarkdown.a 22 | 23 | install.man: install 24 | cp markdown.1 /sys/man/1/markdown 25 | cp markdown.2 /sys/man/2/markdown 26 | cp markdown.6 /sys/man/6/markdown 27 | 28 | installall:V: install.libs install.man install.progs 29 | 30 | config: 31 | ape/psh -c 'cd .. && ./configure.sh $CONFIG' 32 | 33 | clean: 34 | ape/psh -c 'cd .. && make clean' 35 | 36 | nuke: 37 | ape/psh -c 'cd .. && make distclean' 38 | -------------------------------------------------------------------------------- /discount/tests/snakepit.t: -------------------------------------------------------------------------------- 1 | ./echo "The snakepit of Markdown.pl compatability" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | 18 | if [ "$3" = "$Q" ]; then 19 | ./echo " ok" 20 | else 21 | ./echo " FAILED" 22 | ./echo "wanted: $3" 23 | ./echo "got : $Q" 24 | rc=1 25 | fi 26 | } 27 | 28 | try '[](single quote) text (quote)' \ 29 | "[foo](http://Poe's law) will make this fail ('no, it won't!') here."\ 30 | '

foo here.

' 31 | 32 | try '[](unclosed foo

' 34 | exit $rc 35 | -------------------------------------------------------------------------------- /discount/tests/flow.t: -------------------------------------------------------------------------------- 1 | ./echo "paragraph flow" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | 18 | if [ "$3" = "$Q" ]; then 19 | ./echo " ok" 20 | else 21 | ./echo " FAILED" 22 | ./echo "wanted: $3" 23 | ./echo "got : $Q" 24 | rc=1 25 | fi 26 | } 27 | 28 | try 'header followed by paragraph' \ 29 | '###Hello, sailor### 30 | And how are you today?' \ 31 | '

Hello, sailor

32 | 33 |

And how are you today?

' 34 | 35 | try 'two lists punctuated with a HR' \ 36 | '* A 37 | * * * 38 | * B 39 | * C' \ 40 | '
    41 |
  • A
  • 42 |
43 | 44 | 45 |
46 | 47 |
    48 |
  • B
  • 49 |
  • C
  • 50 |
' 51 | 52 | exit $rc 53 | -------------------------------------------------------------------------------- /discount/tools/cols.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | main(argc, argv) 5 | char **argv; 6 | { 7 | register c; 8 | int xp; 9 | int width; 10 | 11 | if ( argc != 2 ) { 12 | fprintf(stderr, "usage: %s width\n", argv[0]); 13 | exit(1); 14 | } 15 | else if ( (width=atoi(argv[1])) < 1 ) { 16 | fprintf(stderr, "%s: please set width to > 0\n", argv[0]); 17 | exit(1); 18 | } 19 | 20 | 21 | for ( xp = 1; (c = getchar()) != EOF; xp++ ) { 22 | while ( c & 0xC0 ) { 23 | /* assume that (1) the output device understands utf-8, and 24 | * (2) the only c & 0x80 input is utf-8. 25 | */ 26 | do { 27 | if ( xp <= width ) 28 | putchar(c); 29 | } while ( (c = getchar()) != EOF && (c & 0x80) && !(c & 0x40) ); 30 | ++xp; 31 | } 32 | if ( c == '\n' ) 33 | xp = 0; 34 | if ( xp <= width ) 35 | putchar(c); 36 | } 37 | exit(0); 38 | } 39 | -------------------------------------------------------------------------------- /discount/tests/crash.t: -------------------------------------------------------------------------------- 1 | ./echo "crashes" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | ./echo -n ' zero-length input ................ ' 7 | 8 | if ./markdown < /dev/null >/dev/null; then 9 | ./echo "ok" 10 | else 11 | ./echo "FAILED" 12 | rc=1 13 | fi 14 | 15 | ./echo -n ' hanging quote in list ............ ' 16 | 17 | ./markdown >/dev/null 2>/dev/null << EOF 18 | * > this should not die 19 | 20 | no. 21 | EOF 22 | 23 | if [ "$?" -eq 0 ]; then 24 | ./echo "ok" 25 | else 26 | ./echo "FAILED" 27 | rc=1 28 | fi 29 | 30 | ./echo -n ' dangling list item ............... ' 31 | 32 | if ./echo ' - ' | ./markdown >/dev/null 2>/dev/null; then 33 | ./echo "ok" 34 | else 35 | ./echo "FAILED" 36 | rc=1 37 | fi 38 | 39 | ./echo -n ' empty []() with baseurl .......... ' 40 | 41 | if ./markdown -bHOHO -s '[]()' >/dev/null 2>/dev/null; then 42 | ./echo "ok" 43 | else 44 | ./echo "FAILED" 45 | rc=1 46 | fi 47 | 48 | exit $rc 49 | -------------------------------------------------------------------------------- /discount/tests/pseudo.t: -------------------------------------------------------------------------------- 1 | ./echo "pseudo-protocols" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | 18 | if [ "$3" = "$Q" ]; then 19 | ./echo " ok" 20 | else 21 | ./echo " FAILED" 22 | ./echo "wanted: $3" 23 | ./echo "got : $Q" 24 | rc=1 25 | fi 26 | } 27 | 28 | try '[](id:) links' '[foo](id:bar)' '

foo

' 29 | try -fnoext '[](id:) links with -fnoext' '[foo](id:bar)' '

[foo](id:bar)

' 30 | try '[](class:) links' '[foo](class:bar)' '

foo

' 31 | try -fnoext '[](class:) links with -fnoext' '[foo](class:bar)' '

[foo](class:bar)

' 32 | try '[](raw:) links' '[foo](raw:bar)' '

bar

' 33 | try -fnoext '[](raw:) links with -fnoext' '[foo](raw:bar)' '

[foo](raw:bar)

' 34 | 35 | exit $rc 36 | -------------------------------------------------------------------------------- /down.ooc: -------------------------------------------------------------------------------- 1 | include ./mkdio 2 | 3 | // Down is our Markdown class. 4 | // Down new("some *markdown*!") toHtml() 5 | Down: class { 6 | html: String 7 | 8 | init: func(=html) {} 9 | 10 | toHtml: func -> String { 11 | res := String 12 | doc := mkd_string(html, html length(), 0) 13 | 14 | if (mkd_compile(doc, 0)) { 15 | mkd_document(doc, res&) 16 | return res 17 | } else { 18 | return "markdown failed" 19 | } 20 | } 21 | 22 | // Shortcut: 23 | // Down toHtml("*hi*") 24 | toHtml: static func ~classLevel ( html : String ) -> String { 25 | return new(html) toHtml() 26 | } 27 | } 28 | 29 | // Bits of Discount we want to use 30 | DiscountDoc: cover from MMIOT* 31 | mkd_string: extern func (text : String, length : Int, flags : Int) -> DiscountDoc 32 | mkd_compile: extern func (doc : DiscountDoc, flags : Int) -> Int 33 | mkd_document: extern func (doc : DiscountDoc, text : String*) -> Int 34 | 35 | main: func { 36 | Down toHtml("*hi*") println() 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /discount/docheader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * docheader -- get values from the document header 3 | * 4 | * Copyright (C) 2007 David L Parsons. 5 | * The redistribution terms are provided in the COPYRIGHT file that must 6 | * be distributed with this source code. 7 | */ 8 | #include "config.h" 9 | #include 10 | #include 11 | #include 12 | 13 | #include "cstring.h" 14 | #include "markdown.h" 15 | #include "amalloc.h" 16 | 17 | #define afterdle(t) (T((t)->text) + (t)->dle) 18 | 19 | char * 20 | mkd_doc_title(Document *doc) 21 | { 22 | if ( doc && doc->headers ) 23 | return afterdle(doc->headers); 24 | return 0; 25 | } 26 | 27 | 28 | char * 29 | mkd_doc_author(Document *doc) 30 | { 31 | if ( doc && doc->headers && doc->headers->next ) 32 | return afterdle(doc->headers->next); 33 | return 0; 34 | } 35 | 36 | 37 | char * 38 | mkd_doc_date(Document *doc) 39 | { 40 | if ( doc && doc->headers && doc->headers->next && doc->headers->next->next ) 41 | return afterdle(doc->headers->next->next); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /discount/tests/compat.t: -------------------------------------------------------------------------------- 1 | ./echo "markdown 1.0 compatability" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | if [ "$3" = "$Q" ]; then 18 | ./echo " ok" 19 | else 20 | ./echo " FAILED" 21 | ./echo "wanted: $3" 22 | ./echo "got : $Q" 23 | rc=1 24 | fi 25 | } 26 | 27 | LINKY='[this] is a test 28 | 29 | [this]: /this' 30 | 31 | try 'implicit reference links' "$LINKY" '

this is a test

' 32 | try -f1.0 'implicit reference links (-f1.0)' "$LINKY" '

[this] is a test

' 33 | 34 | WSP=' ' 35 | WHITESPACE=" 36 | white space$WSP 37 | and more" 38 | 39 | try 'trailing whitespace' "$WHITESPACE" '
white space ''
40 | and more
41 | 
' 42 | 43 | try -f1.0 'trailing whitespace (-f1.0)' "$WHITESPACE" '
white space''
44 | and more
45 | 
' 46 | 47 | exit $rc 48 | -------------------------------------------------------------------------------- /discount/tests/tabstop.t: -------------------------------------------------------------------------------- 1 | rc=0 2 | unset MARKDOWN_FLAGS 3 | unset MKD_TABSTOP 4 | 5 | try() { 6 | unset FLAGS 7 | case "$1" in 8 | -*) FLAGS=$1 9 | shift ;; 10 | esac 11 | 12 | ./echo -n " $1" '..................................' | ./cols 36 13 | 14 | Q=`./echo "$2" | ./markdown $FLAGS` 15 | 16 | if [ "$3" = "$Q" ]; then 17 | ./echo " ok" 18 | else 19 | ./echo " FAILED" 20 | ./echo "wanted: $3" 21 | ./echo "got : $Q" 22 | rc=1 23 | fi 24 | } 25 | 26 | eval `./markdown -V | tr ' ' '\n' | grep TAB` 27 | 28 | if [ "${TAB:-4}" -eq 8 ]; then 29 | ./echo "dealing with tabstop derangement" 30 | 31 | LIST=' 32 | * A 33 | * B 34 | * C' 35 | 36 | try 'markdown with TAB=8' \ 37 | "$LIST" \ 38 | '
    39 |
  • A 40 | 41 |
      42 |
    • B 43 | 44 |
        45 |
      • C
      • 46 |
      47 |
    • 48 |
    49 |
  • 50 |
' 51 | 52 | try -F0x0200 'markdown with TAB=4' \ 53 | "$LIST" \ 54 | '
    55 |
  • A 56 | 57 |
      58 |
    • B
    • 59 |
    • C
    • 60 |
    61 |
  • 62 |
' 63 | 64 | fi 65 | 66 | exit $rc 67 | -------------------------------------------------------------------------------- /discount/tests/emphasis.t: -------------------------------------------------------------------------------- 1 | ./echo "emphasis" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | if [ "$3" = "$Q" ]; then 18 | ./echo " ok" 19 | else 20 | ./echo " FAILED" 21 | ./echo "wanted: $3" 22 | ./echo "got : $Q" 23 | rc=1 24 | fi 25 | } 26 | 27 | 28 | try '*hi* -> hi' '*hi*' '

hi

' 29 | try '* -> *' 'A * A' '

A * A

' 30 | try -fstrict '***A**B*' '***A**B*' '

AB

' 31 | try -fstrict '***A*B**' '***A*B**' '

AB

' 32 | try -fstrict '**A*B***' '**A*B***' '

AB

' 33 | try -fstrict '*A**B***' '*A**B***' '

AB

' 34 | 35 | if ./markdown -V | grep RELAXED >/dev/null; then 36 | try -frelax '_A_B with -frelax' '_A_B' '

_A_B

' 37 | try -fstrict '_A_B with -fstrict' '_A_B' '

AB

' 38 | fi 39 | 40 | exit $rc 41 | -------------------------------------------------------------------------------- /discount/tests/header.t: -------------------------------------------------------------------------------- 1 | ./echo "headers" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | S=`./echo -n "$1" '..................................' | ./cols 34` 14 | ./echo -n " $S " 15 | 16 | Q=`./echo "$2" | ./markdown $FLAGS` 17 | 18 | 19 | if [ "$3" = "$Q" ]; then 20 | ./echo "ok" 21 | else 22 | ./echo "FAILED" 23 | ./echo "wanted: $3" 24 | ./echo "got : $Q" 25 | rc=1 26 | fi 27 | } 28 | 29 | try 'single #' '#' '

#

' 30 | try 'empty ETX' '##' '

#

' 31 | try 'single-char ETX (##W)' '##W' '

W

' 32 | try 'single-char ETX (##W )' '##W ' '

W

' 33 | try 'single-char ETX (## W)' '## W' '

W

' 34 | try 'single-char ETX (## W )' '## W ' '

W

' 35 | try 'single-char ETX (##W##)' '##W##' '

W

' 36 | try 'single-char ETX (##W ##)' '##W ##' '

W

' 37 | try 'single-char ETX (## W##)' '## W##' '

W

' 38 | try 'single-char ETX (## W ##)' '## W ##' '

W

' 39 | 40 | try 'multiple-char ETX (##Hello##)' '##Hello##' '

Hello

' 41 | 42 | exit $rc 43 | -------------------------------------------------------------------------------- /discount/tests/autolink.t: -------------------------------------------------------------------------------- 1 | ./echo 'Reddit-style automatic links' 2 | rc=0 3 | 4 | try() { 5 | unset FLAGS 6 | case "$1" in 7 | -*) FLAGS=$1 8 | shift ;; 9 | esac 10 | 11 | ./echo -n " $1" '..................................' | ./cols 36 12 | 13 | Q=`./echo "$2" | ./markdown $FLAGS` 14 | 15 | 16 | if [ "$3" = "$Q" ]; then 17 | ./echo " ok" 18 | else 19 | ./echo " FAILED" 20 | ./echo "wanted: $3" 21 | ./echo "got : $Q" 22 | rc=1 23 | fi 24 | } 25 | 26 | try -fautolink 'single link' \ 27 | 'http://www.pell.portland.or.us/~orc/Code/discount' \ 28 | '

http://www.pell.portland.or.us/~orc/Code/discount

' 29 | 30 | try -fautolink 'link surrounded by text' \ 31 | 'here http://it is?' \ 32 | '

here http://it is?

' 33 | 34 | try -fautolink 'naked @' '@' '

@

' 35 | 36 | try -fautolink 'parenthesised (url)' \ 37 | '(http://here)' \ 38 | '

(http://here)

' 39 | 40 | try -fautolink 'token with trailing @' 'orc@' '

orc@

' 41 | 42 | exit $rc 43 | -------------------------------------------------------------------------------- /discount/mkd-line.3: -------------------------------------------------------------------------------- 1 | .\" 2 | .Dd January 18, 2008 3 | .Dt MKD_LINE 3 4 | .Os Mastodon 5 | .Sh NAME 6 | .Nm mkd_line 7 | .Nd do Markdown translation of small items 8 | .Sh LIBRARY 9 | Markdown 10 | .Pq libmarkdown , -lmarkdown 11 | .Sh SYNOPSIS 12 | .Fd #include 13 | .Ft int 14 | .Fn mkd_line "char *string" "int size" "char **doc" "int flags" 15 | .Ft int 16 | .Fn mkd_generateline "char *string" "int size" "FILE *output" "int flags" 17 | .Sh DESCRIPTION 18 | .Pp 19 | Occasionally one might want to do markdown translations on fragments of 20 | data, like the title of an weblog article, a date, or a simple signature 21 | line. 22 | .Nm mkd_line 23 | and 24 | .Nm mkd_generateline 25 | allow you to do markdown translations on small blocks of text. 26 | .Nm mkd_line 27 | allocates a buffer, then writes the translated text into that buffer, 28 | and 29 | .Nm mkd_generateline 30 | writes the output to the specified 31 | .Ar FILE* . 32 | .Sh SEE ALSO 33 | .Xr markdown 1 , 34 | .Xr markdown 3 , 35 | .Xr markdown 7 , 36 | .Xr mkd-extensions 7 , 37 | .Xr mmap 2 . 38 | .Pp 39 | http://daringfireball.net/projects/markdown/syntax 40 | .Sh BUGS 41 | Error handling is minimal at best. 42 | -------------------------------------------------------------------------------- /discount/tests/xml.t: -------------------------------------------------------------------------------- 1 | ./echo "xml output with MKD_CDATA" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | case "$2" in 16 | -t*) Q=`./markdown $FLAGS "$2"` ;; 17 | *) Q=`./echo "$2" | ./markdown $FLAGS` ;; 18 | esac 19 | 20 | if [ "$3" = "$Q" ]; then 21 | ./echo " ok" 22 | else 23 | ./echo " FAILED" 24 | ./echo "wanted: $3" 25 | ./echo "got : $Q" 26 | rc=1 27 | fi 28 | } 29 | 30 | try -fcdata 'xml output from markdown()' 'hello,sailor' '<p>hello,sailor</p>' 31 | try -fcdata 'from mkd_generateline()' -t'"hello,sailor"' '&ldquo;hello,sailor&rdquo;' 32 | try -fnocdata 'html output from markdown()' '"hello,sailor"' '

“hello,sailor”

' 33 | try -fnocdata '... from mkd_generateline()' -t'"hello,sailor"' '“hello,sailor”' 34 | 35 | try -fcdata 'xml output with multibyte utf-8' \ 36 | 'tecnología y servicios más confiables' \ 37 | '<p>tecnología y servicios más confiables</p>' 38 | 39 | exit $rc 40 | -------------------------------------------------------------------------------- /discount/tests/peculiarities.t: -------------------------------------------------------------------------------- 1 | ./echo "markup peculiarities" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | if [ "$3" = "$Q" ]; then 18 | ./echo " ok" 19 | else 20 | ./echo " FAILED" 21 | ./echo "wanted: $3" 22 | ./echo "got : $Q" 23 | rc=1 24 | fi 25 | } 26 | 27 | try 'list followed by header .......... ' \ 28 | " 29 | - AAA 30 | - BBB 31 | -" \ 32 | '
    33 |
  • AAA 34 | 35 |

    – BBB

  • 36 |
' 37 | 38 | try 'ul with mixed item prefixes' \ 39 | ' 40 | - A 41 | 1. B' \ 42 | '
    43 |
  • A
  • 44 |
  • B
  • 45 |
' 46 | 47 | try 'ol with mixed item prefixes' \ 48 | ' 49 | 1. A 50 | - B 51 | ' \ 52 | '
    53 |
  1. A
  2. 54 |
  3. B
  4. 55 |
' 56 | 57 | try 'forcing a
' 'this ' '

this
58 |

' 59 | 60 | try 'trimming single spaces' 'this ' '

this

' 61 | try -fnohtml 'markdown
with -fnohtml' 'foo ' '

foo
62 |

' 63 | 64 | exit $rc 65 | -------------------------------------------------------------------------------- /discount/tests/dl.t: -------------------------------------------------------------------------------- 1 | ./echo "definition lists" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | if [ "$3" = "$Q" ]; then 18 | ./echo " ok" 19 | else 20 | ./echo " FAILED" 21 | ./echo "wanted: $3" 22 | ./echo "got : $Q" 23 | rc=1 24 | fi 25 | } 26 | 27 | SRC=' 28 | =this= 29 | is an ugly 30 | =test= 31 | eh?' 32 | 33 | RSLT='
34 |
this
35 |
is an ugly
36 |
test
37 |
eh?
38 |
' 39 | 40 | if ./markdown -V | grep DL_TAG >/dev/null; then 41 | 42 | try '=tag= generates definition lists' "$SRC" "$RSLT" 43 | 44 | try 'one item with two =tags=' \ 45 | '=this= 46 | =is= 47 | A test, eh?' \ 48 | '
49 |
this
50 |
is
51 |
A test, eh?
52 |
' 53 | 54 | 55 | else 56 | try '=tag= does nothing' "$SRC" \ 57 | '

=this=

58 | 59 |
is an ugly
60 | 
61 | 62 |

=test=

63 | 64 |
eh?
65 | 
' 66 | 67 | fi 68 | 69 | exit $rc 70 | -------------------------------------------------------------------------------- /discount/Csio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "cstring.h" 5 | #include "markdown.h" 6 | #include "amalloc.h" 7 | 8 | 9 | /* putc() into a cstring 10 | */ 11 | void 12 | Csputc(int c, Cstring *iot) 13 | { 14 | EXPAND(*iot) = c; 15 | } 16 | 17 | 18 | /* printf() into a cstring 19 | */ 20 | int 21 | Csprintf(Cstring *iot, char *fmt, ...) 22 | { 23 | va_list ptr; 24 | int siz=100; 25 | 26 | do { 27 | RESERVE(*iot, siz); 28 | va_start(ptr, fmt); 29 | siz = vsnprintf(T(*iot)+S(*iot), ALLOCATED(*iot)-S(*iot), fmt, ptr); 30 | va_end(ptr); 31 | } while ( siz > (ALLOCATED(*iot)-S(*iot)) ); 32 | 33 | S(*iot) += siz; 34 | return siz; 35 | } 36 | 37 | 38 | /* write() into a cstring 39 | */ 40 | int 41 | Cswrite(Cstring *iot, char *bfr, int size) 42 | { 43 | RESERVE(*iot, size); 44 | memcpy(T(*iot)+S(*iot), bfr, size); 45 | S(*iot) += size; 46 | return size; 47 | } 48 | 49 | 50 | /* reparse() into a cstring 51 | */ 52 | void 53 | Csreparse(Cstring *iot, char *buf, int size, int flags) 54 | { 55 | MMIOT f; 56 | ___mkd_initmmiot(&f, 0); 57 | ___mkd_reparse(buf, size, 0, &f); 58 | ___mkd_emblock(&f); 59 | SUFFIX(*iot, T(f.out), S(f.out)); 60 | ___mkd_freemmiot(&f, 0); 61 | } 62 | -------------------------------------------------------------------------------- /discount/tests/list3deep.t: -------------------------------------------------------------------------------- 1 | ./echo "deeply nested lists" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | if [ "$3" = "$Q" ]; then 18 | ./echo " ok" 19 | else 20 | ./echo " FAILED" 21 | ./echo "wanted: $3" 22 | ./echo "got : $Q" 23 | rc=1 24 | fi 25 | } 26 | 27 | LIST=' 28 | * top-level list ( list 1) 29 | + second-level list (list 2) 30 | * first item third-level list (list 3) 31 | + * second item, third-level list, first item. (list 4) 32 | * second item, third-level list, second item. 33 | * top-level list again.' 34 | 35 | RSLT='
    36 |
  • top-level list ( list 1) 37 | 38 |
      39 |
    • second-level list (list 2) 40 | 41 |
        42 |
      • first item third-level list (list 3)
      • 43 |
      44 |
    • 45 |
      • 46 |
      • second item, third-level list, first item. (list 4)
      • 47 |
      • second item, third-level list, second item.
      • 48 |
      49 |
    • 50 |
    51 |
  • 52 |
  • top-level list again.
  • 53 |
' 54 | 55 | try 'thrice-nested lists' "$LIST" "$RSLT" 56 | 57 | exit $rc 58 | -------------------------------------------------------------------------------- /discount/tests/pandoc.t: -------------------------------------------------------------------------------- 1 | ./echo "pandoc headers" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | 18 | if [ "$3" = "$Q" ]; then 19 | ./echo " ok" 20 | else 21 | ./echo " FAILED" 22 | ./echo "wanted: $3" 23 | ./echo "got : $Q" 24 | rc=1 25 | fi 26 | } 27 | 28 | 29 | HEADER='% title 30 | % author(s) 31 | % date' 32 | 33 | 34 | if ./markdown -V | grep HEADER > /dev/null; then 35 | 36 | try 'valid header' "$HEADER" '' 37 | try -F0x0100 'valid header with -F0x0100' "$HEADER" '

% title 38 | % author(s) 39 | % date

' 40 | 41 | try 'invalid header' \ 42 | '% title 43 | % author(s) 44 | a pony!' \ 45 | '

% title 46 | % author(s) 47 | a pony!

' 48 | 49 | try 'offset header' \ 50 | ' 51 | % title 52 | % author(s) 53 | % date' \ 54 | '

% title 55 | % author(s) 56 | % date

' 57 | 58 | try 'indented header' \ 59 | ' % title 60 | % author(s) 61 | % date' \ 62 | '

% title 63 | % author(s) 64 | % date

' 65 | 66 | else 67 | 68 | try 'ignore headers' "$HEADER" '

% title 69 | % author(s) 70 | % date

' 71 | 72 | fi 73 | 74 | exit $rc 75 | -------------------------------------------------------------------------------- /discount/tests/div.t: -------------------------------------------------------------------------------- 1 | ./markdown -V | grep DIV >/dev/null || exit 0 2 | 3 | ./echo "%div% blocks" 4 | 5 | rc=0 6 | MARKDOWN_FLAGS= 7 | 8 | try() { 9 | unset FLAGS 10 | case "$1" in 11 | -*) FLAGS=$1 12 | shift ;; 13 | esac 14 | 15 | ./echo -n " $1" '..................................' | ./cols 36 16 | 17 | Q=`./echo "$2" | ./markdown $FLAGS` 18 | 19 | 20 | if [ "$3" = "$Q" ]; then 21 | ./echo " ok" 22 | else 23 | ./echo " FAILED" 24 | ./echo "wanted: $3" 25 | ./echo "got : $Q" 26 | rc=1 27 | fi 28 | } 29 | 30 | try 'simple >%div% block' \ 31 | '>%this% 32 | this this' \ 33 | '

this this

' 34 | 35 | try 'two >%div% blocks in a row' \ 36 | '>%this% 37 | this this 38 | 39 | >%that% 40 | that that' \ 41 | '

this this

42 | 43 |

that that

' 44 | 45 | try '>%class:div%' \ 46 | '>%class:this% 47 | this this' \ 48 | '

this this

' 49 | 50 | try '>%id:div%' \ 51 | '>%id:this% 52 | this this' \ 53 | '

this this

' 54 | 55 | try 'nested >%div%' \ 56 | '>%this% 57 | >>%that% 58 | >>that 59 | 60 | >%more% 61 | more' \ 62 | '

that

63 | 64 |

more

' 65 | 66 | 67 | exit $rc 68 | -------------------------------------------------------------------------------- /discount/xmlpage.c: -------------------------------------------------------------------------------- 1 | /* 2 | * xmlpage -- write a skeletal xhtml page 3 | * 4 | * Copyright (C) 2007 David L Parsons. 5 | * The redistribution terms are provided in the COPYRIGHT file that must 6 | * be distributed with this source code. 7 | */ 8 | #include "config.h" 9 | #include 10 | #include 11 | #include 12 | 13 | #include "cstring.h" 14 | #include "markdown.h" 15 | #include "amalloc.h" 16 | 17 | 18 | int 19 | mkd_xhtmlpage(Document *p, int flags, FILE *out) 20 | { 21 | char *title; 22 | extern char *mkd_doc_title(Document *); 23 | 24 | if ( mkd_compile(p, flags) ) { 25 | fprintf(out, "\n"); 26 | fprintf(out, "\n"); 29 | 30 | fprintf(out, "\n"); 31 | 32 | fprintf(out, "\n"); 33 | if ( title = mkd_doc_title(p) ) 34 | fprintf(out, "%s\n", title); 35 | mkd_generatecss(p, out); 36 | fprintf(out, "\n"); 37 | 38 | fprintf(out, "\n"); 39 | mkd_generatehtml(p, out); 40 | fprintf(out, "\n"); 41 | fprintf(out, "\n"); 42 | 43 | mkd_cleanup(p); 44 | 45 | return 0; 46 | } 47 | return -1; 48 | } 49 | -------------------------------------------------------------------------------- /discount/Plan9/README: -------------------------------------------------------------------------------- 1 | % Discount on Plan 9 2 | % Josh Wood 3 | % 2009-06-12 4 | 5 | # *Discount* Markdown compiler on Plan 9 6 | 7 | ## Build 8 | 9 | % CONFIG='--enable-all-features' mk config 10 | % mk install 11 | % markdown -V 12 | markdown: discount X.Y.Z DL_TAG HEADER DEBUG SUPERSCRIPT RELAXED DIV 13 | 14 | `--enable-all-features` may be replaced by zero or more of: 15 | 16 | --enable-dl-tag Use the DL tag extension 17 | --enable-pandoc-header Use pandoc-style header blocks 18 | --enable-superscript A^B becomes AB 19 | --enable-amalloc Enable memory allocation debugging 20 | --relaxed-emphasis underscores aren't special in the middle of words 21 | --with-tabstops=N Set tabstops to N characters (default is 4) 22 | --enable-div Enable >%id% divisions 23 | --enable-alpha-list Enable (a)/(b)/(c) lists 24 | --enable-all-features Turn on all stable optional features 25 | 26 | ## Notes 27 | 28 | The supplied mkfile merely drives Discount's own configure script and 29 | then APE's *psh* environment to build the Discount source, then copies 30 | the result(s) to locations appropriate for system-wide use on Plan 9. 31 | There are a few other *mk*(1) targets: 32 | 33 | `install.libs`: Discount includes a C library and header. 34 | Installation is optional. Plan 9 binaries are statically linked. 35 | 36 | `install.man`: Add manual pages for markdown(1) and (6). 37 | 38 | `install.progs`: Extra programs. *makepage* writes complete XHTML 39 | documents, rather than fragments. *mkd2html* is similar, but produces 40 | HTML. 41 | -------------------------------------------------------------------------------- /discount/tests/smarty.t: -------------------------------------------------------------------------------- 1 | ./echo "smarty pants" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS=0x0; export MARKDOWN_FLAGS 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS="$1" 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | 18 | if [ "$3" = "$Q" ]; then 19 | ./echo " ok" 20 | else 21 | ./echo " FAILED" 22 | ./echo "wanted: $3" 23 | ./echo "got : $Q" 24 | rc=1 25 | fi 26 | } 27 | 28 | 29 | try '(c) -> ©' '(c)' '

©

' 30 | try '(r) -> ®' '(r)' '

®

' 31 | try '(tm) -> ™' '(tm)' '

' 32 | try '... -> …' '...' '

' 33 | 34 | try '"--" -> —' '--' '

' 35 | 36 | try '"-" -> –' 'regular -' '

regular –

' 37 | try 'A-B -> A-B' 'A-B' '

A-B

' 38 | try '"fancy" -> “fancy”' '"fancy"' '

“fancy”

' 39 | try "'fancy'" "'fancy'" '

‘fancy’

' 40 | try "don't -> don’t" "don't" '

don’t

' 41 | try "don't -> don’t" "don't" '

don’t

' 42 | try "it's -> it’s" "it's" '

it’s

' 43 | 44 | if ./markdown -V | grep SUPERSCRIPT >/dev/null; then 45 | try -frelax 'A^B -> AB (-frelax)' 'A^B' '

AB

' 46 | try -fstrict 'A^B != AB (-fstrict)' 'A^B' '

A^B

' 47 | try -frelax 'A^B in link title' '[link](here "A^B")' '

link

' 48 | fi 49 | 50 | exit $rc 51 | -------------------------------------------------------------------------------- /discount/CREDITS: -------------------------------------------------------------------------------- 1 | Discount is primarily my work, but it has only reached the point 2 | where it is via contributions, critiques, and bug reports from a 3 | host of other people, some of which are listed before. If your 4 | name isn't on this list, please remind me 5 | -david parsons (orc@pell.chi.il.us) 6 | 7 | 8 | Josh Wood -- Plan9 support. 9 | Mike Schiraldi -- Reddit style automatic links, MANY MANY MANY 10 | bug reports about boundary conditions and 11 | places where I didn't get it right. 12 | Jjgod Jiang -- Table of contents support. 13 | Petite Abeille -- Many bug reports about places where I didn't 14 | get it right. 15 | Tim Channon -- inspiration for the `mkd_xhtmlpage()` function 16 | Christian Herenz-- Many bug reports regarding my implementation of 17 | `[]()` and `![]()` 18 | A.S.Bradbury -- Portability bug reports for 64 bit systems. 19 | Joyent -- Loan of a solaris box so I could get discount 20 | working under solaris. 21 | Ryan Tomayko -- Portability requests (and the rdiscount ruby 22 | binding.) 23 | yidabu -- feedback on the documentation, bug reports 24 | against utf-8 support. 25 | Pierre Joye -- bug reports, php discount binding. 26 | Masayoshi Sekimura- perl discount binding. 27 | Jeremy Hinegardner- bug reports about list handling. 28 | Andrew White -- bug reports about the format of generated urls. 29 | Steve Huff -- bug reports about Makefile portability (for Fink) 30 | Ignacio Burgue?o-- bug reports about `>%class%` 31 | Henrik Nyh -- bug reports about embedded html handling. 32 | 33 | 34 | -------------------------------------------------------------------------------- /discount/tests/automatic.t: -------------------------------------------------------------------------------- 1 | ./echo "automatic links" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | 18 | if [ "$3" = "$Q" ]; then 19 | ./echo " ok" 20 | else 21 | ./echo " FAILED" 22 | ./echo "wanted: $3" 23 | ./echo "got : $Q" 24 | rc=1 25 | fi 26 | } 27 | 28 | match() { 29 | ./echo -n " $1" '..................................' | ./cols 36 30 | 31 | if ./echo "$2" | ./markdown | grep "$3" >/dev/null; then 32 | ./echo " ok" 33 | else 34 | ./echo " FAILED" 35 | rc=1 36 | fi 37 | } 38 | 39 | try 'http url' '' '

http://here

' 40 | try 'ftp url' '' '

ftp://here

' 41 | match '' '' '' '' '' '' '

<orc@>

' 44 | try 'invalid <@pell>' '<@pell>' '

<@pell>

' 45 | try 'invalid ' '' '

<orc@pell>

' 46 | try 'invalid ' '' '

<orc@.pell>

' 47 | try 'invalid ' '' '

<orc@pell.>

' 48 | match '' '' '
' '' '' '' '' '' ' 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "config.h" 15 | 16 | #include "cstring.h" 17 | #include "markdown.h" 18 | #include "amalloc.h" 19 | 20 | 21 | /* 22 | * dump out stylesheet sections. 23 | */ 24 | static void 25 | stylesheets(Paragraph *p, Cstring *f) 26 | { 27 | Line* q; 28 | 29 | for ( ; p ; p = p->next ) { 30 | if ( p->typ == STYLE ) { 31 | for ( q = p->text; q ; q = q->next ) 32 | Cswrite(f, T(q->text), S(q->text)); 33 | Csputc('\n', f); 34 | } 35 | if ( p->down ) 36 | stylesheets(p->down, f); 37 | } 38 | } 39 | 40 | 41 | /* dump any embedded styles to a string 42 | */ 43 | int 44 | mkd_css(Document *d, char **res) 45 | { 46 | Cstring f; 47 | 48 | if ( res && *res && d && d->compiled ) { 49 | CREATE(f); 50 | RESERVE(f, 100); 51 | stylesheets(d->code, &f); 52 | 53 | /* HACK ALERT! HACK ALERT! HACK ALERT! */ 54 | *res = T(f); /* we know that a T(Cstring) is a character pointer */ 55 | /* so we can simply pick it up and carry it away, */ 56 | return S(f); /* leaving the husk of the Ctring on the stack */ 57 | /* END HACK ALERT */ 58 | } 59 | return EOF; 60 | } 61 | 62 | 63 | /* dump any embedded styles to a file 64 | */ 65 | int 66 | mkd_generatecss(Document *d, FILE *f) 67 | { 68 | char *res; 69 | int written = EOF, size = mkd_css(d, &res); 70 | 71 | if ( size > 0 ) 72 | written = fwrite(res, size, 1, f); 73 | if ( res ) 74 | free(res); 75 | return (written == size) ? size : EOF; 76 | } 77 | -------------------------------------------------------------------------------- /discount/INSTALL: -------------------------------------------------------------------------------- 1 | 2 | HOW TO BUILD AND INSTALL DISCOUNT 3 | 4 | 1) Unpacking the distribution 5 | 6 | The DISCOUNT sources are distributed in tarballs. After extracting from 7 | the tarball, you should end up with all the source and build files in the 8 | directory 9 | discount-(version) 10 | 11 | 2) Installing the distribution 12 | 13 | DISCOUNT uses configure.sh to set itself up for compilation. To run 14 | configure, just do ``./configure.sh'' and it will check your system for 15 | build dependencies and build makefiles for you. If configure.sh finishes 16 | without complaint, you can then do a ``make'' to compile everything and a 17 | ``make install'' to install the binaries. 18 | 19 | Configure.sh has a few options that can be set: 20 | 21 | --src=DIR where the source lives (.) 22 | --prefix=DIR where to install the final product (/usr/local) 23 | --execdir=DIR where to put executables (prefix/bin) 24 | --sbindir=DIR where to put static executables (prefix/sbin) 25 | --confdir=DIR where to put configuration information (/etc) 26 | --libdir=DIR where to put libraries (prefix/lib) 27 | --libexecdir=DIR where to put private executables 28 | --mandir=DIR where to put manpages 29 | --enable-dl-tag Use the DL tag extension 30 | --enable-pandoc-header Use pandoc-style header blocks 31 | --enable-superscript A^B expands to AB 32 | --enable-amalloc Use a debugging memory allocator (to detect leaks) 33 | --relaxed-emphasis Don't treat _ in the middle of a word as emphasis 34 | --with-tabstops=N Set tabstops to N characters (default is 4) 35 | 36 | 3) Installing sample programs and manpages 37 | 38 | The standard ``make install'' rule just installs the binaries. If you 39 | want to install the sample programs, they are installed with 40 | ``make install.samples''; to install manpages, ``make install.man''. 41 | A shortcut to install everything is ``make install.everything'' 42 | -------------------------------------------------------------------------------- /discount/xml.c: -------------------------------------------------------------------------------- 1 | /* markdown: a C implementation of John Gruber's Markdown markup language. 2 | * 3 | * Copyright (C) 2007 David L Parsons. 4 | * The redistribution terms are provided in the COPYRIGHT file that must 5 | * be distributed with this source code. 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "config.h" 15 | 16 | #include "cstring.h" 17 | #include "markdown.h" 18 | #include "amalloc.h" 19 | 20 | /* return the xml version of a character 21 | */ 22 | static char * 23 | mkd_xmlchar(unsigned char c) 24 | { 25 | switch (c) { 26 | case '<': return "<"; 27 | case '>': return ">"; 28 | case '&': return "&"; 29 | case '"': return """; 30 | case '\'': return "'"; 31 | default: if ( isascii(c) || (c & 0x80) ) 32 | return 0; 33 | return ""; 34 | } 35 | } 36 | 37 | 38 | /* write output in XML format 39 | */ 40 | int 41 | mkd_generatexml(char *p, int size, FILE *out) 42 | { 43 | unsigned char c; 44 | char *entity; 45 | 46 | while ( size-- > 0 ) { 47 | c = *p++; 48 | 49 | if ( entity = mkd_xmlchar(c) ) 50 | fputs(entity, out); 51 | else 52 | fputc(c, out); 53 | } 54 | return 0; 55 | } 56 | 57 | 58 | /* build a xml'ed version of a string 59 | */ 60 | int 61 | mkd_xml(char *p, int size, char **res) 62 | { 63 | unsigned char c; 64 | char *entity; 65 | Cstring f; 66 | 67 | CREATE(f); 68 | RESERVE(f, 100); 69 | 70 | while ( size-- > 0 ) { 71 | c = *p++; 72 | if ( entity = mkd_xmlchar(c) ) 73 | Cswrite(&f, entity, strlen(entity)); 74 | else 75 | Csputc(c, &f); 76 | } 77 | /* HACK ALERT! HACK ALERT! HACK ALERT! */ 78 | *res = T(f); /* we know that a T(Cstring) is a character pointer */ 79 | /* so we can simply pick it up and carry it away, */ 80 | return S(f); /* leaving the husk of the Ctring on the stack */ 81 | /* END HACK ALERT */ 82 | } 83 | -------------------------------------------------------------------------------- /discount/tests/html.t: -------------------------------------------------------------------------------- 1 | ./echo "html blocks" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | if [ "$3" = "$Q" ]; then 18 | ./echo " ok" 19 | else 20 | ./echo " FAILED" 21 | ./echo "wanted: $3" 22 | ./echo "got : $Q" 23 | rc=1 24 | fi 25 | } 26 | 27 | try 'self-closing block tags (hr)' \ 28 | '
29 | 30 | text' \ 31 | '
32 | 33 | 34 |

text

' 35 | 36 | try 'self-closing block tags (hr/)' \ 37 | '
38 | 39 | text' \ 40 | '
41 | 42 | 43 |

text

' 44 | 45 | try 'self-closing block tags (br)' \ 46 | '
47 | 48 | text' \ 49 | '
50 | 51 | 52 |

text

' 53 | 54 | try 'html comments' \ 55 | '' \ 58 | '' 61 | 62 | try 'no smartypants inside tags (#1)' \ 63 | '' \ 64 | '

' 65 | 66 | try 'no smartypants inside tags (#2)' \ 67 | ':)' \ 68 | '

:)

' 69 | 70 | try -fnohtml 'block html with -fnohtml' 'hi!' '

<b>hi!</b>

' 71 | try -fhtml 'allow html with -fhtml' 'hi!' '

hi!

' 72 | 73 | 74 | # check that nested raw html blocks terminate properly. 75 | # 76 | BLOCK1SRC='Markdown works fine *here*. 77 | 78 | *And* here. 79 | 80 |
 81 | 
82 | 83 | Markdown here is *not* parsed by RDiscount. 84 | 85 | Nor in *this* paragraph, and there are no paragraph breaks.' 86 | 87 | BLOCK1OUT='

Markdown works fine here.

88 | 89 |

And here.

90 | 91 |
 92 | 
93 | 94 | 95 |

Markdown here is not parsed by RDiscount.

96 | 97 |

Nor in this paragraph, and there are no paragraph breaks.

' 98 | 99 | try 'nested html blocks (1)' "$BLOCK1SRC" "$BLOCK1OUT" 100 | 101 | try 'nested html blocks (2)' \ 102 | '
This is inside a html block 103 |
This is, too
and 104 | so is this
' \ 105 | '
This is inside a html block 106 |
This is, too
and 107 | so is this
' 108 | 109 | exit $rc 110 | -------------------------------------------------------------------------------- /discount/COPYRIGHT: -------------------------------------------------------------------------------- 1 | ->Copyright (C) 2007 David Loren Parsons. 2 | All rights reserved.<- 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation files 6 | (the "Software"), to deal in the Software without restriction, 7 | including without limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicence, and/or sell copies of the Software, 9 | and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | 1. Redistributions of source code must retain the above copyright 13 | notice, this list of conditions, and the following disclaimer. 14 | 15 | 2. Redistributions in binary form must reproduce the above 16 | copyright notice, this list of conditions and the following 17 | disclaimer in the documentation and/or other materials provided 18 | with the distribution, and in the same place and form as other 19 | copyright, license and disclaimer information. 20 | 21 | 3. The end-user documentation included with the redistribution, if 22 | any, must include the following acknowledgment: 23 | 24 | This product includes software developed by 25 | David Loren Parsons 26 | 27 | in the same place and form as other third-party acknowledgments. 28 | Alternately, this acknowledgment may appear in the software 29 | itself, in the same form and location as other such third-party 30 | acknowledgments. 31 | 32 | 4. Except as contained in this notice, the name of David Loren 33 | Parsons shall not be used in advertising or otherwise to promote 34 | the sale, use or other dealings in this Software without prior 35 | written authorization from David Loren Parsons. 36 | 37 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 39 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 40 | IN NO EVENT SHALL DAVID LOREN PARSONS BE LIABLE FOR ANY DIRECT, 41 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 42 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 43 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 45 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 47 | OF THE POSSIBILITY OF SUCH DAMAGE. 48 | -------------------------------------------------------------------------------- /discount/toc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * toc -- spit out a table of contents based on header blocks 3 | * 4 | * Copyright (C) 2008 Jjgod Jiang, David L Parsons. 5 | * The redistribution terms are provided in the COPYRIGHT file that must 6 | * be distributed with this source code. 7 | */ 8 | #include "config.h" 9 | #include 10 | #include 11 | #include 12 | 13 | #include "cstring.h" 14 | #include "markdown.h" 15 | #include "amalloc.h" 16 | 17 | /* write an header index 18 | */ 19 | int 20 | mkd_toc(Document *p, char **doc) 21 | { 22 | Paragraph *tp, *srcp; 23 | int last_hnumber = 0; 24 | Cstring res; 25 | 26 | CREATE(res); 27 | RESERVE(res, 100); 28 | 29 | *doc = 0; 30 | 31 | if ( !(p && p->ctx) ) return -1; 32 | if ( ! (p->ctx->flags & TOC) ) return 0; 33 | 34 | for ( tp = p->code; tp ; tp = tp->next ) { 35 | if ( tp->typ == SOURCE ) { 36 | for ( srcp = tp->down; srcp; srcp = srcp->next ) { 37 | if ( srcp->typ == HDR && srcp->text ) { 38 | 39 | if ( last_hnumber == srcp->hnumber ) 40 | Csprintf(&res, "%*s\n", srcp->hnumber, ""); 41 | else while ( last_hnumber > srcp->hnumber ) { 42 | Csprintf(&res, "%*s\n%*s\n", 43 | last_hnumber, "", 44 | last_hnumber-1,""); 45 | --last_hnumber; 46 | } 47 | 48 | while ( srcp->hnumber > last_hnumber ) { 49 | Csprintf(&res, "\n%*s
\n", 64 | last_hnumber, "", last_hnumber, ""); 65 | --last_hnumber; 66 | } 67 | /* HACK ALERT! HACK ALERT! HACK ALERT! */ 68 | *doc = T(res); /* we know that a T(Cstring) is a character pointer */ 69 | /* so we can simply pick it up and carry it away, */ 70 | return S(res); /* leaving the husk of the Ctring on the stack */ 71 | /* END HACK ALERT */ 72 | } 73 | 74 | 75 | /* write an header index 76 | */ 77 | int 78 | mkd_generatetoc(Document *p, FILE *out) 79 | { 80 | char *buf = 0; 81 | int sz = mkd_toc(p, &buf); 82 | int ret = EOF; 83 | 84 | if ( sz > 0 ) 85 | ret = fwrite(buf, sz, 1, out); 86 | 87 | if ( buf ) free(buf); 88 | 89 | return ret; 90 | } 91 | -------------------------------------------------------------------------------- /discount/amalloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * debugging malloc()/realloc()/calloc()/free() that attempts 3 | * to keep track of just what's been allocated today. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #define MAGIC 0x1f2e3d4c 10 | 11 | struct alist { int magic, size; struct alist *next, *last; }; 12 | 13 | static struct alist list = { 0, 0, 0, 0 }; 14 | 15 | static int mallocs=0; 16 | static int reallocs=0; 17 | static int frees=0; 18 | 19 | void * 20 | acalloc(int size, int count) 21 | { 22 | struct alist *ret = calloc(size + sizeof(struct alist), count); 23 | 24 | if ( ret ) { 25 | ret->magic = MAGIC; 26 | ret->size = size * count; 27 | if ( list.next ) { 28 | ret->next = list.next; 29 | ret->last = &list; 30 | ret->next->last = ret; 31 | list.next = ret; 32 | } 33 | else { 34 | ret->last = ret->next = &list; 35 | list.next = list.last = ret; 36 | } 37 | ++mallocs; 38 | return ret+1; 39 | } 40 | return 0; 41 | } 42 | 43 | 44 | void* 45 | amalloc(int size) 46 | { 47 | return acalloc(size,1); 48 | } 49 | 50 | 51 | void 52 | afree(void *ptr) 53 | { 54 | struct alist *p2 = ((struct alist*)ptr)-1; 55 | 56 | if ( p2->magic == MAGIC ) { 57 | p2->last->next = p2->next; 58 | p2->next->last = p2->last; 59 | ++frees; 60 | free(p2); 61 | } 62 | else 63 | free(ptr); 64 | } 65 | 66 | 67 | void * 68 | arealloc(void *ptr, int size) 69 | { 70 | struct alist *p2 = ((struct alist*)ptr)-1; 71 | struct alist save; 72 | 73 | if ( p2->magic == MAGIC ) { 74 | save.next = p2->next; 75 | save.last = p2->last; 76 | p2 = realloc(p2, sizeof(*p2) + size); 77 | 78 | if ( p2 ) { 79 | p2->size = size; 80 | p2->next->last = p2; 81 | p2->last->next = p2; 82 | ++reallocs; 83 | return p2+1; 84 | } 85 | else { 86 | save.next->last = save.last; 87 | save.last->next = save.next; 88 | return 0; 89 | } 90 | } 91 | return realloc(ptr, size); 92 | } 93 | 94 | 95 | void 96 | adump() 97 | { 98 | struct alist *p; 99 | 100 | 101 | for ( p = list.next; p && (p != &list); p = p->next ) { 102 | fprintf(stderr, "allocated: %d byte%s\n", p->size, (p->size==1) ? "" : "s"); 103 | fprintf(stderr, " [%.*s]\n", p->size, p+1); 104 | } 105 | 106 | if ( getenv("AMALLOC_STATISTICS") ) { 107 | fprintf(stderr, "%d malloc%s\n", mallocs, (mallocs==1)?"":"s"); 108 | fprintf(stderr, "%d realloc%s\n", reallocs, (reallocs==1)?"":"s"); 109 | fprintf(stderr, "%d free%s\n", frees, (frees==1)?"":"s"); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /discount/cstring.h: -------------------------------------------------------------------------------- 1 | /* two template types: STRING(t) which defines a pascal-style string 2 | * of element (t) [STRING(char) is the closest to the pascal string], 3 | * and ANCHOR(t) which defines a baseplate that a linked list can be 4 | * built up from. [The linked list /must/ contain a ->next pointer 5 | * for linking the list together with.] 6 | */ 7 | #ifndef _CSTRING_D 8 | #define _CSTRING_D 9 | 10 | #include 11 | #include 12 | 13 | #include "amalloc.h" 14 | 15 | /* expandable Pascal-style string. 16 | */ 17 | #define STRING(type) struct { type *text; int size, alloc; } 18 | 19 | #define CREATE(x) T(x) = (void*)(S(x) = (x).alloc = 0) 20 | #define EXPAND(x) (S(x)++)[(S(x) < (x).alloc) \ 21 | ? (T(x)) \ 22 | : (T(x) = T(x) ? realloc(T(x), sizeof T(x)[0] * ((x).alloc += 100)) \ 23 | : malloc(sizeof T(x)[0] * ((x).alloc += 100)) )] 24 | 25 | #define DELETE(x) ALLOCATED(x) ? (free(T(x)), S(x) = (x).alloc = 0) \ 26 | : ( S(x) = 0 ) 27 | #define CLIP(t,i,sz) \ 28 | ( ((i) >= 0) && ((sz) > 0) && (((i)+(sz)) <= S(t)) ) ? \ 29 | (memmove(&T(t)[i], &T(t)[i+sz], (S(t)-(i+sz)+1)*sizeof(T(t)[0])), \ 30 | S(t) -= (sz)) : -1 31 | 32 | #define RESERVE(x, sz) T(x) = ((x).alloc > S(x) + (sz) \ 33 | ? T(x) \ 34 | : T(x) \ 35 | ? realloc(T(x), sizeof T(x)[0] * ((x).alloc = 100+(sz)+S(x))) \ 36 | : malloc(sizeof T(x)[0] * ((x).alloc = 100+(sz)+S(x)))) 37 | #define SUFFIX(t,p,sz) \ 38 | memcpy(((S(t) += (sz)) - (sz)) + \ 39 | (T(t) = T(t) ? realloc(T(t), sizeof T(t)[0] * ((t).alloc += sz)) \ 40 | : malloc(sizeof T(t)[0] * ((t).alloc += sz))), \ 41 | (p), sizeof(T(t)[0])*(sz)) 42 | 43 | #define PREFIX(t,p,sz) \ 44 | RESERVE( (t), (sz) ); \ 45 | if ( S(t) ) { memmove(T(t)+(sz), T(t), S(t)); } \ 46 | memcpy( T(t), (p), (sz) ); \ 47 | S(t) += (sz) 48 | 49 | /* reference-style links (and images) are stored in an array 50 | */ 51 | #define T(x) (x).text 52 | #define S(x) (x).size 53 | #define ALLOCATED(x) (x).alloc 54 | 55 | /* abstract anchor type that defines a list base 56 | * with a function that attaches an element to 57 | * the end of the list. 58 | * 59 | * the list base field is named .text so that the T() 60 | * macro will work with it. 61 | */ 62 | #define ANCHOR(t) struct { t *text, *end; } 63 | #define E(t) ((t).end) 64 | 65 | #define ATTACH(t, p) ( T(t) ? ( (E(t)->next = (p)), (E(t) = (p)) ) \ 66 | : ( (T(t) = E(t) = (p)) ) ) 67 | 68 | typedef STRING(char) Cstring; 69 | 70 | extern void Csputc(int, Cstring *); 71 | extern int Csprintf(Cstring *, char *, ...); 72 | extern int Cswrite(Cstring *, char *, int); 73 | extern void Csreparse(Cstring *, char *, int, int); 74 | 75 | #endif/*_CSTRING_D*/ 76 | -------------------------------------------------------------------------------- /discount/mkdio.h: -------------------------------------------------------------------------------- 1 | #ifndef _MKDIO_D 2 | #define _MKDIO_D 3 | 4 | #include 5 | 6 | typedef void MMIOT; 7 | 8 | /* line builder for markdown() 9 | */ 10 | MMIOT *mkd_in(FILE*,int); /* assemble input from a file */ 11 | MMIOT *mkd_string(char*,int,int); /* assemble input from a buffer */ 12 | 13 | void mkd_basename(MMIOT*,char*); 14 | 15 | /* compilation, debugging, cleanup 16 | */ 17 | int mkd_compile(MMIOT*, int); 18 | int mkd_cleanup(MMIOT*); 19 | 20 | /* markup functions 21 | */ 22 | int mkd_dump(MMIOT*, FILE*, int, char*); 23 | int markdown(MMIOT*, FILE*, int); 24 | int mkd_line(char *, int, char **, int); 25 | void mkd_string_to_anchor(char *, int, int (*)(int,void*), void*); 26 | int mkd_xhtmlpage(MMIOT*,int,FILE*); 27 | 28 | /* header block access 29 | */ 30 | char* mkd_doc_title(MMIOT*); 31 | char* mkd_doc_author(MMIOT*); 32 | char* mkd_doc_date(MMIOT*); 33 | 34 | /* compiled data access 35 | */ 36 | int mkd_document(MMIOT*, char**); 37 | int mkd_toc(MMIOT*, char**); 38 | int mkd_css(MMIOT*, char **); 39 | int mkd_xml(char *, int, char **); 40 | 41 | /* write-to-file functions 42 | */ 43 | int mkd_generatehtml(MMIOT*,FILE*); 44 | int mkd_generatetoc(MMIOT*,FILE*); 45 | int mkd_generatexml(char *, int,FILE*); 46 | int mkd_generatecss(MMIOT*,FILE*); 47 | #define mkd_style mkd_generatecss 48 | int mkd_generateline(char *, int, FILE*, int); 49 | #define mkd_text mkd_generateline 50 | 51 | /* version#. 52 | */ 53 | extern char markdown_version[]; 54 | 55 | /* special flags for markdown() and mkd_text() 56 | */ 57 | #define MKD_NOLINKS 0x0001 /* don't do link processing, block tags */ 58 | #define MKD_NOIMAGE 0x0002 /* don't do image processing, block */ 59 | #define MKD_NOPANTS 0x0004 /* don't run smartypants() */ 60 | #define MKD_NOHTML 0x0008 /* don't allow raw html through AT ALL */ 61 | #define MKD_STRICT 0x0010 /* disable SUPERSCRIPT, RELAXED_EMPHASIS */ 62 | #define MKD_TAGTEXT 0x0020 /* process text inside an html tag; no 63 | * , no , no html or [] expansion */ 64 | #define MKD_NO_EXT 0x0040 /* don't allow pseudo-protocols */ 65 | #define MKD_CDATA 0x0080 /* generate code for xml ![CDATA[...]] */ 66 | #define MKD_NOTABLES 0x0400 /* disallow tables */ 67 | #define MKD_TOC 0x1000 /* do table-of-contents processing */ 68 | #define MKD_1_COMPAT 0x2000 /* compatability with MarkdownTest_1.0 */ 69 | #define MKD_AUTOLINK 0x4000 /* make http://foo.com link even without <>s */ 70 | #define MKD_SAFELINK 0x8000 /* paranoid check for link protocol */ 71 | #define MKD_EMBED MKD_NOLINKS|MKD_NOIMAGE|MKD_TAGTEXT 72 | 73 | /* special flags for mkd_in() and mkd_string() 74 | */ 75 | #define MKD_NOHEADER 0x0100 /* don't process header blocks */ 76 | #define MKD_TABSTOP 0x0200 /* expand tabs to 4 spaces */ 77 | 78 | 79 | #endif/*_MKDIO_D*/ 80 | -------------------------------------------------------------------------------- /discount/tests/tables.t: -------------------------------------------------------------------------------- 1 | ./echo "tables" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | if [ "$3" = "$Q" ]; then 18 | ./echo " ok" 19 | else 20 | ./echo " FAILED" 21 | ./echo "wanted: $3" 22 | ./echo "got : $Q" 23 | rc=1 24 | fi 25 | } 26 | 27 | 28 | try 'single-column table' \ 29 | '|hello 30 | |----- 31 | |sailor' \ 32 | ' 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
hello
sailor
' 46 | 47 | 48 | try 'two-column table' \ 49 | ' 50 | a | b 51 | -----|------ 52 | hello|sailor' \ 53 | ' 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
a b
hellosailor
' 67 | 68 | try 'three-column table' \ 69 | 'a|b|c 70 | -|-|- 71 | hello||sailor'\ 72 | ' 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 |
abc
hellosailor
' 88 | 89 | try 'two-column table with empty cells' \ 90 | ' 91 | a | b 92 | -----|------ 93 | hello| 94 | |sailor' \ 95 | ' 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |
a b
hello
sailor
' 113 | 114 | try 'two-column table with alignment' \ 115 | ' 116 | a | b 117 | ----:|:----- 118 | hello|sailor' \ 119 | ' 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 |
a b
hellosailor
' 133 | 134 | try 'table with extra data column' \ 135 | ' 136 | a | b 137 | -----|------ 138 | hello|sailor|boy' \ 139 | ' 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 |
a b
hellosailor|boy
' 153 | 154 | 155 | try -fnotables 'tables with -fnotables' \ 156 | 'a|b 157 | -|- 158 | hello|sailor' \ 159 | '

a|b 160 | –|– 161 | hello|sailor

' 162 | 163 | 164 | exit $rc 165 | -------------------------------------------------------------------------------- /discount/tests/list.t: -------------------------------------------------------------------------------- 1 | ./echo "lists" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | if [ "$3" = "$Q" ]; then 18 | ./echo " ok" 19 | else 20 | ./echo " FAILED" 21 | ./echo "wanted: $3" 22 | ./echo "got : $Q" 23 | rc=1 24 | fi 25 | } 26 | 27 | try 'two separated items' \ 28 | ' * A 29 | 30 | * B' \ 31 | '
    32 |
  • A

  • 33 |
  • B

  • 34 |
' 35 | 36 | try 'two adjacent items' \ 37 | ' * A 38 | * B' \ 39 | '
    40 |
  • A
  • 41 |
  • B
  • 42 |
' 43 | 44 | 45 | try 'two adjacent items, then space' \ 46 | ' * A 47 | * B 48 | 49 | space, the final frontier' \ 50 | '
    51 |
  • A
  • 52 |
  • B
  • 53 |
54 | 55 | 56 |

space, the final frontier

' 57 | 58 | try 'nested lists (1)' \ 59 | ' * 1. Sub (list) 60 | 2. Two (items) 61 | 3. Here' \ 62 | '
    63 |
    1. 64 |
    2. Sub (list)
    3. 65 |
    4. Two (items)
    5. 66 |
    6. Here
    7. 67 |
    68 |
  • 69 |
' 70 | 71 | try 'nested lists (2)' \ 72 | ' * A (list) 73 | 74 | 1. Sub (list) 75 | 2. Two (items) 76 | 3. Here 77 | 78 | Here 79 | * B (list)' \ 80 | '
    81 |
  • A (list)

    82 | 83 |
      84 |
    1. Sub (list)
    2. 85 |
    3. Two (items)
    4. 86 |
    5. Here
    6. 87 |
    88 | 89 | 90 |

    Here

  • 91 |
  • B (list)
  • 92 |
' 93 | 94 | try 'list inside blockquote' \ 95 | '>A (list) 96 | > 97 | >1. Sub (list) 98 | >2. Two (items) 99 | >3. Here' \ 100 | '

A (list)

101 | 102 |
    103 |
  1. Sub (list)
  2. 104 |
  3. Two (items)
  4. 105 |
  5. Here
  6. 106 |
107 |
' 108 | 109 | try 'blockquote inside list' \ 110 | ' * A (list) 111 | 112 | > quote 113 | > me 114 | 115 | dont quote me' \ 116 | '
    117 |
  • A (list)

    118 | 119 |

    quote 120 | me

    121 | 122 |

    dont quote me

  • 123 |
' 124 | 125 | try 'empty list' \ 126 | ' 127 | - 128 | 129 | - 130 | ' \ 131 | '
    132 |
  • 133 |
  • 134 |
' 135 | 136 | 137 | if ./markdown -V | grep DL_TAG >/dev/null; then 138 | 139 | try 'dl followed by non-dl' \ 140 | '=a= 141 | test 142 | 2. here' \ 143 | '
144 |
a
145 |
test
146 |
147 | 148 |
    149 |
  1. here
  2. 150 |
' 151 | 152 | try 'non-dl followed by dl' \ 153 | '1. hello 154 | =sailor= 155 | hi!' \ 156 | '
    157 |
  1. hello
  2. 158 |
159 | 160 | 161 |
162 |
sailor
163 |
hi!
164 |
' 165 | 166 | fi 167 | 168 | exit $rc 169 | -------------------------------------------------------------------------------- /discount/Makefile.in: -------------------------------------------------------------------------------- 1 | CC=@CC@ -I. -L. 2 | AR=@AR@ 3 | RANLIB=@RANLIB@ 4 | 5 | BINDIR=@exedir@ 6 | MANDIR=@mandir@ 7 | LIBDIR=@libdir@ 8 | INCDIR=@prefix@/include 9 | 10 | PGMS=markdown 11 | SAMPLE_PGMS=mkd2html makepage 12 | @THEME@SAMPLE_PGMS+= theme 13 | MKDLIB=libmarkdown.a 14 | OBJS=mkdio.o markdown.o dumptree.o generate.o \ 15 | resource.o docheader.o version.o toc.o css.o \ 16 | xml.o Csio.o xmlpage.o @AMALLOC@ 17 | 18 | all: $(PGMS) $(SAMPLE_PGMS) 19 | 20 | install: $(PGMS) 21 | @INSTALL_PROGRAM@ $(PGMS) $(DESTDIR)/$(BINDIR) 22 | @INSTALL_DATA@ $(MKDLIB) $(DESTDIR)/$(LIBDIR) 23 | @INSTALL_DATA@ mkdio.h $(DESTDIR)/$(INCDIR) 24 | 25 | install.everything: install install.samples install.man 26 | 27 | install.samples: $(SAMPLE_PGMS) install 28 | @INSTALL_PROGRAM@ $(SAMPLE_PGMS) $(DESTDIR)/$(BINDIR) 29 | @INSTALL_DIR@ $(DESTDIR)/$(MANDIR)/man1 30 | @INSTALL_DATA@ theme.1 $(DESTDIR)/$(MANDIR)/man1 31 | 32 | install.man: 33 | @INSTALL_DIR@ $(DESTDIR)/$(MANDIR)/man3 34 | @INSTALL_DATA@ mkd-functions.3 markdown.3 mkd-line.3 $(DESTDIR)/$(MANDIR)/man3 35 | for x in mkd_line mkd_generateline; do \ 36 | ( echo '.\"' ; echo ".so man3/mkd-line.3" ) > $(DESTDIR)/$(MANDIR)/man3/$$x.3;\ 37 | done 38 | for x in mkd_in mkd_string; do \ 39 | ( echo '.\"' ; echo ".so man3/markdown.3" ) > $(DESTDIR)/$(MANDIR)/man3/$$x.3;\ 40 | done 41 | for x in mkd_compile mkd_css mkd_generatecss mkd_generatehtml mkd_cleanup mkd_doc_title mkd_doc_author mkd_doc_date; do \ 42 | ( echo '.\"' ; echo ".so man3/mkd-functions.3" ) > $(DESTDIR)/$(MANDIR)/man3/$$x.3; \ 43 | done 44 | @INSTALL_DIR@ $(DESTDIR)/$(MANDIR)/man7 45 | @INSTALL_DATA@ markdown.7 mkd-extensions.7 $(DESTDIR)/$(MANDIR)/man7 46 | @INSTALL_DIR@ $(DESTDIR)/$(MANDIR)/man1 47 | @INSTALL_DATA@ markdown.1 $(DESTDIR)/$(MANDIR)/man1 48 | 49 | install.everything: install install.man 50 | 51 | version.o: version.c VERSION 52 | $(CC) -DVERSION=\"`cat VERSION`\" -c version.c 53 | 54 | markdown: main.o $(MKDLIB) 55 | $(CC) -o markdown main.o -lmarkdown @LIBS@ 56 | 57 | # example programs 58 | @THEME@theme: theme.o $(MKDLIB) mkdio.h 59 | @THEME@ $(CC) -o theme theme.o -lmarkdown @LIBS@ 60 | 61 | 62 | mkd2html: mkd2html.o $(MKDLIB) mkdio.h 63 | $(CC) -o mkd2html mkd2html.o -lmarkdown @LIBS@ 64 | 65 | makepage: makepage.c $(MKDLIB) mkdio.h 66 | $(CC) -o makepage makepage.c -lmarkdown @LIBS@ 67 | 68 | main.o: main.c mkdio.h config.h 69 | $(CC) -I. -c main.c 70 | 71 | $(MKDLIB): $(OBJS) 72 | $(AR) crv $(MKDLIB) $(OBJS) 73 | $(RANLIB) $(MKDLIB) 74 | 75 | test: $(PGMS) echo cols 76 | @for x in tests/*.t; do \ 77 | sh $$x || exit 1; \ 78 | done 79 | 80 | cols: tools/cols.c 81 | $(CC) -o cols tools/cols.c 82 | echo: tools/echo.c 83 | $(CC) -o echo tools/echo.c 84 | 85 | clean: 86 | rm -f $(PGMS) $(SAMPLE_PGMS) *.o $(MKDLIB) 87 | 88 | distclean spotless: clean 89 | rm -f @GENERATED_FILES@ @CONFIGURE_FILES@ 90 | 91 | markdown.o: markdown.c config.h cstring.h markdown.h 92 | generate.o: generate.c config.h cstring.h markdown.h 93 | dumptree.o: dumptree.c cstring.h markdown.h 94 | mkdio.o: mkdio.c mkdio.h cstring.h config.h 95 | xmlpage.o: xmlpage.c mkdio.h cstring.h config.h 96 | toc.o: toc.c mkdio.h cstring.h config.h 97 | -------------------------------------------------------------------------------- /discount/markdown.1.in: -------------------------------------------------------------------------------- 1 | .\" %A% 2 | .\" 3 | .Dd January 7, 2008 4 | .Dt MARKDOWN 1 5 | .Os MASTODON 6 | .Sh NAME 7 | .Nm markdown 8 | .Nd text to html conversion tool 9 | .Sh SYNOPSIS 10 | .Nm 11 | .Op Fl d 12 | .Op Fl T 13 | .Op Fl V 14 | .Op Fl b Ar url-base 15 | .Op Fl F Pa bitmap 16 | .Op Fl f Ar flags 17 | .Op Fl o Pa file 18 | .Op Fl s Pa text 19 | .Op Fl t Pa text 20 | .Op Pa textfile 21 | .Sh DESCRIPTION 22 | The 23 | .Nm 24 | utility reads the 25 | .Xr markdown 7 Ns -formatted 26 | .Pa textfile 27 | .Pq or stdin if not specified, 28 | compiles it, and writes the html output 29 | to stdout. 30 | .Pp 31 | The options are as follows: 32 | .Bl -tag -width "-o file" 33 | .It Fl b Ar url-base 34 | Links in source begining with / will be prefixed with 35 | .Ar url-base 36 | in the output. 37 | .It Fl d 38 | Instead of writing the html file, dump a parse 39 | tree to stdout. 40 | .It Fl f Ar flags 41 | Set or clear various translation flags. The flags 42 | are in a comma-delimited list, with an optional 43 | .Ar + 44 | (set) prefix on each flag. 45 | .Bl -tag -width "NOHEADER" 46 | .It Ar noimage 47 | Don't allow image tags. 48 | .It Ar nolinks 49 | Don't allow links. 50 | .It Ar nohtml 51 | Don't allow 52 | .B any 53 | embedded html. 54 | .It Ar cdata 55 | Generate valid XML output. 56 | .It Ar noheader 57 | Do not process pandoc headers. 58 | .It Ar notables 59 | Do not process Markdown Extra-style tables. 60 | .It Ar tabstops 61 | Use markdown-standard 4-space tabstops. 62 | @STRICT@.It Ar strict 63 | @STRICT@Disable superscript and relaxed emphasis. 64 | @STRICT@.It Ar relax 65 | @STRICT@Enable superscript and relaxed emphasis (this is the default.) 66 | .It Ar toc 67 | Enable table-of-contents support 68 | .It Ar 1.0 69 | Revert to Markdown 1.0 compatability. 70 | .El 71 | .Pp 72 | As an example, the option 73 | .Fl f Ar nolinks,quot 74 | tells 75 | .Nm 76 | to not allow \
0 if an error occurs. 122 | .Sh SEE ALSO 123 | .Xr markdown 3 , 124 | .Xr markdown 7 , 125 | .Xr mkd-extensions 7 . 126 | .Sh AUTHOR 127 | .An David Parsons 128 | .Pq Li orc@pell.chi.il.us 129 | -------------------------------------------------------------------------------- /discount/markdown.3: -------------------------------------------------------------------------------- 1 | .\" 2 | .Dd December 20, 2007 3 | .Dt MARKDOWN 3 4 | .Os Mastodon 5 | .Sh NAME 6 | .Nm markdown 7 | .Nd process Markdown documents 8 | .Sh LIBRARY 9 | Markdown 10 | .Pq libmarkdown , -lmarkdown 11 | .Sh SYNOPSIS 12 | .Fd #include 13 | .Ft MMIOT 14 | .Fn *mkd_in "FILE *input" 15 | .Ft MMIOT 16 | .Fn *mkd_string "char *string" "int size" 17 | .Ft int 18 | .Fn markdown "MMIOT *doc" "FILE *output" "int flags" 19 | .Sh DESCRIPTION 20 | These functions 21 | convert 22 | .Em Markdown 23 | documents and strings into HTML. 24 | .Fn markdown 25 | processes an entire document, while 26 | .Fn mkd_text 27 | processes a single string. 28 | .Pp 29 | To process a file, you pass a FILE* to 30 | .Fn mkd_in , 31 | and if it returns a nonzero value you pass that in to 32 | .Fn markdown , 33 | which then writes the converted document to the specified 34 | .Em FILE* . 35 | If your input has already been written into a string (generated 36 | input or a file opened 37 | with 38 | .Xr mmap 2 ) 39 | you can feed that string to 40 | .Fn mkd_string 41 | and pass its return value to 42 | .Fn markdown. 43 | .Pp 44 | .Fn Markdown 45 | accepts the following flag values (or-ed together if needed) 46 | to restrict how it processes input: 47 | .Bl -tag -width MKD_SAFELINK -compact 48 | .It Ar MKD_NOIMAGE 49 | Do not process `![]' and 50 | remove 51 | .Em \ 52 | tags from the output. 53 | .It Ar MKD_NOLINKS 54 | Do not process `[]' and remove 55 | .Em \ 56 | tags from the output. 57 | .It Ar MKD_NOPANTS 58 | Do not do Smartypants-style mangling of quotes, dashes, or ellipses. 59 | .It Ar MKD_STRICT 60 | Disable superscript and relaxed emphasis processing (if they are configured; 61 | otherwise it's a no-op.) 62 | .\" .It Ar MKD_QUOT 63 | .\" Expand 64 | .\" .Ar \&" 65 | .\" to \&". 66 | .It Ar MKD_NOHEADER 67 | Do not attempt to parse any Pandoc-style headers. 68 | .It Ar MKD_TABSTOP 69 | When reading documents, expand tabs to 70 | .Em 4 71 | spaces instead of whatever 72 | .Nm 73 | was originally configured for. 74 | .It Ar MKD_TOC 75 | Label all headers for use with the 76 | .Fn mkd_generatetoc 77 | and 78 | .Fn mkd_toc 79 | functions. 80 | .It Ar MKD_1_COMPAT 81 | MarkdownTest_1.0 compatability flag; trim trailing spaces from the 82 | first line of code blocks and disable implicit reference links. 83 | .It Ar MKD_AUTOLINK 84 | Greedily urlify links -- if 85 | .Em MKD_AUTOLINK 86 | is set, urls will be converted into hyperlinks even if they 87 | aren't encased in 88 | .Em <> . 89 | .It Ar MKD_SAFELINK 90 | Don't make hyperlinks from 91 | .Em [][] 92 | links that have unknown url types. 93 | .It Ar MKD_NOTABLES 94 | Don't process tables. 95 | .El 96 | .Sh RETURN VALUES 97 | .Fn markdown 98 | returns 0 on success, 1 on failure. 99 | The 100 | .Fn mkd_in 101 | and 102 | .Fn mkd_string 103 | functions return a MMIOT* on success, null on failure. 104 | .Sh SEE ALSO 105 | .Xr markdown 1 , 106 | .Xr mkd-functions 3 , 107 | .Xr mkd-line 3 , 108 | .Xr markdown 7 , 109 | .Xr mkd-extensions 7 , 110 | .Xr mmap 2 . 111 | .Pp 112 | http://daringfireball.net/projects/markdown/syntax 113 | .Sh BUGS 114 | Error handling is minimal at best. 115 | .Pp 116 | The 117 | .Ar MMIOT 118 | created by 119 | .Fn mkd_string 120 | is deleted by the 121 | .Nm 122 | function. 123 | 124 | -------------------------------------------------------------------------------- /discount/theme.1: -------------------------------------------------------------------------------- 1 | .\" %A% 2 | .\" 3 | .Dd January 23, 2008 4 | .Dt THEME 1 5 | .Os MASTODON 6 | .Sh NAME 7 | .Nm theme 8 | .Nd create a web page from a template file 9 | .Sh SYNOPSIS 10 | .Nm 11 | .Op Fl d Pa root 12 | .Op Fl f 13 | .Op Fl o Pa file 14 | .Op Fl p Pa pagename 15 | .Op Fl t Pa template 16 | .Op Fl V 17 | .Op Pa textfile 18 | .Sh DESCRIPTION 19 | The 20 | .Nm 21 | utility takes a 22 | .Xr markdown 7 Ns -formatted 23 | .Pa textfile 24 | .Pq or stdin if not specified, 25 | compiles it, and combines it with a 26 | .Em template 27 | .Po 28 | .Pa page.theme 29 | by default 30 | .Pc 31 | to produce a web page. If a path to the 32 | template is not specified, 33 | .Nm 34 | looks for 35 | .Pa page.theme 36 | in the current directory, then each parent directory up to the 37 | .Pa "document root" 38 | .Po 39 | set with 40 | .Fl d 41 | or, if unset, the 42 | .Em "root directory" 43 | of the system. 44 | .Pc 45 | If 46 | .Pa page.theme 47 | is found, 48 | .Nm 49 | copies it to the output, looking for 50 | .Em "" 51 | html tags and processing the embedded 52 | .Ar action 53 | as appropriate. 54 | .Pp 55 | .Nm 56 | processes the following actions: 57 | .Bl -tag -width "include(" 58 | .It Ar author 59 | Prints the author name(s) from the 60 | .Xr mkd_doc_author 3 61 | function. 62 | .It Ar body 63 | Prints the formatted 64 | .Xr markdown 7 65 | input file. 66 | .It Ar date 67 | Prints the date returned by 68 | .Xr mkd_doc_date 3 69 | or, if none, the 70 | date the input file was last modified. 71 | .It Ar dir 72 | Prints the directory part of the pagename 73 | .It Ar include Ns Pq Pa file 74 | Prints the contents of 75 | .Pa file . 76 | .Xr Markdown 7 77 | translation will 78 | .Em NOT 79 | be done on this file. 80 | .It Ar source 81 | The filename part of the pagename. 82 | .It Ar style 83 | Print any stylesheets 84 | .Pq see Xr mkd-extensions 7 85 | found in the input file. 86 | .It Ar title 87 | Print the title returned by 88 | .Xr mkd_doc_title 3 , 89 | or, if that does not exist, the source filename. 90 | .It Ar version 91 | Print the version of 92 | .Xr discount 7 93 | that this copy of theme was compiled with. 94 | .El 95 | .Pp 96 | If input is coming from a file and the output was not set with the 97 | .Ar o 98 | option, 99 | .Nm writes the output to 100 | .Pa file-sans-text.html 101 | .Pq if 102 | .Ar file 103 | has a 104 | .Pa .text 105 | suffix, that will be stripped off and replaced with 106 | .Pa .html ; 107 | otherwise a 108 | .Pa .html 109 | will be appended to the end of the filename.) 110 | .Pp 111 | The options are as follows: 112 | .Bl -tag -width "-o file" 113 | .It Fl d Pa root 114 | Set the 115 | .Em "document root" 116 | to 117 | .Ar root 118 | .It Fl f 119 | Forcibly overwrite existing html files. 120 | .It Fl o Pa filename 121 | Write the output to 122 | .Ar filename . 123 | .It Fl p Ar path 124 | Set the pagename to 125 | .Ar path . 126 | .It Fl t Ar filename 127 | Use 128 | .Ar filename 129 | as the template file. 130 | .El 131 | .Sh RETURN VALUES 132 | The 133 | .Nm 134 | utility exits 0 on success, and >0 if an error occurs. 135 | .Sh SEE ALSO 136 | .Xr markdown 1 , 137 | .Xr markdown 3 , 138 | .Xr markdown 7 , 139 | .Xr mkd-extensions 7 . 140 | .Sh AUTHOR 141 | .An David Parsons 142 | .Pq Li orc@pell.chi.il.us 143 | -------------------------------------------------------------------------------- /discount/tests/linkylinky.t: -------------------------------------------------------------------------------- 1 | ./echo "embedded links" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | ./echo -n " $1" '..................................' | ./cols 36 14 | 15 | Q=`./echo "$2" | ./markdown $FLAGS` 16 | 17 | 18 | if [ "$3" = "$Q" ]; then 19 | ./echo " ok" 20 | else 21 | ./echo " FAILED" 22 | ./echo "wanted: $3" 23 | ./echo "got : $Q" 24 | rc=1 25 | fi 26 | } 27 | 28 | try 'url contains &' '[hehehe](u&rl)' '

hehehe

' 29 | try 'url contains +' '[hehehe](u+rl)' '

hehehe

' 30 | try 'url contains "' '[hehehe](u"rl)' '

hehehe

' 31 | try 'url contains <' '[hehehe](uhehehe

' 32 | try 'url contains whitespace' '[ha](r u)' '

ha

' 33 | 34 | try 'url contains whitespace & title' \ 35 | '[hehehe](r u "there")' \ 36 | '

hehehe

' 37 | 38 | try 'url contains escaped )' \ 39 | '[hehehe](u\))' \ 40 | '

hehehe

' 41 | 42 | try 'image label contains <' \ 43 | '![hehe<he<he

' 45 | 46 | try 'image label contains >' \ 47 | '![he>he>he](url)' \ 48 | '

he>he>he

' 49 | 50 | try 'sloppy context link' \ 51 | '[heh]( url "how about it?" )' \ 52 | '

heh

' 53 | 54 | try 'footnote urls formed properly' \ 55 | '[hehehe]: hohoho "ha ha" 56 | 57 | [hehehe][]' \ 58 | '

hehehe

' 59 | 60 | try 'linky-like []s work' \ 61 | '[foo]' \ 62 | '

[foo]

' 63 | 64 | try 'pseudo-protocol "id:"'\ 65 | '[foo](id:bar)' \ 66 | '

foo

' 67 | 68 | try 'pseudo-protocol "class:"' \ 69 | '[foo](class:bar)' \ 70 | '

foo

' 71 | 72 | try 'pseudo-protocol "abbr:"'\ 73 | '[foo](abbr:bar)' \ 74 | '

foo

' 75 | 76 | try 'nested [][]s' \ 77 | '[[z](y)](x)' \ 78 | '

[z](y)

' 79 | 80 | try 'empty [][] tags' \ 81 | '[![][1]][2] 82 | 83 | [1]: image1 84 | [2]: image2' \ 85 | '

' 86 | 87 | try 'footnote cuddled up to text' \ 88 | 'foo 89 | [bar]:bar' \ 90 | '

foo

' 91 | 92 | try 'mid-paragraph footnote' \ 93 | 'talk talk talk talk 94 | [bar]: bar 95 | talk talk talk talk' \ 96 | '

talk talk talk talk 97 | talk talk talk talk

' 98 | 99 | try 'mid-blockquote footnote' \ 100 | '>blockquote! 101 | [footnote]: here! 102 | >blockquote!' \ 103 | '

blockquote! 104 | blockquote!

' 105 | 106 | try 'end-blockquote footnote' \ 107 | '>blockquote! 108 | >blockquote! 109 | [footnote]: here!' \ 110 | '

blockquote! 111 | blockquote!

' 112 | 113 | try 'start-blockquote footnote' \ 114 | '[footnote]: here! 115 | >blockquote! 116 | >blockquote!' \ 117 | '

blockquote! 118 | blockquote!

' 119 | 120 | try '[text] (text) not a link' \ 121 | '[test] (me)' \ 122 | '

[test] (me)

' 123 | 124 | exit $rc 125 | -------------------------------------------------------------------------------- /discount/resource.c: -------------------------------------------------------------------------------- 1 | /* markdown: a C implementation of John Gruber's Markdown markup language. 2 | * 3 | * Copyright (C) 2007 David L Parsons. 4 | * The redistribution terms are provided in the COPYRIGHT file that must 5 | * be distributed with this source code. 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "config.h" 15 | 16 | #include "cstring.h" 17 | #include "markdown.h" 18 | #include "amalloc.h" 19 | 20 | /* free a (single) line 21 | */ 22 | void 23 | ___mkd_freeLine(Line *ptr) 24 | { 25 | DELETE(ptr->text); 26 | free(ptr); 27 | } 28 | 29 | 30 | /* free a list of lines 31 | */ 32 | void 33 | ___mkd_freeLines(Line *p) 34 | { 35 | if (p->next) 36 | ___mkd_freeLines(p->next); 37 | ___mkd_freeLine(p); 38 | } 39 | 40 | 41 | /* bye bye paragraph. 42 | */ 43 | void 44 | ___mkd_freeParagraph(Paragraph *p) 45 | { 46 | if (p->next) 47 | ___mkd_freeParagraph(p->next); 48 | if (p->down) 49 | ___mkd_freeParagraph(p->down); 50 | if (p->text) 51 | ___mkd_freeLines(p->text); 52 | if (p->ident) 53 | free(p->ident); 54 | free(p); 55 | } 56 | 57 | 58 | /* bye bye footnote. 59 | */ 60 | void 61 | ___mkd_freefootnote(Footnote *f) 62 | { 63 | DELETE(f->tag); 64 | DELETE(f->link); 65 | DELETE(f->title); 66 | } 67 | 68 | 69 | /* bye bye footnotes. 70 | */ 71 | void 72 | ___mkd_freefootnotes(MMIOT *f) 73 | { 74 | int i; 75 | 76 | if ( f->footnotes ) { 77 | for (i=0; i < S(*f->footnotes); i++) 78 | ___mkd_freefootnote( &T(*f->footnotes)[i] ); 79 | DELETE(*f->footnotes); 80 | free(f->footnotes); 81 | } 82 | } 83 | 84 | 85 | /* initialize a new MMIOT 86 | */ 87 | void 88 | ___mkd_initmmiot(MMIOT *f, void *footnotes) 89 | { 90 | if ( f ) { 91 | memset(f, 0, sizeof *f); 92 | CREATE(f->in); 93 | CREATE(f->out); 94 | CREATE(f->Q); 95 | if ( footnotes ) 96 | f->footnotes = footnotes; 97 | else { 98 | f->footnotes = malloc(sizeof f->footnotes[0]); 99 | CREATE(*f->footnotes); 100 | } 101 | } 102 | } 103 | 104 | 105 | /* free the contents of a MMIOT, but leave the object alone. 106 | */ 107 | void 108 | ___mkd_freemmiot(MMIOT *f, void *footnotes) 109 | { 110 | if ( f ) { 111 | DELETE(f->in); 112 | DELETE(f->out); 113 | DELETE(f->Q); 114 | if ( f->footnotes != footnotes ) 115 | ___mkd_freefootnotes(f); 116 | memset(f, 0, sizeof *f); 117 | } 118 | } 119 | 120 | 121 | /* free lines up to an barrier. 122 | */ 123 | void 124 | ___mkd_freeLineRange(Line *anchor, Line *stop) 125 | { 126 | Line *r = anchor->next; 127 | 128 | if ( r != stop ) { 129 | while ( r && (r->next != stop) ) 130 | r = r->next; 131 | if ( r ) r->next = 0; 132 | ___mkd_freeLines(anchor->next); 133 | } 134 | anchor->next = 0; 135 | } 136 | 137 | 138 | /* clean up everything allocated in __mkd_compile() 139 | */ 140 | void 141 | mkd_cleanup(Document *doc) 142 | { 143 | if ( doc ) { 144 | if ( doc->ctx ) { 145 | ___mkd_freemmiot(doc->ctx, 0); 146 | free(doc->ctx); 147 | } 148 | 149 | if ( doc->code) ___mkd_freeParagraph(doc->code); 150 | if ( doc->headers ) ___mkd_freeLines(doc->headers); 151 | if ( T(doc->content) ) ___mkd_freeLines(T(doc->content)); 152 | memset(doc, 0, sizeof doc[0]); 153 | free(doc); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /discount/Plan9/markdown.1: -------------------------------------------------------------------------------- 1 | .TH MARKDOWN 1 2 | .SH NAME 3 | markdown \- convert Markdown text to HTML 4 | .SH SYNOPSIS 5 | .B markdown 6 | [ 7 | .B -dTV 8 | ] 9 | [ 10 | .BI -b " url-base 11 | ] 12 | [ 13 | .BI -F " bitmap 14 | ] 15 | [ 16 | .BI -f " flags 17 | ] 18 | [ 19 | .BI -o " ofile 20 | ] 21 | [ 22 | .BI -s " text 23 | ] 24 | [ 25 | .BI -t " text 26 | ] 27 | [ 28 | .I file 29 | ] 30 | .SH DESCRIPTION 31 | The 32 | .I markdown 33 | utility reads the 34 | .IR Markdown (6)-formatted 35 | .I file 36 | (or standard input) and writes its 37 | .SM HTML 38 | fragment representation on standard output. 39 | .PP 40 | The options are: 41 | .TF dfdoptions 42 | .TP 43 | .BI -b " url-base 44 | Links in source begining with 45 | .B / 46 | will be prefixed with 47 | .I url-base 48 | in the output. 49 | .TP 50 | .B -d 51 | Instead of printing an 52 | .SM HTML 53 | fragment, print a parse tree. 54 | .TP 55 | .BI -F " bitmap 56 | Set translation flags. 57 | .I Bitmap 58 | is a bit map of the various configuration options described in 59 | .IR markdown (2). 60 | .TP 61 | .BI -f " flags 62 | Set or clear various translation 63 | .IR flags , 64 | described below. 65 | .I Flags 66 | are in a comma-delimited list, with an optional 67 | .B + 68 | (set) prefix on each flag. 69 | .TP 70 | .BI -o " ofile 71 | Write the generated 72 | .SM HTML 73 | to 74 | .IR ofile . 75 | .TP 76 | .BI -s " text 77 | Use the 78 | .IR markdown (2) 79 | function to format the 80 | .I text 81 | on standard input. 82 | .TP 83 | .B -T 84 | Under 85 | .B -f 86 | .BR toc , 87 | print the table of contents as an unordered list before the usual 88 | .SM HTML 89 | output. 90 | .TP 91 | .BI -t " text 92 | Use 93 | .IR mkd_text 94 | (in 95 | .IR markdown (2)) 96 | to format 97 | .I text 98 | instead of processing standard input with 99 | .IR markdown . 100 | .TP 101 | .B -V 102 | Show version number and configuration. If the version includes the string 103 | .BR DL_TAG , 104 | .I markdown 105 | was configured with definition list support. If the version includes the string 106 | .BR HEADER , 107 | .I markdown 108 | was configured to support pandoc header blocks. 109 | .PD 110 | .SS TRANSLATION FLAGS 111 | The translation flags understood by 112 | .B -f 113 | are: 114 | .TF \ noheader 115 | .TP 116 | .B noimage 117 | Don't allow image tags. 118 | .TP 119 | .B nolinks 120 | Don't allow links. 121 | .TP 122 | .B nohtml 123 | Don't allow any embedded HTML. 124 | .TP 125 | .B cdata 126 | Generate valid XML output. 127 | .TP 128 | .B noheader 129 | Do not process pandoc headers. 130 | .TP 131 | .B notables 132 | Do not process the syntax extension for tables. 133 | .TP 134 | .B tabstops 135 | Use Markdown-standard 4-space tabstops. 136 | .TP 137 | .B strict 138 | Disable superscript and relaxed emphasis. 139 | .TP 140 | .B relax 141 | Enable superscript and relaxed emphasis (the default). 142 | .TP 143 | .B toc 144 | Enable table of contents support, generated from headings (in 145 | .IR markdown (6)) 146 | in the source. 147 | .TP 148 | .B 1.0 149 | Revert to Markdown 1.0 compatibility. 150 | .PD 151 | .PP 152 | For example, 153 | .B -f nolinks,quot 154 | tells 155 | .I markdown 156 | not to allow 157 | .B 158 | tags, and to expand double quotes. 159 | .SH SOURCE 160 | .B /sys/src/cmd/discount 161 | .SH SEE ALSO 162 | .IR markdown (2), 163 | .IR markdown (6) 164 | .PP 165 | http://daringfireball.net/projects/markdown/, 166 | ``Markdown''. 167 | .SH DIAGNOSTICS 168 | .I Markdown 169 | exits 0 on success and >0 if an error occurs. 170 | -------------------------------------------------------------------------------- /discount/tests/schiraldi.t: -------------------------------------------------------------------------------- 1 | ./echo "Bugs & misfeatures reported by Mike Schiraldi" 2 | 3 | rc=0 4 | MARKDOWN_FLAGS= 5 | 6 | try() { 7 | unset FLAGS 8 | case "$1" in 9 | -*) FLAGS=$1 10 | shift ;; 11 | esac 12 | 13 | S=`./echo -n "$1" '..................................' | ./cols 34` 14 | ./echo -n " $S " 15 | 16 | Q=`./echo "$2" | ./markdown $FLAGS` 17 | 18 | 19 | if [ "$3" = "$Q" ]; then 20 | ./echo "ok" 21 | else 22 | ./echo "FAILED" 23 | ./echo "wanted: $3" 24 | ./echo "got : $Q" 25 | rc=1 26 | fi 27 | } 28 | 29 | try -fnohtml 'breaks with -fnohtml' 'foo ' '

foo
30 |

' 31 | 32 | try 'links with trailing \)' \ 33 | '[foo](http://en.wikipedia.org/wiki/Link_(film\))' \ 34 | '

foo

' 35 | 36 | try -fautolink '(url) with -fautolink' \ 37 | '(http://tsfr.org)' \ 38 | '

(http://tsfr.org)

' 39 | 40 | try 'single #' \ 41 | '#' \ 42 | '

#

' 43 | 44 | try -frelax '* processing with -frelax' \ 45 | '2*4 = 8 * 1 = 2**3' \ 46 | '

2*4 = 8 * 1 = 2**3

' 47 | 48 | try -fnopants '[]() with a single quote mark' \ 49 | '[Poe'"'"'s law](http://rationalwiki.com/wiki/Poe'"'"'s_Law)' \ 50 | '

Poe'"'"'s law

' 51 | 52 | try -fautolink 'autolink url with escaped spaces' \ 53 | 'http://\(here\ I\ am\)' \ 54 | '

http://(here I am)

' 55 | 56 | try -fautolink 'autolink café_racer' \ 57 | 'http://en.wikipedia.org/wiki/café_racer' \ 58 | '

http://en.wikipedia.org/wiki/caf%C3%A9_racer

' 59 | 60 | try -fautolink 'autolink url with arguments' \ 61 | 'http://foo.bar?a&b=c' \ 62 | '

http://foo.bar?a&b=c

' 63 | 64 | try '\( escapes in []()' \ 65 | '[foo](http://a.com/\(foo\))' \ 66 | '

foo

' 67 | 68 | try -fautolink 'autolink url with escaped ()' \ 69 | 'http://a.com/\(foo\)' \ 70 | '

http://a.com/(foo)

' 71 | 72 | try -fautolink 'autolink url with escaped \' \ 73 | 'http://a.com/\\\)' \ 74 | '

http://a.com/\)

' 75 | 76 | try -fautolink 'autolink url with -' \ 77 | 'http://experts-exchange.com' \ 78 | '

http://experts-exchange.com

' 79 | 80 | try -fautolink 'autolink url with +' \ 81 | 'http://www67.wolframalpha.com/input/?i=how+old+was+jfk+jr+when+jfk+died' \ 82 | '

http://www67.wolframalpha.com/input/?i=how+old+was+jfk+jr+when+jfk+died

' 83 | 84 | try -fautolink 'autolink url with &' \ 85 | 'http://foo.bar?a&b=c' \ 86 | '

http://foo.bar?a&b=c

' 87 | 88 | 89 | try -fautolink 'autolink url with ,' \ 90 | 'http://www.spiegel.de/international/europe/0,1518,626171,00.html' \ 91 | '

http://www.spiegel.de/international/europe/0,1518,626171,00.html

' 92 | 93 | try -fautolink 'autolink url with : & ;' \ 94 | 'http://www.biblegateway.com/passage/?search=Matthew%205:29-30;&version=31;' \ 95 | '

http://www.biblegateway.com/passage/?search=Matthew%205:29-30;&version=31;

' 96 | 97 | exit $rc 98 | -------------------------------------------------------------------------------- /discount/dumptree.c: -------------------------------------------------------------------------------- 1 | /* markdown: a C implementation of John Gruber's Markdown markup language. 2 | * 3 | * Copyright (C) 2007 David L Parsons. 4 | * The redistribution terms are provided in the COPYRIGHT file that must 5 | * be distributed with this source code. 6 | */ 7 | #include 8 | #include "markdown.h" 9 | #include "cstring.h" 10 | #include "amalloc.h" 11 | 12 | struct frame { 13 | int indent; 14 | char c; 15 | }; 16 | 17 | typedef STRING(struct frame) Stack; 18 | 19 | static char * 20 | Pptype(int typ) 21 | { 22 | switch (typ) { 23 | case WHITESPACE: return "whitespace"; 24 | case CODE : return "code"; 25 | case QUOTE : return "quote"; 26 | case MARKUP : return "markup"; 27 | case HTML : return "html"; 28 | case DL : return "dl"; 29 | case UL : return "ul"; 30 | case OL : return "ol"; 31 | case LISTITEM : return "item"; 32 | case HDR : return "header"; 33 | case HR : return "hr"; 34 | case TABLE : return "table"; 35 | case SOURCE : return "source"; 36 | default : return "mystery node!"; 37 | } 38 | } 39 | 40 | static void 41 | pushpfx(int indent, char c, Stack *sp) 42 | { 43 | struct frame *q = &EXPAND(*sp); 44 | 45 | q->indent = indent; 46 | q->c = c; 47 | } 48 | 49 | 50 | static void 51 | poppfx(Stack *sp) 52 | { 53 | S(*sp)--; 54 | } 55 | 56 | 57 | static void 58 | changepfx(Stack *sp, char c) 59 | { 60 | char ch; 61 | 62 | if ( !S(*sp) ) return; 63 | 64 | ch = T(*sp)[S(*sp)-1].c; 65 | 66 | if ( ch == '+' || ch == '|' ) 67 | T(*sp)[S(*sp)-1].c = c; 68 | } 69 | 70 | 71 | static void 72 | printpfx(Stack *sp, FILE *f) 73 | { 74 | int i; 75 | char c; 76 | 77 | if ( !S(*sp) ) return; 78 | 79 | c = T(*sp)[S(*sp)-1].c; 80 | 81 | if ( c == '+' || c == '-' ) { 82 | fprintf(f, "--%c", c); 83 | T(*sp)[S(*sp)-1].c = (c == '-') ? ' ' : '|'; 84 | } 85 | else 86 | for ( i=0; i < S(*sp); i++ ) { 87 | if ( i ) 88 | fprintf(f, " "); 89 | fprintf(f, "%*s%c", T(*sp)[i].indent + 2, " ", T(*sp)[i].c); 90 | if ( T(*sp)[i].c == '`' ) 91 | T(*sp)[i].c = ' '; 92 | } 93 | fprintf(f, "--"); 94 | } 95 | 96 | 97 | static void 98 | dumptree(Paragraph *pp, Stack *sp, FILE *f) 99 | { 100 | int count; 101 | Line *p; 102 | int d; 103 | static char *Begin[] = { 0, "P", "center" }; 104 | 105 | while ( pp ) { 106 | if ( !pp->next ) 107 | changepfx(sp, '`'); 108 | printpfx(sp, f); 109 | 110 | d = fprintf(f, "[%s", Pptype(pp->typ)); 111 | if ( pp->ident ) 112 | d += fprintf(f, " %s", pp->ident); 113 | if ( pp->align ) 114 | d += fprintf(f, ", <%s>", Begin[pp->align]); 115 | 116 | for (count=0, p=pp->text; p; ++count, (p = p->next) ) 117 | ; 118 | 119 | if ( count ) 120 | d += fprintf(f, ", %d line%s", count, (count==1)?"":"s"); 121 | 122 | d += fprintf(f, "]"); 123 | 124 | if ( pp->down ) { 125 | pushpfx(d, pp->down->next ? '+' : '-', sp); 126 | dumptree(pp->down, sp, f); 127 | poppfx(sp); 128 | } 129 | else fputc('\n', f); 130 | pp = pp->next; 131 | } 132 | } 133 | 134 | 135 | int 136 | mkd_dump(Document *doc, FILE *out, int flags, char *title) 137 | { 138 | Stack stack; 139 | 140 | if (mkd_compile(doc, flags) ) { 141 | 142 | CREATE(stack); 143 | pushpfx(fprintf(out, "%s", title), doc->code->next ? '+' : '-', &stack); 144 | dumptree(doc->code, &stack, out); 145 | DELETE(stack); 146 | 147 | mkd_cleanup(doc); 148 | return 0; 149 | } 150 | return -1; 151 | } 152 | -------------------------------------------------------------------------------- /discount/configure.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # local options: ac_help is the help message that describes them 4 | # and LOCAL_AC_OPTIONS is the script that interprets them. LOCAL_AC_OPTIONS 5 | # is a script that's processed with eval, so you need to be very careful to 6 | # make certain that what you quote is what you want to quote. 7 | 8 | # load in the configuration file 9 | # 10 | ac_help='--enable-dl-tag Use the DL tag extension 11 | --enable-pandoc-header Use pandoc-style header blocks 12 | --enable-superscript A^B becomes AB 13 | --enable-amalloc Enable memory allocation debugging 14 | --relaxed-emphasis underscores aren'\''t special in the middle of words 15 | --with-tabstops=N Set tabstops to N characters (default is 4) 16 | --enable-div Enable >%id% divisions 17 | --enable-alpha-list Enable (a)/(b)/(c) lists 18 | --enable-all-features Turn on all stable optional features' 19 | 20 | LOCAL_AC_OPTIONS=' 21 | set=`locals $*`; 22 | if [ "$set" ]; then 23 | eval $set 24 | shift 1 25 | else 26 | ac_error=T; 27 | fi' 28 | 29 | locals() { 30 | K=`echo $1 | $AC_UPPERCASE` 31 | case "$K" in 32 | --RELAXED-EMPHAS*) 33 | echo RELAXED_EMPHASIS=T 34 | ;; 35 | --ENABLE-ALL|--ENABLE-ALL-FEATURES) 36 | echo WITH_DL_TAG=T 37 | echo RELAXED_EMPHASIS=T 38 | echo WITH_PANDOC_HEADER=T 39 | echo WITH_SUPERSCRIPT=T 40 | echo WITH_AMALLOC=T 41 | echo WITH_DIV=T 42 | #echo WITH_ALPHA_LIST=T 43 | ;; 44 | --ENABLE-*) enable=`echo $K | sed -e 's/--ENABLE-//' | tr '-' '_'` 45 | echo WITH_${enable}=T ;; 46 | esac 47 | } 48 | 49 | TARGET=markdown 50 | . ./configure.inc 51 | 52 | AC_INIT $TARGET 53 | 54 | AC_PROG_CC 55 | 56 | case "$AC_CC $AC_CFLAGS" in 57 | *-Wall*) AC_DEFINE 'while(x)' 'while( (x) != 0 )' 58 | AC_DEFINE 'if(x)' 'if( (x) != 0 )' ;; 59 | esac 60 | 61 | AC_PROG ar || AC_FAIL "$TARGET requires ar" 62 | AC_PROG ranlib 63 | 64 | AC_C_VOLATILE 65 | AC_C_CONST 66 | AC_SCALAR_TYPES 67 | AC_CHECK_BASENAME 68 | 69 | AC_CHECK_HEADERS sys/types.h pwd.h && AC_CHECK_FUNCS getpwuid 70 | 71 | if AC_CHECK_FUNCS srandom; then 72 | AC_DEFINE 'INITRNG(x)' 'srandom((unsigned int)x)' 73 | elif AC_CHECK_FUNCS srand; then 74 | AC_DEFINE 'INITRNG(x)' 'srand((unsigned int)x)' 75 | else 76 | AC_DEFINE 'INITRNG(x)' '(void)1' 77 | fi 78 | 79 | if AC_CHECK_FUNCS random; then 80 | AC_DEFINE 'COINTOSS()' '(random()&1)' 81 | elif AC_CHECK_FUNCS rand; then 82 | AC_DEFINE 'COINTOSS()' '(rand()&1)' 83 | else 84 | AC_DEFINE 'COINTOSS()' '1' 85 | fi 86 | 87 | if AC_CHECK_FUNCS strcasecmp; then 88 | : 89 | elif AC_CHECK_FUNCS stricmp; then 90 | AC_DEFINE strcasecmp stricmp 91 | else 92 | AC_FAIL "$TARGET requires either strcasecmp() or stricmp()" 93 | fi 94 | 95 | if AC_CHECK_FUNCS strncasecmp; then 96 | : 97 | elif AC_CHECK_FUNCS strnicmp; then 98 | AC_DEFINE strncasecmp strnicmp 99 | else 100 | AC_FAIL "$TARGET requires either strncasecmp() or strnicmp()" 101 | fi 102 | 103 | if AC_CHECK_FUNCS fchdir || AC_CHECK_FUNCS getcwd ; then 104 | AC_SUB 'THEME' '' 105 | else 106 | AC_SUB 'THEME' '#' 107 | fi 108 | 109 | if [ -z "$WITH_TABSTOPS" ]; then 110 | TABSTOP=4 111 | elif [ "$WITH_TABSTOPS" -eq 1 ]; then 112 | TABSTOP=8 113 | else 114 | TABSTOP=$WITH_TABSTOPS 115 | fi 116 | AC_DEFINE 'TABSTOP' $TABSTOP 117 | AC_SUB 'TABSTOP' $TABSTOP 118 | 119 | test -z "$WITH_SUPERSCRIPT" || AC_DEFINE 'SUPERSCRIPT' 1 120 | test -z "$RELAXED_EMPHASIS" || AC_DEFINE 'RELAXED_EMPHASIS' 1 121 | test -z "$WITH_DIV" || AC_DEFINE 'DIV_QUOTE' 1 122 | test -z "$WITH_ALPHA_LIST" || AC_DEFINE 'ALPHA_LIST' 1 123 | 124 | 125 | if [ "$WITH_AMALLOC" ]; then 126 | AC_DEFINE 'USE_AMALLOC' 1 127 | AC_SUB 'AMALLOC' 'amalloc.o' 128 | else 129 | AC_SUB 'AMALLOC' '' 130 | fi 131 | 132 | if [ "$RELAXED_EMPHASIS" -o "$WITH_SUPERSCRIPT" ]; then 133 | AC_SUB 'STRICT' '' 134 | else 135 | AC_SUB 'STRICT' '.\"' 136 | fi 137 | 138 | 139 | [ "$OS_FREEBSD" -o "$OS_DRAGONFLY" ] || AC_CHECK_HEADERS malloc.h 140 | 141 | [ "$WITH_DL_TAG" ] && AC_DEFINE 'DL_TAG_EXTENSION' '1' 142 | [ "$WITH_PANDOC_HEADER" ] && AC_DEFINE 'PANDOC_HEADER' '1' 143 | 144 | AC_OUTPUT Makefile version.c markdown.1 145 | -------------------------------------------------------------------------------- /discount/mkd2html.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mkd2html: parse a markdown input file and generate a web page. 3 | * 4 | * usage: mkd2html [options] filename 5 | * or mkd2html [options] < markdown > html 6 | * 7 | * options 8 | * -css css-file 9 | * -header line-to-add-to-
10 | * -footer line-to-add-before- 11 | * 12 | * example: 13 | * 14 | * mkd2html -cs /~orc/pages.css syntax 15 | * ( read syntax OR syntax.text, write syntax.html ) 16 | */ 17 | /* 18 | * Copyright (C) 2007 David L Parsons. 19 | * The redistribution terms are provided in the COPYRIGHT file that must 20 | * be distributed with this source code. 21 | */ 22 | #include "config.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #ifdef HAVE_BASENAME 28 | # ifdef HAVE_LIBGEN_H 29 | # include 30 | # else 31 | # include 32 | # endif 33 | #endif 34 | #include 35 | 36 | #include "mkdio.h" 37 | #include "cstring.h" 38 | #include "amalloc.h" 39 | 40 | char *pgm = "mkd2html"; 41 | 42 | #ifndef HAVE_BASENAME 43 | char * 44 | basename(char *path) 45 | { 46 | char *p; 47 | 48 | if (( p = strrchr(path, '/') )) 49 | return 1+p; 50 | return path; 51 | } 52 | #endif 53 | 54 | void 55 | fail(char *why, ...) 56 | { 57 | va_list ptr; 58 | 59 | va_start(ptr,why); 60 | fprintf(stderr, "%s: ", pgm); 61 | vfprintf(stderr, why, ptr); 62 | fputc('\n', stderr); 63 | va_end(ptr); 64 | exit(1); 65 | } 66 | 67 | 68 | void 69 | main(argc, argv) 70 | char **argv; 71 | { 72 | char *h; 73 | char *source = 0, *dest = 0; 74 | MMIOT *mmiot; 75 | int i; 76 | FILE *input, *output; 77 | STRING(char*) css, headers, footers; 78 | 79 | 80 | CREATE(css); 81 | CREATE(headers); 82 | CREATE(footers); 83 | pgm = basename(argv[0]); 84 | 85 | while ( argc > 2 ) { 86 | if ( strcmp(argv[1], "-css") == 0 ) { 87 | EXPAND(css) = argv[2]; 88 | argc -= 2; 89 | argv += 2; 90 | } 91 | else if ( strcmp(argv[1], "-header") == 0 ) { 92 | EXPAND(headers) = argv[2]; 93 | argc -= 2; 94 | argv += 2; 95 | } 96 | else if ( strcmp(argv[1], "-footer") == 0 ) { 97 | EXPAND(footers) = argv[2]; 98 | argc -= 2; 99 | argv += 2; 100 | } 101 | } 102 | 103 | 104 | if ( argc > 1 ) { 105 | char *p, *dot; 106 | 107 | source = malloc(strlen(argv[1]) + 6); 108 | dest = malloc(strlen(argv[1]) + 6); 109 | 110 | if ( !(source && dest) ) 111 | fail("out of memory allocating name buffers"); 112 | 113 | strcpy(source, argv[1]); 114 | if (( p = strrchr(source, '/') )) 115 | p = source; 116 | else 117 | ++p; 118 | 119 | if ( (input = fopen(source, "r")) == 0 ) { 120 | strcat(source, ".text"); 121 | if ( (input = fopen(source, "r")) == 0 ) 122 | fail("can't open either %s or %s", argv[1], source); 123 | } 124 | strcpy(dest, source); 125 | 126 | if (( dot = strrchr(dest, '.') )) 127 | *dot = 0; 128 | strcat(dest, ".html"); 129 | 130 | if ( (output = fopen(dest, "w")) == 0 ) 131 | fail("can't write to %s", dest); 132 | } 133 | else { 134 | input = stdin; 135 | output = stdout; 136 | } 137 | 138 | if ( (mmiot = mkd_in(input, 0)) == 0 ) 139 | fail("can't read %s", source ? source : "stdin"); 140 | 141 | if ( !mkd_compile(mmiot, 0) ) 142 | fail("couldn't compile input"); 143 | 144 | 145 | h = mkd_doc_title(mmiot); 146 | 147 | /* print a header */ 148 | 149 | fprintf(output, 150 | "\n" 151 | "\n" 152 | "\n" 153 | " \n", markdown_version); 154 | 155 | fprintf(output," "); 157 | 158 | for ( i=0; i < S(css); i++ ) 159 | fprintf(output, " \n", T(css)[i]); 162 | 163 | if ( h ) { 164 | fprintf(output," "); 165 | mkd_generateline(h, strlen(h), output, 0); 166 | fprintf(output, "\n"); 167 | } 168 | for ( i=0; i < S(headers); i++ ) 169 | fprintf(output, " %s\n", T(headers)[i]); 170 | fprintf(output, "\n" 171 | "\n"); 172 | 173 | /* print the compiled body */ 174 | 175 | mkd_generatehtml(mmiot, output); 176 | 177 | for ( i=0; i < S(footers); i++ ) 178 | fprintf(output, "%s\n", T(footers)[i]); 179 | 180 | fprintf(output, "\n" 181 | "\n"); 182 | 183 | mkd_cleanup(mmiot); 184 | exit(0); 185 | } 186 | -------------------------------------------------------------------------------- /discount/mkd-extensions.7: -------------------------------------------------------------------------------- 1 | .\" 2 | .Dd Dec 22, 2007 3 | .Dt MKD-EXTENSIONS 7 4 | .Os MASTODON 5 | .Sh NAME 6 | .Nm mkd-extensions 7 | .Nd Extensions to the Markdown text formatting syntax 8 | .Sh DESCRIPTION 9 | This version of markdown has been extended in a few ways by 10 | extending existing markup, creating new markup from scratch, 11 | and borrowing markup from other markup languages. 12 | .Ss Image dimensions 13 | Markdown embedded images have been extended to allow specifying 14 | the dimensions of the image by adding a new argument 15 | .Em =/height/x/width/ 16 | to the link description. 17 | .Pp 18 | The new image syntax is 19 | .nf 20 | ![alt text](image =/height/x/width/ "title") 21 | .fi 22 | .Ss pseudo-protocols 23 | Three pseudo-protocols have been added to links 24 | .Bl -tag -width XXXXX 25 | .It Ar id: 26 | The 27 | .Ar "alt text" 28 | is marked up and written to the output, wrapped with 29 | .Em "" 30 | and 31 | .Em "" . 32 | .It Ar class: 33 | The 34 | .Ar "alt text" 35 | is marked up and written to the output, wrapped with 36 | .Em "" 37 | and 38 | .Em "" . 39 | .It Ar raw: 40 | The 41 | .Ar title 42 | is written 43 | .Em -- with no further processing -- 44 | to the output. The 45 | .Ar "alt text" 46 | is discarded. 47 | .It Ar abbr: 48 | The 49 | .Ar "alt text" 50 | is marked up and written to the output, wrapped with 51 | .Em " 52 | and 53 | .Em "" . 54 | .El 55 | .Ss Pandoc headers 56 | If markdown was configured with 57 | .Ar --enable-pandoc-header , 58 | the markdown source document can have a 3-line 59 | .Xr Pandoc 60 | header in the format of 61 | .nf 62 | % title 63 | % author(s) 64 | % date 65 | .fi 66 | which will be made available to the 67 | .Fn mkd_doc_title , 68 | .Fn mkd_doc_author , 69 | and 70 | .Fn mkd_doc_date 71 | functions. 72 | .Ss Definition lists 73 | If markdown was configured with 74 | .Ar --enable-dl-tag , 75 | markup for definition lists is enabled. A definition list item 76 | is defined as 77 | .nf 78 | =tag= 79 | description 80 | .fi 81 | (that is a 82 | .Ar = , 83 | followed by text, another 84 | .Ar = , 85 | a newline, 4 spaces of intent, and then more text.) 86 | .Pp 87 | .Ss embedded stylesheets 88 | Stylesheets may be defined and modified in a 89 | .Em 96 | at the end of the line or a 97 | .Em 98 | at the beginning of a subsequent line. 99 | .Pp 100 | Be warned that style blocks work like footnote links -- no matter 101 | where you define them they are valid for the entire document. 102 | .Ss relaxed emphasis 103 | If markdown was configured with 104 | .Ar --relaxed-emphasis , 105 | the rules for emphasis are changed so that a single 106 | .Ar _ 107 | will 108 | .Em not 109 | count as a emphasis character if it's in the middle of a word. 110 | This is primarily for documenting code, if you don't wish to 111 | have to backquote all code references. 112 | .Ss alpha lists 113 | If markdown was configured with 114 | .Ar --enable-alpha-list , 115 | alphabetic lists (like regular numeric lists, but with alphabetic 116 | items) are supported. So: 117 | .nf 118 | a. this 119 | b. is 120 | c. an alphabetic 121 | d. list 122 | .fi 123 | will produce: 124 | .nf 125 |
    126 |
  1. this
  2. 127 |
  3. is
  4. 128 |
  5. an alphabetic
  6. 129 |
  7. list
  8. 130 |
131 | .fi 132 | .Ss tables 133 | .Ar PHP Markdown Extra -style 134 | tables are supported; input of the form 135 | .nf 136 | header|header 137 | ------|------ 138 | text | text 139 | .fi 140 | will produce: 141 | .nf 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 |
headerheader
texttext
156 | .fi 157 | The dashed line can also contain 158 | .Em : 159 | characters for formatting; if a 160 | .Em : 161 | is at the start of a column, it tells 162 | .Nm discount 163 | to align the cell contents to the left; if it's at the end, it 164 | aligns right, and if there's one at the start and at the 165 | end, it centers. 166 | .Sh AUTHOR 167 | David Parsons 168 | .%T http://www.pell.portland.or.us/~orc/ 169 | .Sh SEE ALSO 170 | .Xr markdown 1 , 171 | .Xr markdown 3 , 172 | .Xr mkd-functions 3 , 173 | .Xr mkd-line 3 , 174 | .Xr mkd-extensions 7 . 175 | .Pp 176 | .%T http://daringfireball.net/projects/markdown 177 | .Pp 178 | .%T http://michelf.com/projects/php-markdown 179 | -------------------------------------------------------------------------------- /discount/mkd-functions.3: -------------------------------------------------------------------------------- 1 | .\" 2 | .Dd January 18, 2008 3 | .Dt MKD_FUNCTIONS 3 4 | .Os Mastodon 5 | .Sh NAME 6 | .Nm mkd_functions 7 | .Nd access and process Markdown documents. 8 | .Sh LIBRARY 9 | Markdown 10 | .Pq libmarkdown , -lmarkdown 11 | .Sh SYNOPSIS 12 | .Fd #include 13 | .Ft int 14 | .Fn mkd_compile "MMIOT *document" "int flags" 15 | .Ft int 16 | .Fn mkd_css "MMIOT *document" "char **doc" 17 | .Ft int 18 | .Fn mkd_generatecss "MMIOT *document" "FILE *output" 19 | .Ft int 20 | .Fn mkd_document "MMIOT *document" "char **doc" 21 | .Ft int 22 | .Fn mkd_generatehtml "MMIOT *document" "FILE *output" 23 | .Ft int 24 | .Fn mkd_xhtmlpage "MMIOT *document" "int flags" "FILE *output" 25 | .Ft int 26 | .Fn mkd_toc "MMIOT *document" "char **doc" 27 | .Ft void 28 | .Fn mkd_generatetoc "MMIOT *document" "FILE *output" 29 | .Ft void 30 | .Fn mkd_cleanup "MMIOT*" 31 | .Ft char* 32 | .Fn mkd_doc_title "MMIOT*" 33 | .Ft char* 34 | .Fn mkd_doc_author "MMIOT*" 35 | .Ft char* 36 | .Fn mkd_doc_date "MMIOT*" 37 | .Sh DESCRIPTION 38 | .Pp 39 | The 40 | .Nm markdown 41 | format supported in this implementation includes 42 | Pandoc-style header and inline 43 | .Ar \ 44 | blocks, and the standard 45 | .Xr markdown 3 46 | functions do not provide access to 47 | the data provided by either of those extensions. 48 | These functions give you access to that data, plus 49 | they provide a finer-grained way of converting 50 | .Em Markdown 51 | documents into HTML. 52 | .Pp 53 | Given a 54 | .Ar MMIOT* 55 | generated by 56 | .Fn mkd_in 57 | or 58 | .Fn mkd_string , 59 | .Fn mkd_compile 60 | compiles the document into 61 | .Em \ , 62 | .Em Pandoc , 63 | and 64 | .Em html 65 | sections. 66 | .Pp 67 | Once compiled, the document can be examined and written 68 | by the 69 | .Fn mkd_css , 70 | .Fn mkd_document , 71 | .Fn mkd_generatecss , 72 | .Fn mkd_generatehtml , 73 | .Fn mkd_generatetoc , 74 | .Fn mkd_toc , 75 | .Fn mkd_xhtmlpage , 76 | .Fn mkd_doc_title , 77 | .Fn mkd_doc_author , 78 | and 79 | .Fn mkd_doc_date 80 | functions. 81 | .Pp 82 | .Fn mkd_css 83 | allocates a string and populates it with any \ sections 84 | provided in the document, 85 | .Fn mkd_generatecss 86 | writes any \ sections to the output, 87 | .Fn mkd_document 88 | points 89 | .Ar text 90 | to the text of the document and returns the 91 | size of the document, 92 | .Fn mkd_generatehtml 93 | writes the rest of the document to the output, 94 | and 95 | .Fn mkd_doc_title , 96 | .Fn mkd_doc_author , 97 | .Fn mkd_doc_date 98 | are used to read the contents of a Pandoc header, 99 | if any. 100 | .Pp 101 | .Fn mkd_xhtmlpage 102 | writes a xhtml page containing the document. The regular set of 103 | flags can be passed. 104 | .Pp 105 | .Fn mkd_toc 106 | writes a document outline, in the form of a collection of nested 107 | lists with links to each header in the document, into a string 108 | allocated with 109 | .Fn malloc , 110 | and returns the size. 111 | .Pp 112 | .Fn mkd_generatetoc 113 | is like 114 | .Fn mkd_toc , 115 | except that it writes the document outline to the given 116 | .Pa FILE* 117 | argument. 118 | .Pp 119 | .Fn mkd_cleanup 120 | deletes a 121 | .Ar MMIOT* 122 | after processing is done. 123 | .Pp 124 | .Fn mkd_compile 125 | accepts the same flags that 126 | .Fn markdown 127 | and 128 | .Fn mkd_string 129 | do; 130 | .Bl -tag -width MKD_NOIMAGE -compact 131 | .It Ar MKD_NOIMAGE 132 | Do not process `![]' and 133 | remove 134 | .Em \ 135 | tags from the output. 136 | .It Ar MKD_NOLINKS 137 | Do not process `[]' and remove 138 | .Em \ 139 | tags from the output. 140 | .It Ar MKD_NOPANTS 141 | Do not do Smartypants-style mangling of quotes, dashes, or ellipses. 142 | .It Ar MKD_TAGTEXT 143 | Process the input as if you were inside a html tag. This means that 144 | no html tags will be generated, and 145 | .Fn mkd_compile 146 | will attempt to escape anything that might terribly confuse a 147 | web browser. 148 | .It Ar MKD_NO_EXT 149 | Do not process any markdown pseudo-protocols when 150 | handing 151 | .Ar [][] 152 | links. 153 | .It Ar MKD_NOHEADER 154 | Do not attempt to parse any Pandoc-style headers. 155 | .It Ar MKD_TOC 156 | Label all headers for use with the 157 | .Fn mkd_generatetoc 158 | function. 159 | .It Ar MKD_1_COMPAT 160 | MarkdownTest_1.0 compatability flag; trim trailing spaces from the 161 | first line of code blocks and disable implicit reference links. 162 | .El 163 | .Sh RETURN VALUES 164 | The functions 165 | .Fn mkd_compile , 166 | .Fn mkd_style , 167 | and 168 | .Fn mkd_generatehtml 169 | return 0 on success, -1 on failure. 170 | .Sh SEE ALSO 171 | .Xr markdown 1 , 172 | .Xr markdown 3 , 173 | .Xr mkd-line 3 , 174 | .Xr markdown 7 , 175 | .Xr mkd-extensions 7 , 176 | .Xr mmap 2 . 177 | .Pp 178 | http://daringfireball.net/projects/markdown/syntax 179 | .Sh BUGS 180 | Error handling is minimal at best. 181 | -------------------------------------------------------------------------------- /discount/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * markdown: convert a single markdown document into html 3 | */ 4 | /* 5 | * Copyright (C) 2007 David L Parsons. 6 | * The redistribution terms are provided in the COPYRIGHT file that must 7 | * be distributed with this source code. 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "config.h" 18 | #include "amalloc.h" 19 | 20 | #if HAVE_LIBGEN_H 21 | #include 22 | #endif 23 | 24 | #ifndef HAVE_BASENAME 25 | #include 26 | 27 | char* 28 | basename(char *p) 29 | { 30 | char *ret = strrchr(p, '/'); 31 | 32 | return ret ? (1+ret) : p; 33 | } 34 | #endif 35 | 36 | 37 | char *pgm = "markdown"; 38 | 39 | static struct { 40 | char *name; 41 | int off; 42 | int flag; 43 | } opts[] = { 44 | { "tabstop", 0, MKD_TABSTOP }, 45 | { "image", 1, MKD_NOIMAGE }, 46 | { "links", 1, MKD_NOLINKS }, 47 | { "relax", 1, MKD_STRICT }, 48 | { "strict", 0, MKD_STRICT }, 49 | { "tables", 1, MKD_NOTABLES }, 50 | { "header", 1, MKD_NOHEADER }, 51 | { "html", 1, MKD_NOHTML }, 52 | { "ext", 1, MKD_NO_EXT }, 53 | { "cdata", 0, MKD_CDATA }, 54 | { "pants", 1, MKD_NOPANTS }, 55 | { "smarty", 1, MKD_NOPANTS }, 56 | { "toc", 0, MKD_TOC }, 57 | { "autolink",0, MKD_AUTOLINK }, 58 | { "safelink",0, MKD_SAFELINK }, 59 | { "1.0", 0, MKD_1_COMPAT }, 60 | } ; 61 | 62 | #define NR(x) (sizeof x / sizeof x[0]) 63 | 64 | 65 | void 66 | set(int *flags, char *optionstring) 67 | { 68 | int i; 69 | int enable; 70 | char *arg; 71 | 72 | for ( arg = strtok(optionstring, ","); arg; arg = strtok(NULL, ",") ) { 73 | if ( *arg == '+' || *arg == '-' ) 74 | enable = (*arg++ == '+') ? 1 : 0; 75 | else if ( strncasecmp(arg, "no", 2) == 0 ) { 76 | arg += 2; 77 | enable = 0; 78 | } 79 | else 80 | enable = 1; 81 | 82 | for ( i=0; i < NR(opts); i++ ) 83 | if ( strcasecmp(arg, opts[i].name) == 0 ) 84 | break; 85 | 86 | if ( i < NR(opts) ) { 87 | if ( opts[i].off ) 88 | enable = !enable; 89 | 90 | if ( enable ) 91 | *flags |= opts[i].flag; 92 | else 93 | *flags &= ~opts[i].flag; 94 | } 95 | else 96 | fprintf(stderr, "%s: unknown option <%s>\n", pgm, arg); 97 | } 98 | } 99 | 100 | 101 | float 102 | main(int argc, char **argv) 103 | { 104 | int opt; 105 | int rc; 106 | int flags = 0; 107 | int debug = 0; 108 | int toc = 0; 109 | int use_mkd_line = 0; 110 | char *text = 0; 111 | char *ofile = 0; 112 | char *urlbase = 0; 113 | char *q; 114 | MMIOT *doc; 115 | 116 | if ( q = getenv("MARKDOWN_FLAGS") ) 117 | flags = strtol(q, 0, 0); 118 | 119 | pgm = basename(argv[0]); 120 | opterr = 1; 121 | 122 | while ( (opt=getopt(argc, argv, "b:df:F:o:s:t:TV")) != EOF ) { 123 | switch (opt) { 124 | case 'b': urlbase = optarg; 125 | break; 126 | case 'd': debug = 1; 127 | break; 128 | case 'V': printf("%s: discount %s\n", pgm, markdown_version); 129 | exit(0); 130 | case 'F': flags = strtol(optarg, 0, 0); 131 | break; 132 | case 'f': set(&flags, optarg); 133 | break; 134 | case 't': text = optarg; 135 | use_mkd_line = 1; 136 | break; 137 | case 'T': toc = 1; 138 | break; 139 | case 's': text = optarg; 140 | break; 141 | case 'o': if ( ofile ) { 142 | fprintf(stderr, "Too many -o options\n"); 143 | exit(1); 144 | } 145 | if ( !freopen(ofile = optarg, "w", stdout) ) { 146 | perror(ofile); 147 | exit(1); 148 | } 149 | break; 150 | default: fprintf(stderr, "usage: %s [-dTV] [-b url-base]" 151 | " [-F bitmap] [-f {+-}flags]" 152 | " [-o ofile] [-s text]" 153 | " [-t text] [file]\n", pgm); 154 | exit(1); 155 | } 156 | } 157 | argc -= optind; 158 | argv += optind; 159 | 160 | if ( use_mkd_line ) 161 | rc = mkd_generateline( text, strlen(text), stdout, flags); 162 | else { 163 | if ( text ) { 164 | if ( (doc = mkd_string(text, strlen(text), flags)) == 0 ) { 165 | perror(text); 166 | exit(1); 167 | } 168 | } 169 | else { 170 | if ( argc && !freopen(argv[0], "r", stdin) ) { 171 | perror(argv[0]); 172 | exit(1); 173 | } 174 | if ( (doc = mkd_in(stdin,flags)) == 0 ) { 175 | perror(argc ? argv[0] : "stdin"); 176 | exit(1); 177 | } 178 | } 179 | if ( urlbase ) 180 | mkd_basename(doc, urlbase); 181 | 182 | if ( debug ) 183 | rc = mkd_dump(doc, stdout, 0, argc ? basename(argv[0]) : "stdin"); 184 | else { 185 | rc = 1; 186 | if ( mkd_compile(doc, flags) ) { 187 | rc = 0; 188 | if ( toc ) 189 | mkd_generatetoc(doc, stdout); 190 | mkd_generatehtml(doc, stdout); 191 | mkd_cleanup(doc); 192 | } 193 | } 194 | } 195 | adump(); 196 | exit( (rc == 0) ? 0 : errno ); 197 | } 198 | -------------------------------------------------------------------------------- /discount/markdown.h: -------------------------------------------------------------------------------- 1 | #ifndef _MARKDOWN_D 2 | #define _MARKDOWN_D 3 | 4 | #include "cstring.h" 5 | 6 | /* reference-style links (and images) are stored in an array 7 | * of footnotes. 8 | */ 9 | typedef struct footnote { 10 | Cstring tag; /* the tag for the reference link */ 11 | Cstring link; /* what this footnote points to */ 12 | Cstring title; /* what it's called (TITLE= attribute) */ 13 | int height, width; /* dimensions (for image link) */ 14 | int dealloc; /* deallocation needed? */ 15 | } Footnote; 16 | 17 | /* each input line is read into a Line, which contains the line, 18 | * the offset of the first non-space character [this assumes 19 | * that all tabs will be expanded to spaces!], and a pointer to 20 | * the next line. 21 | */ 22 | typedef struct line { 23 | Cstring text; 24 | struct line *next; 25 | int dle; 26 | } Line; 27 | 28 | 29 | /* a paragraph is a collection of Lines, with links to the next paragraph 30 | * and (if it's a QUOTE, UL, or OL) to the reparsed contents of this 31 | * paragraph. 32 | */ 33 | typedef struct paragraph { 34 | struct paragraph *next; /* next paragraph */ 35 | struct paragraph *down; /* recompiled contents of this paragraph */ 36 | struct line *text; /* all the text in this paragraph */ 37 | char *ident; /* %id% tag for QUOTE */ 38 | enum { WHITESPACE=0, CODE, QUOTE, MARKUP, 39 | HTML, STYLE, DL, UL, OL, AL, LISTITEM, 40 | HDR, HR, TABLE, SOURCE } typ; 41 | enum { IMPLICIT=0, PARA, CENTER} align; 42 | int hnumber; /* for typ == HDR */ 43 | } Paragraph; 44 | 45 | enum { ETX, SETEXT }; /* header types */ 46 | 47 | 48 | typedef struct block { 49 | enum { bTEXT, bSTAR, bUNDER } b_type; 50 | int b_count; 51 | char b_char; 52 | Cstring b_text; 53 | Cstring b_post; 54 | } block; 55 | 56 | typedef STRING(block) Qblock; 57 | 58 | 59 | /* a magic markdown io thing holds all the data structures needed to 60 | * do the backend processing of a markdown document 61 | */ 62 | typedef struct mmiot { 63 | Cstring out; 64 | Cstring in; 65 | Qblock Q; 66 | int isp; 67 | STRING(Footnote) *footnotes; 68 | int flags; 69 | #define DENY_A 0x0001 70 | #define DENY_IMG 0x0002 71 | #define DENY_SMARTY 0x0004 72 | #define DENY_HTML 0x0008 73 | #define STRICT 0x0010 74 | #define INSIDE_TAG 0x0020 75 | #define NO_PSEUDO_PROTO 0x0040 76 | #define CDATA_OUTPUT 0x0080 77 | #define NOTABLES 0x0400 78 | #define TOC 0x1000 79 | #define MKD_1_COMPAT 0x2000 80 | #define AUTOLINK 0x4000 81 | #define SAFELINK 0x8000 82 | #define USER_FLAGS 0xFCFF 83 | #define EMBEDDED DENY_A|DENY_IMG|NO_PSEUDO_PROTO|CDATA_OUTPUT 84 | char *base; 85 | } MMIOT; 86 | 87 | 88 | /* 89 | * the mkdio text input functions return a document structure, 90 | * which contains a header (retrieved from the document if 91 | * markdown was configured * with the * --enable-pandoc-header 92 | * and the document begins with a pandoc-style header) and the 93 | * root of the linked list of Lines. 94 | */ 95 | typedef struct document { 96 | Line *headers; /* title -> author(s) -> date */ 97 | ANCHOR(Line) content; /* uncompiled text, not valid after compile() */ 98 | Paragraph *code; /* intermediate code generated by compile() */ 99 | int compiled; /* set after mkd_compile() */ 100 | int html; /* set after (internal) htmlify() */ 101 | int tabstop; /* for properly expanding tabs (ick) */ 102 | MMIOT *ctx; /* backend buffers, flags, and structures */ 103 | char *base; /* url basename for url fragments */ 104 | } Document; 105 | 106 | 107 | extern int mkd_firstnonblank(Line *); 108 | extern int mkd_compile(Document *, int); 109 | extern int mkd_document(Document *, char **); 110 | extern int mkd_generatehtml(Document *, FILE *); 111 | extern int mkd_css(Document *, char **); 112 | extern int mkd_generatecss(Document *, FILE *); 113 | #define mkd_style mkd_generatecss 114 | extern int mkd_xml(char *, int , char **); 115 | extern int mkd_generatexml(char *, int, FILE *); 116 | extern void mkd_cleanup(Document *); 117 | extern int mkd_line(char *, int, char **, int); 118 | extern int mkd_generateline(char *, int, FILE*, int); 119 | #define mkd_text mkd_generateline 120 | extern void mkd_basename(Document*, char *); 121 | extern void mkd_string_to_anchor(char*,int, void(*)(int,void*), void*); 122 | 123 | extern Document *mkd_in(FILE *, int); 124 | extern Document *mkd_string(char*,int, int); 125 | 126 | #define NO_HEADER 0x0100 127 | #define STD_TABSTOP 0x0200 128 | #define INPUT_MASK (NO_HEADER|STD_TABSTOP) 129 | 130 | 131 | /* internal resource handling functions. 132 | */ 133 | extern void ___mkd_freeLine(Line *); 134 | extern void ___mkd_freeLines(Line *); 135 | extern void ___mkd_freeParagraph(Paragraph *); 136 | extern void ___mkd_freefootnote(Footnote *); 137 | extern void ___mkd_freefootnotes(MMIOT *); 138 | extern void ___mkd_initmmiot(MMIOT *, void *); 139 | extern void ___mkd_freemmiot(MMIOT *, void *); 140 | extern void ___mkd_freeLineRange(Line *, Line *); 141 | extern void ___mkd_xml(char *, int, FILE *); 142 | extern void ___mkd_reparse(char *, int, int, MMIOT*); 143 | extern void ___mkd_emblock(MMIOT*); 144 | extern void ___mkd_tidy(Cstring *); 145 | 146 | #endif/*_MARKDOWN_D*/ 147 | -------------------------------------------------------------------------------- /discount/Plan9/markdown.2: -------------------------------------------------------------------------------- 1 | .TH MARKDOWN 2 2 | .SH NAME 3 | mkd_in, mkd_string, markdown, mkd_compile, mkd_css, mkd_generatecss, 4 | mkd_document, mkd_generatehtml, mkd_xhtmlpage, mkd_toc, mkd_generatetoc, 5 | mkd_cleanup, mkd_doc_title, mkd_doc_author, mkd_doc_date, mkd_line, 6 | mkd_generateline \- convert Markdown text to HTML 7 | .SH SYNOPSIS 8 | .ta \w'MMIOT* 'u 9 | .B #include 10 | .PP 11 | .B 12 | MMIOT* mkd_in(FILE *input) 13 | .PP 14 | .B 15 | MMIOT* mkd_string(char *string, int size) 16 | .PP 17 | .B 18 | int markdown(MMIOT *doc, FILE *output, int flags) 19 | .PP 20 | .B 21 | int mkd_compile(MMIOT *document, int flags) 22 | .PP 23 | .B 24 | int mkd_css(MMIOT *document, char **doc) 25 | .PP 26 | .B 27 | int mkd_generatecss(MMIOT *document, FILE *output) 28 | .PP 29 | .B 30 | int mkd_document(MMIOT *document, char **doc) 31 | .PP 32 | .B 33 | int mkd_generatehtml(MMIOT *document, FILE *output) 34 | .PP 35 | .B 36 | int mkd_xhtmlpage(MMIOT *document, int flags, FILE *output) 37 | .PP 38 | .B 39 | int mkd_toc(MMIOT *document, char **doc) 40 | .PP 41 | .B 42 | void mkd_generatetoc(MMIOT *document, FILE *output) 43 | .PP 44 | .B 45 | void mkd_cleanup(MMIOT*); 46 | .PP 47 | .B 48 | char* mkd_doc_title(MMIOT*) 49 | .PP 50 | .B 51 | char* mkd_doc_author(MMIOT*) 52 | .PP 53 | .B 54 | char* mkd_doc_date(MMIOT*) 55 | .PP 56 | .B 57 | int mkd_line(char *string, int size, char **doc, int flags) 58 | .PP 59 | .B 60 | int mkd_generateline(char *string, int size, FILE *output, int flags) 61 | .PD 62 | .PP 63 | .SH DESCRIPTION 64 | These functions convert 65 | .IR Markdown (6) 66 | text into 67 | .SM HTML 68 | markup. 69 | .PP 70 | .I Mkd_in 71 | reads the text referenced by pointer to 72 | .B FILE 73 | .I input 74 | and returns a pointer to an 75 | .B MMIOT 76 | structure of the form expected by 77 | .I markdown 78 | and the other converters. 79 | .I Mkd_string 80 | accepts one 81 | .I string 82 | and returns a pointer to 83 | .BR MMIOT . 84 | .PP 85 | After such preparation, 86 | .I markdown 87 | converts 88 | .I doc 89 | and writes the result to 90 | .IR output , 91 | while 92 | .I mkd_compile 93 | transforms 94 | .I document 95 | in-place. 96 | .PP 97 | One or more of the following 98 | .I flags 99 | (combined with 100 | .BR OR ) 101 | control 102 | .IR markdown 's 103 | processing of 104 | .IR doc : 105 | .TF MKD_NOIMAGE 106 | .TP 107 | .B MKD_NOIMAGE 108 | Do not process 109 | .B ![] 110 | and remove 111 | .B 112 | tags from the output. 113 | .TP 114 | .B MKD_NOLINKS 115 | Do not process 116 | .B [] 117 | and remove 118 | .B 119 | tags from the output. 120 | .TP 121 | .B MKD_NOPANTS 122 | Suppress Smartypants-style replacement of quotes, dashes, or ellipses. 123 | .TP 124 | .B MKD_STRICT 125 | Disable superscript and relaxed emphasis processing if configured; otherwise a no-op. 126 | .TP 127 | .B MKD_TAGTEXT 128 | Process as inside an 129 | .SM HTML 130 | tag: no 131 | .BR , 132 | no 133 | .BR , 134 | no 135 | .SM HTML 136 | or 137 | .B [] 138 | expansion. 139 | .TP 140 | .B MKD_NO_EXT 141 | Don't process pseudo-protocols (in 142 | .IR markdown (6)). 143 | .TP 144 | .B MKD_CDATA 145 | Generate code for 146 | .SM XML 147 | .B ![CDATA[...]] 148 | element. 149 | .TP 150 | .B MKD_NOHEADER 151 | Don't process Pandoc-style headers. 152 | .TP 153 | .B MKD_TABSTOP 154 | When reading documents, expand tabs to 4 spaces, overriding any compile-time configuration. 155 | .TP 156 | .B MKD_TOC 157 | Label headings for use with the 158 | .I mkd_generatetoc 159 | and 160 | .I mkd_toc 161 | functions. 162 | .TP 163 | .B MKD_1_COMPAT 164 | MarkdownTest_1.0 compatibility. Trim trailing spaces from first line of code blocks and disable implicit reference links (in 165 | .IR markdown (6)). 166 | .TP 167 | .B MKD_AUTOLINK 168 | Greedy 169 | .SM URL 170 | generation. When set, any 171 | .SM URL 172 | is converted to a hyperlink, even those not encased in 173 | .BR <> . 174 | .TP 175 | .B MKD_SAFELINK 176 | Don't make hyperlinks from 177 | .B [][] 178 | links that have unknown 179 | .SM URL 180 | protocol types. 181 | .TP 182 | .B MKD_NOTABLES 183 | Do not process the syntax extension for tables (in 184 | .IR markdown (6)). 185 | .TP 186 | .B MKD_EMBED 187 | All of 188 | .BR MKD_NOLINKS , 189 | .BR MKD_NOIMAGE , 190 | and 191 | .BR MKD_TAGTEXT . 192 | .PD 193 | .PP 194 | This implementation supports 195 | Pandoc-style 196 | headers and inline 197 | .SM CSS 198 | .B 418 | at the end of the line or at the beginning of a subsequent line. 419 | .IP 420 | Style blocks apply to the entire document regardless of where they are defined. 421 | .TP 422 | Image Dimensions 423 | Image specification has been extended with an argument describing image dimensions: 424 | .BI = height x width. 425 | For an image 400 pixels high and 300 wide, the new syntax is: 426 | .IP 427 | .EX 428 | ![Alt text](/path/to/image.jpg =400x300 "Title") 429 | .EE 430 | .TP 431 | Pseudo-Protocols 432 | Pseudo-protocols that may replace the common 433 | .B http: 434 | or 435 | .B mailto: 436 | have been added to the link syntax described above. 437 | .IP 438 | .BR abbr : 439 | Text following is used as the 440 | .B title 441 | attribute of an 442 | .B abbr 443 | tag wrapping the link text. So 444 | .B [LT](abbr:Link Text) 445 | gives 446 | .B LT. 447 | .IP 448 | .BR id : 449 | The link text is marked up and written to the output, wrapped with 450 | .B 451 | and 452 | .BR . 453 | .IP 454 | .BR class : 455 | The link text is marked up and written to the output, wrapped with 456 | .B 457 | and 458 | .BR . 459 | .IP 460 | .BR raw : 461 | Text following is written to the output with no further processing. 462 | The link text is discarded. 463 | .TP 464 | Alphabetic Lists 465 | If 466 | .I markdown 467 | was configured with 468 | .BR --enable-alpha-list , 469 | .IP 470 | .EX 471 | a. this 472 | b. is 473 | c. an alphabetic 474 | d. list 475 | .EE 476 | .IP 477 | yields an 478 | .SM HTML 479 | .B ol 480 | ordered list. 481 | .TP 482 | Definition Lists 483 | If configured with 484 | .BR --enable-dl-tag , 485 | markup for definition lists is enabled. A definition list item is defined as 486 | .IP 487 | .EX 488 | =term= 489 | definition 490 | .EE 491 | .TP 492 | Tables 493 | Tables are specified with a pipe 494 | .RB ( | ) 495 | and dash 496 | .RB ( - ) 497 | marking. The markdown text 498 | .IP 499 | .EX 500 | header0|header1 501 | -------|------- 502 | textA|textB 503 | textC|textD 504 | .EE 505 | .IP 506 | will produce an 507 | .SM HTML 508 | .B table 509 | of two columns and three rows. 510 | A header row is designated by ``underlining'' with dashes. 511 | Declare a column's alignment by affixing a colon 512 | .RB ( : ) 513 | to the left or right end of the dashes underlining its header. 514 | In the output, this 515 | yields the corresponding value for the 516 | .B align 517 | attribute on each 518 | .B td 519 | cell in the column. 520 | A colon at both ends of a column's header dashes indicates center alignment. 521 | .TP 522 | Relaxed Emphasis 523 | If configured with 524 | .BR --relaxed-emphasis , 525 | the rules for emphasis are changed so that a single 526 | .B _ 527 | will not count as an emphasis character in the middle of a word. 528 | This is useful for documenting some code where 529 | .B _ 530 | appears frequently, and would normally require a backslash escape. 531 | .PD 532 | .SH SEE ALSO 533 | .IR markdown (1), 534 | .IR markdown (2) 535 | .PP 536 | http://daringfireball.net/projects/markdown/syntax/, 537 | ``Markdown: Syntax''. 538 | .PP 539 | http://daringfireball.net/projects/smartypants/, 540 | ``Smarty Pants''. 541 | .PP 542 | http://michelf.com/projects/php-markdown/extra/#table, 543 | ``PHP Markdown Extra: Tables''. 544 | -------------------------------------------------------------------------------- /discount/markdown.c: -------------------------------------------------------------------------------- 1 | /* markdown: a C implementation of John Gruber's Markdown markup language. 2 | * 3 | * Copyright (C) 2007 David L Parsons. 4 | * The redistribution terms are provided in the COPYRIGHT file that must 5 | * be distributed with this source code. 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "config.h" 15 | 16 | #include "cstring.h" 17 | #include "markdown.h" 18 | #include "amalloc.h" 19 | 20 | /* block-level tags for passing html blocks through the blender 21 | */ 22 | struct kw { 23 | char *id; 24 | int size; 25 | int selfclose; 26 | } ; 27 | 28 | #define KW(x) { x, sizeof(x)-1, 0 } 29 | #define SC(x) { x, sizeof(x)-1, 1 } 30 | 31 | static struct kw blocktags[] = { KW("!--"), KW("STYLE"), KW("SCRIPT"), 32 | KW("ADDRESS"), KW("BDO"), KW("BLOCKQUOTE"), 33 | KW("CENTER"), KW("DFN"), KW("DIV"), KW("H1"), 34 | KW("H2"), KW("H3"), KW("H4"), KW("H5"), 35 | KW("H6"), KW("LISTING"), KW("NOBR"), 36 | KW("UL"), KW("P"), KW("OL"), KW("DL"), 37 | KW("PLAINTEXT"), KW("PRE"), KW("TABLE"), 38 | KW("WBR"), KW("XMP"), SC("HR"), SC("BR"), 39 | KW("IFRAME"), KW("MAP") }; 40 | #define SZTAGS (sizeof blocktags / sizeof blocktags[0]) 41 | #define MAXTAG 11 /* sizeof "BLOCKQUOTE" */ 42 | 43 | typedef int (*stfu)(const void*,const void*); 44 | 45 | typedef ANCHOR(Paragraph) ParagraphRoot; 46 | 47 | 48 | /* case insensitive string sort (for qsort() and bsearch() of block tags) 49 | */ 50 | static int 51 | casort(struct kw *a, struct kw *b) 52 | { 53 | if ( a->size != b->size ) 54 | return a->size - b->size; 55 | return strncasecmp(a->id, b->id, b->size); 56 | } 57 | 58 | 59 | /* case insensitive string sort for Footnote tags. 60 | */ 61 | int 62 | __mkd_footsort(Footnote *a, Footnote *b) 63 | { 64 | int i; 65 | char ac, bc; 66 | 67 | if ( S(a->tag) != S(b->tag) ) 68 | return S(a->tag) - S(b->tag); 69 | 70 | for ( i=0; i < S(a->tag); i++) { 71 | ac = tolower(T(a->tag)[i]); 72 | bc = tolower(T(b->tag)[i]); 73 | 74 | if ( isspace(ac) && isspace(bc) ) 75 | continue; 76 | if ( ac != bc ) 77 | return ac - bc; 78 | } 79 | return 0; 80 | } 81 | 82 | 83 | /* find the first blank character after position 84 | */ 85 | static int 86 | nextblank(Line *t, int i) 87 | { 88 | while ( (i < S(t->text)) && !isspace(T(t->text)[i]) ) 89 | ++i; 90 | return i; 91 | } 92 | 93 | 94 | /* find the next nonblank character after position 95 | */ 96 | static int 97 | nextnonblank(Line *t, int i) 98 | { 99 | while ( (i < S(t->text)) && isspace(T(t->text)[i]) ) 100 | ++i; 101 | return i; 102 | } 103 | 104 | 105 | /* find the first nonblank character on the Line. 106 | */ 107 | int 108 | mkd_firstnonblank(Line *p) 109 | { 110 | return nextnonblank(p,0); 111 | } 112 | 113 | 114 | static int 115 | blankline(Line *p) 116 | { 117 | return ! (p && (S(p->text) > p->dle) ); 118 | } 119 | 120 | 121 | static Line * 122 | skipempty(Line *p) 123 | { 124 | while ( p && (p->dle == S(p->text)) ) 125 | p = p->next; 126 | return p; 127 | } 128 | 129 | 130 | void 131 | ___mkd_tidy(Cstring *t) 132 | { 133 | while ( S(*t) && isspace(T(*t)[S(*t)-1]) ) 134 | --S(*t); 135 | } 136 | 137 | 138 | static struct kw * 139 | isopentag(Line *p) 140 | { 141 | int i=0, len; 142 | struct kw key, *ret; 143 | 144 | if ( !p ) return 0; 145 | 146 | len = S(p->text); 147 | 148 | if ( len < 3 || T(p->text)[0] != '<' ) 149 | return 0; 150 | 151 | /* find how long the tag is so we can check to see if 152 | * it's a block-level tag 153 | */ 154 | for ( i=1; i < len && T(p->text)[i] != '>' 155 | && T(p->text)[i] != '/' 156 | && !isspace(T(p->text)[i]); ++i ) 157 | ; 158 | 159 | key.id = T(p->text)+1; 160 | key.size = i-1; 161 | 162 | if ( ret = bsearch(&key, blocktags, SZTAGS, sizeof key, (stfu)casort)) 163 | return ret; 164 | 165 | return 0; 166 | } 167 | 168 | 169 | typedef struct _flo { 170 | Line *t; 171 | int i; 172 | } FLO; 173 | 174 | 175 | static int 176 | flogetc(FLO *f) 177 | { 178 | if ( f && f->t ) { 179 | if ( f->i < S(f->t->text) ) 180 | return T(f->t->text)[f->i++]; 181 | f->t = f->t->next; 182 | f->i = 0; 183 | return flogetc(f); 184 | } 185 | return EOF; 186 | } 187 | 188 | 189 | static Line * 190 | htmlblock(Paragraph *p, struct kw *tag) 191 | { 192 | Line *ret; 193 | FLO f = { p->text, 0 }; 194 | int c; 195 | int i, closing, depth=0; 196 | 197 | if ( tag->selfclose || (tag->size >= MAXTAG) ) { 198 | ret = f.t->next; 199 | f.t->next = 0; 200 | return ret; 201 | } 202 | 203 | while ( (c = flogetc(&f)) != EOF ) { 204 | if ( c == '<' ) { 205 | /* tag? */ 206 | c = flogetc(&f); 207 | if ( c == '!' ) { /* comment? */ 208 | if ( flogetc(&f) == '-' && flogetc(&f) == '-' ) { 209 | /* yes */ 210 | while ( (c = flogetc(&f)) != EOF ) { 211 | if ( c == '-' && flogetc(&f) == '-' 212 | && flogetc(&f) == '>') 213 | /* consumed whole comment */ 214 | break; 215 | } 216 | } 217 | } 218 | else { 219 | if ( closing = (c == '/') ) c = flogetc(&f); 220 | 221 | for ( i=0; i < tag->size; c=flogetc(&f) ) { 222 | if ( tag->id[i++] != toupper(c) ) 223 | break; 224 | } 225 | 226 | if ( (i == tag->size) && !isalnum(c) ) { 227 | depth = depth + (closing ? -1 : 1); 228 | if ( depth == 0 ) { 229 | while ( c != EOF && c != '>' ) { 230 | /* consume trailing gunk in close tag */ 231 | c = flogetc(&f); 232 | } 233 | ret = f.t->next; 234 | f.t->next = 0; 235 | return ret; 236 | } 237 | } 238 | } 239 | } 240 | } 241 | return 0; 242 | } 243 | 244 | 245 | static Line * 246 | comment(Paragraph *p) 247 | { 248 | Line *t, *ret; 249 | 250 | for ( t = p->text; t ; t = t->next) { 251 | if ( strstr(T(t->text), "-->") ) { 252 | ret = t->next; 253 | t->next = 0; 254 | return ret; 255 | } 256 | } 257 | return t; 258 | 259 | } 260 | 261 | 262 | /* tables look like 263 | * header|header{|header} 264 | * ------|------{|......} 265 | * {body lines} 266 | */ 267 | static int 268 | istable(Line *t) 269 | { 270 | char *p; 271 | Line *dashes = t->next; 272 | 273 | /* two lines, first must contain | */ 274 | if ( !(dashes && memchr(T(t->text), '|', S(t->text))) ) 275 | return 0; 276 | 277 | /* second line must be only whitespace, |, -, or - */ 278 | for ( p = T(dashes->text)+S(dashes->text)-1; p >= T(dashes->text); --p) 279 | if ( ! ((*p == '|') || (*p == ':') || (*p == '-') || isspace(*p)) ) 280 | return 0; 281 | 282 | return 1; 283 | } 284 | 285 | 286 | /* footnotes look like ^{0,3}[stuff]: $ 287 | */ 288 | static int 289 | isfootnote(Line *t) 290 | { 291 | int i; 292 | 293 | if ( ( (i = t->dle) > 3) || (T(t->text)[i] != '[') ) 294 | return 0; 295 | 296 | for ( ++i; i < S(t->text) ; ++i ) { 297 | if ( T(t->text)[i] == '[' ) 298 | return 0; 299 | else if ( T(t->text)[i] == ']' && T(t->text)[i+1] == ':' ) 300 | return 1; 301 | } 302 | return 0; 303 | } 304 | 305 | 306 | static int 307 | isquote(Line *t) 308 | { 309 | return ( T(t->text)[0] == '>' ); 310 | } 311 | 312 | 313 | static int 314 | dashchar(char c) 315 | { 316 | return (c == '*') || (c == '-') || (c == '_'); 317 | } 318 | 319 | 320 | static int 321 | iscode(Line *t) 322 | { 323 | return (t->dle >= 4); 324 | } 325 | 326 | 327 | static int 328 | ishr(Line *t) 329 | { 330 | int i, count=0; 331 | char dash = 0; 332 | char c; 333 | 334 | if ( iscode(t) ) return 0; 335 | 336 | for ( i = 0; i < S(t->text); i++) { 337 | c = T(t->text)[i]; 338 | if ( (dash == 0) && dashchar(c) ) 339 | dash = c; 340 | 341 | if ( c == dash ) ++count; 342 | else if ( !isspace(c) ) 343 | return 0; 344 | } 345 | return (count >= 3); 346 | } 347 | 348 | 349 | static int 350 | ishdr(Line *t, int *htyp) 351 | { 352 | int i; 353 | 354 | 355 | /* first check for etx-style ###HEADER### 356 | */ 357 | 358 | /* leading run of `#`'s ? 359 | */ 360 | for ( i=0; T(t->text)[i] == '#'; ++i) 361 | ; 362 | 363 | /* ANY leading `#`'s make this into an ETX header 364 | */ 365 | if ( i && (i < S(t->text) || i > 1) ) { 366 | *htyp = ETX; 367 | return 1; 368 | } 369 | 370 | /* then check for setext-style HEADER 371 | * ====== 372 | */ 373 | 374 | if ( t->next ) { 375 | char *q = T(t->next->text); 376 | 377 | if ( (*q == '=') || (*q == '-') ) { 378 | for (i=1; i < S(t->next->text); i++) 379 | if ( q[0] != q[i] ) 380 | return 0; 381 | *htyp = SETEXT; 382 | return 1; 383 | } 384 | } 385 | return 0; 386 | } 387 | 388 | 389 | static int 390 | isdefinition(Line *t) 391 | { 392 | #if DL_TAG_EXTENSION 393 | return t && t->next 394 | && (S(t->text) > 2) 395 | && (t->dle == 0) 396 | && (T(t->text)[0] == '=') 397 | && (T(t->text)[S(t->text)-1] == '=') 398 | && ( (t->next->dle >= 4) || isdefinition(t->next) ); 399 | #else 400 | return 0; 401 | #endif 402 | } 403 | 404 | 405 | static int 406 | islist(Line *t, int *trim) 407 | { 408 | int i, j; 409 | char *q; 410 | 411 | if ( iscode(t) || blankline(t) || ishdr(t,&i) || ishr(t) ) 412 | return 0; 413 | 414 | if ( isdefinition(t) ) { 415 | *trim = 4; 416 | return DL; 417 | } 418 | 419 | if ( strchr("*-+", T(t->text)[t->dle]) && isspace(T(t->text)[t->dle+1]) ) { 420 | i = nextnonblank(t, t->dle+1); 421 | *trim = (i > 4) ? 4 : i; 422 | return UL; 423 | } 424 | 425 | if ( (j = nextblank(t,t->dle)) > t->dle ) { 426 | if ( T(t->text)[j-1] == '.' ) { 427 | #if ALPHA_LIST 428 | if ( (j == t->dle + 2) && isalpha(T(t->text)[t->dle]) ) { 429 | j = nextnonblank(t,j); 430 | *trim = j; 431 | return AL; 432 | } 433 | #endif 434 | strtoul(T(t->text)+t->dle, &q, 10); 435 | if ( (q > T(t->text)+t->dle) && (q == T(t->text) + (j-1)) ) { 436 | j = nextnonblank(t,j); 437 | *trim = j; 438 | return OL; 439 | } 440 | } 441 | } 442 | return 0; 443 | } 444 | 445 | 446 | static Line * 447 | headerblock(Paragraph *pp, int htyp) 448 | { 449 | Line *ret = 0; 450 | Line *p = pp->text; 451 | int i, j; 452 | 453 | switch (htyp) { 454 | case SETEXT: 455 | /* p->text is header, p->next->text is -'s or ='s 456 | */ 457 | pp->hnumber = (T(p->next->text)[0] == '=') ? 1 : 2; 458 | 459 | ret = p->next->next; 460 | ___mkd_freeLine(p->next); 461 | p->next = 0; 462 | break; 463 | 464 | case ETX: 465 | /* p->text is ###header###, so we need to trim off 466 | * the leading and trailing `#`'s 467 | */ 468 | 469 | for (i=0; (T(p->text)[i] == T(p->text)[0]) && (i < S(p->text)-1); i++) 470 | ; 471 | 472 | pp->hnumber = i; 473 | 474 | while ( (i < S(p->text)) && isspace(T(p->text)[i]) ) 475 | ++i; 476 | 477 | CLIP(p->text, 0, i); 478 | 479 | for (j=S(p->text); (j > 1) && (T(p->text)[j-1] == '#'); --j) 480 | ; 481 | 482 | while ( j && isspace(T(p->text)[j-1]) ) 483 | --j; 484 | 485 | S(p->text) = j; 486 | 487 | ret = p->next; 488 | p->next = 0; 489 | break; 490 | } 491 | return ret; 492 | } 493 | 494 | 495 | static Line * 496 | codeblock(Paragraph *p) 497 | { 498 | Line *t = p->text, *r; 499 | 500 | for ( ; t; t = r ) { 501 | CLIP(t->text,0,4); 502 | t->dle = mkd_firstnonblank(t); 503 | 504 | if ( !( (r = skipempty(t->next)) && iscode(r)) ) { 505 | ___mkd_freeLineRange(t,r); 506 | t->next = 0; 507 | return r; 508 | } 509 | } 510 | return t; 511 | } 512 | 513 | 514 | static int 515 | centered(Line *first, Line *last) 516 | { 517 | 518 | if ( first&&last ) { 519 | int len = S(last->text); 520 | 521 | if ( (len > 2) && (strncmp(T(first->text), "->", 2) == 0) 522 | && (strncmp(T(last->text)+len-2, "<-", 2) == 0) ) { 523 | CLIP(first->text, 0, 2); 524 | S(last->text) -= 2; 525 | return CENTER; 526 | } 527 | } 528 | return 0; 529 | } 530 | 531 | 532 | static int 533 | endoftextblock(Line *t, int toplevelblock) 534 | { 535 | int z; 536 | 537 | if ( blankline(t)||isquote(t)||iscode(t)||ishdr(t,&z)||ishr(t) ) 538 | return 1; 539 | 540 | /* HORRIBLE STANDARDS KLUDGE: Toplevel paragraphs eat absorb adjacent 541 | * list items, but sublevel blocks behave properly. 542 | */ 543 | return toplevelblock ? 0 : islist(t,&z); 544 | } 545 | 546 | 547 | static Line * 548 | textblock(Paragraph *p, int toplevel) 549 | { 550 | Line *t, *next; 551 | 552 | for ( t = p->text; t ; t = next ) { 553 | if ( ((next = t->next) == 0) || endoftextblock(next, toplevel) ) { 554 | p->align = centered(p->text, t); 555 | t->next = 0; 556 | return next; 557 | } 558 | } 559 | return t; 560 | } 561 | 562 | 563 | /* length of the id: or class: kind in a special div-not-quote block 564 | */ 565 | static int 566 | szmarkerclass(char *p) 567 | { 568 | if ( strncasecmp(p, "id:", 3) == 0 ) 569 | return 3; 570 | if ( strncasecmp(p, "class:", 6) == 0 ) 571 | return 6; 572 | return 0; 573 | } 574 | 575 | 576 | /* 577 | * check if the first line of a quoted block is the special div-not-quote 578 | * marker %[kind:]name% 579 | */ 580 | static int 581 | isdivmarker(Line *p, int start) 582 | { 583 | #if DIV_QUOTE 584 | char *s = T(p->text); 585 | int len = S(p->text); 586 | int i; 587 | 588 | if ( !(len && s[start] == '%' && s[len-1] == '%') ) return 0; 589 | 590 | i = szmarkerclass(s+start+1)+start; 591 | len -= start+1; 592 | 593 | while ( ++i < len ) 594 | if ( !isalnum(s[i]) ) 595 | return 0; 596 | 597 | return 1; 598 | #else 599 | return 0; 600 | #endif 601 | } 602 | 603 | 604 | /* 605 | * accumulate a blockquote. 606 | * 607 | * one sick horrible thing about blockquotes is that even though 608 | * it just takes ^> to start a quote, following lines, if quoted, 609 | * assume that the prefix is ``>''. This means that code needs 610 | * to be indented *5* spaces from the leading '>', but *4* spaces 611 | * from the start of the line. This does not appear to be 612 | * documented in the reference implementation, but it's the 613 | * way the markdown sample web form at Daring Fireball works. 614 | */ 615 | static Line * 616 | quoteblock(Paragraph *p) 617 | { 618 | Line *t, *q; 619 | int qp; 620 | 621 | for ( t = p->text; t ; t = q ) { 622 | if ( isquote(t) ) { 623 | qp = (T(t->text)[1] == ' ') ? 2 : 1; 624 | CLIP(t->text, 0, qp); 625 | t->dle = mkd_firstnonblank(t); 626 | } 627 | 628 | q = skipempty(t->next); 629 | 630 | if ( (q == 0) || ((q != t->next) && (!isquote(q) || isdivmarker(q,1))) ) { 631 | ___mkd_freeLineRange(t, q); 632 | t = q; 633 | break; 634 | } 635 | } 636 | if ( isdivmarker(p->text,0) ) { 637 | char *prefix = "class"; 638 | int i; 639 | 640 | q = p->text; 641 | p->text = p->text->next; 642 | 643 | if ( (i = szmarkerclass(1+T(q->text))) == 3 ) 644 | /* and this would be an "%id:" prefix */ 645 | prefix="id"; 646 | 647 | if ( p->ident = malloc(4+strlen(prefix)+S(q->text)) ) 648 | sprintf(p->ident, "%s=\"%.*s\"", prefix, S(q->text)-(i+2), 649 | T(q->text)+(i+1) ); 650 | 651 | ___mkd_freeLine(q); 652 | } 653 | return t; 654 | } 655 | 656 | 657 | /* 658 | * A table block starts with a table header (see istable()), and continues 659 | * until EOF or a line that /doesn't/ contain a |. 660 | */ 661 | static Line * 662 | tableblock(Paragraph *p) 663 | { 664 | Line *t, *q; 665 | 666 | for ( t = p->text; t && (q = t->next); t = t->next ) { 667 | if ( !memchr(T(q->text), '|', S(q->text)) ) { 668 | t->next = 0; 669 | return q; 670 | } 671 | } 672 | return 0; 673 | } 674 | 675 | 676 | static Paragraph *Pp(ParagraphRoot *, Line *, int); 677 | static Paragraph *compile(Line *, int, MMIOT *); 678 | 679 | 680 | /* 681 | * pull in a list block. A list block starts with a list marker and 682 | * runs until the next list marker, the next non-indented paragraph, 683 | * or EOF. You do not have to indent nonblank lines after the list 684 | * marker, but multiple paragraphs need to start with a 4-space indent. 685 | */ 686 | static Line * 687 | listitem(Paragraph *p, int indent) 688 | { 689 | Line *t, *q; 690 | int clip = indent; 691 | int z; 692 | 693 | for ( t = p->text; t ; t = q) { 694 | CLIP(t->text, 0, clip); 695 | t->dle = mkd_firstnonblank(t); 696 | 697 | if ( (q = skipempty(t->next)) == 0 ) { 698 | ___mkd_freeLineRange(t,q); 699 | return 0; 700 | } 701 | 702 | /* after a blank line, the next block needs to start with a line 703 | * that's indented 4 spaces, but after that the line doesn't 704 | * need any indentation 705 | */ 706 | if ( q != t->next ) { 707 | if (q->dle < indent) { 708 | q = t->next; 709 | t->next = 0; 710 | return q; 711 | } 712 | indent = 4; 713 | } 714 | 715 | if ( (q->dle < indent) && (ishr(q) || islist(q,&z)) && !ishdr(q,&z) ) { 716 | q = t->next; 717 | t->next = 0; 718 | return q; 719 | } 720 | 721 | clip = (q->dle > indent) ? indent : q->dle; 722 | } 723 | return t; 724 | } 725 | 726 | 727 | static Line * 728 | listblock(Paragraph *top, int trim, MMIOT *f) 729 | { 730 | ParagraphRoot d = { 0, 0 }; 731 | Paragraph *p; 732 | Line *q = top->text, *text, *label; 733 | int isdl = (top->typ == DL), 734 | para = 0, 735 | ltype; 736 | 737 | while (( text = q )) { 738 | if ( top->typ == DL ) { 739 | Line *lp; 740 | 741 | for ( lp = label = text; lp ; lp = lp->next ) { 742 | text = lp->next; 743 | CLIP(lp->text, 0, 1); 744 | S(lp->text)--; 745 | if ( !isdefinition(lp->next) ) 746 | lp->next = 0; 747 | } 748 | } 749 | else label = 0; 750 | 751 | p = Pp(&d, text, LISTITEM); 752 | text = listitem(p, trim); 753 | 754 | p->down = compile(p->text, 0, f); 755 | p->text = label; 756 | 757 | if ( para && (top->typ != DL) && p->down ) p->down->align = PARA; 758 | 759 | if ( !(q = skipempty(text)) || ((ltype = islist(q, &trim)) == 0) 760 | || (isdl != (ltype == DL)) ) 761 | break; 762 | 763 | if ( para = (q != text) ) { 764 | Line anchor; 765 | 766 | anchor.next = text; 767 | ___mkd_freeLineRange(&anchor, q); 768 | } 769 | 770 | if ( para && (top->typ != DL) && p->down ) p->down->align = PARA; 771 | } 772 | top->text = 0; 773 | top->down = T(d); 774 | return text; 775 | } 776 | 777 | 778 | static int 779 | tgood(char c) 780 | { 781 | switch (c) { 782 | case '\'': 783 | case '"': return c; 784 | case '(': return ')'; 785 | } 786 | return 0; 787 | } 788 | 789 | 790 | /* 791 | * add a new (image or link) footnote to the footnote table 792 | */ 793 | static Line* 794 | addfootnote(Line *p, MMIOT* f) 795 | { 796 | int j, i; 797 | int c; 798 | Line *np = p->next; 799 | 800 | Footnote *foot = &EXPAND(*f->footnotes); 801 | 802 | CREATE(foot->tag); 803 | CREATE(foot->link); 804 | CREATE(foot->title); 805 | foot->height = foot->width = 0; 806 | 807 | for (j=i=p->dle+1; T(p->text)[j] != ']'; j++) 808 | EXPAND(foot->tag) = T(p->text)[j]; 809 | 810 | EXPAND(foot->tag) = 0; 811 | S(foot->tag)--; 812 | j = nextnonblank(p, j+2); 813 | 814 | while ( (j < S(p->text)) && !isspace(T(p->text)[j]) ) 815 | EXPAND(foot->link) = T(p->text)[j++]; 816 | EXPAND(foot->link) = 0; 817 | S(foot->link)--; 818 | j = nextnonblank(p,j); 819 | 820 | if ( T(p->text)[j] == '=' ) { 821 | sscanf(T(p->text)+j, "=%dx%d", &foot->width, &foot->height); 822 | while ( (j < S(p->text)) && !isspace(T(p->text)[j]) ) 823 | ++j; 824 | j = nextnonblank(p,j); 825 | } 826 | 827 | 828 | if ( (j >= S(p->text)) && np && np->dle && tgood(T(np->text)[np->dle]) ) { 829 | ___mkd_freeLine(p); 830 | p = np; 831 | np = p->next; 832 | j = p->dle; 833 | } 834 | 835 | if ( (c = tgood(T(p->text)[j])) ) { 836 | /* Try to take the rest of the line as a comment; read to 837 | * EOL, then shrink the string back to before the final 838 | * quote. 839 | */ 840 | ++j; /* skip leading quote */ 841 | 842 | while ( j < S(p->text) ) 843 | EXPAND(foot->title) = T(p->text)[j++]; 844 | 845 | while ( S(foot->title) && T(foot->title)[S(foot->title)-1] != c ) 846 | --S(foot->title); 847 | if ( S(foot->title) ) /* skip trailing quote */ 848 | --S(foot->title); 849 | EXPAND(foot->title) = 0; 850 | --S(foot->title); 851 | } 852 | 853 | ___mkd_freeLine(p); 854 | return np; 855 | } 856 | 857 | 858 | /* 859 | * allocate a paragraph header, link it to the 860 | * tail of the current document 861 | */ 862 | static Paragraph * 863 | Pp(ParagraphRoot *d, Line *ptr, int typ) 864 | { 865 | Paragraph *ret = calloc(sizeof *ret, 1); 866 | 867 | ret->text = ptr; 868 | ret->typ = typ; 869 | 870 | return ATTACH(*d, ret); 871 | } 872 | 873 | 874 | 875 | static Line* 876 | consume(Line *ptr, int *eaten) 877 | { 878 | Line *next; 879 | int blanks=0; 880 | 881 | for (; ptr && blankline(ptr); ptr = next, blanks++ ) { 882 | next = ptr->next; 883 | ___mkd_freeLine(ptr); 884 | } 885 | if ( ptr ) *eaten = blanks; 886 | return ptr; 887 | } 888 | 889 | 890 | /* 891 | * top-level compilation; break the document into 892 | * style, html, and source blocks with footnote links 893 | * weeded out. 894 | */ 895 | static Paragraph * 896 | compile_document(Line *ptr, MMIOT *f) 897 | { 898 | ParagraphRoot d = { 0, 0 }; 899 | ANCHOR(Line) source = { 0, 0 }; 900 | Paragraph *p = 0; 901 | struct kw *tag; 902 | int eaten; 903 | 904 | while ( ptr ) { 905 | if ( !(f->flags & DENY_HTML) && (tag = isopentag(ptr)) ) { 906 | /* If we encounter a html/style block, compile and save all 907 | * of the cached source BEFORE processing the html/style. 908 | */ 909 | if ( T(source) ) { 910 | E(source)->next = 0; 911 | p = Pp(&d, 0, SOURCE); 912 | p->down = compile(T(source), 1, f); 913 | T(source) = E(source) = 0; 914 | } 915 | p = Pp(&d, ptr, strcmp(tag->id, "STYLE") == 0 ? STYLE : HTML); 916 | if ( strcmp(tag->id, "!--") == 0 ) 917 | ptr = comment(p); 918 | else 919 | ptr = htmlblock(p, tag); 920 | } 921 | else if ( isfootnote(ptr) ) { 922 | /* footnotes, like cats, sleep anywhere; pull them 923 | * out of the input stream and file them away for 924 | * later processing 925 | */ 926 | ptr = consume(addfootnote(ptr, f), &eaten); 927 | } 928 | else { 929 | /* source; cache it up to wait for eof or the 930 | * next html/style block 931 | */ 932 | ATTACH(source,ptr); 933 | ptr = ptr->next; 934 | } 935 | } 936 | if ( T(source) ) { 937 | /* if there's any cached source at EOF, compile 938 | * it now. 939 | */ 940 | E(source)->next = 0; 941 | p = Pp(&d, 0, SOURCE); 942 | p->down = compile(T(source), 1, f); 943 | } 944 | return T(d); 945 | } 946 | 947 | 948 | /* 949 | * break a collection of markdown input into 950 | * blocks of lists, code, html, and text to 951 | * be marked up. 952 | */ 953 | static Paragraph * 954 | compile(Line *ptr, int toplevel, MMIOT *f) 955 | { 956 | ParagraphRoot d = { 0, 0 }; 957 | Paragraph *p = 0; 958 | Line *r; 959 | int para = toplevel; 960 | int blocks = 0; 961 | int hdr_type, list_type, indent; 962 | 963 | ptr = consume(ptr, ¶); 964 | 965 | while ( ptr ) { 966 | if ( iscode(ptr) ) { 967 | p = Pp(&d, ptr, CODE); 968 | 969 | if ( f->flags & MKD_1_COMPAT) { 970 | /* HORRIBLE STANDARDS KLUDGE: the first line of every block 971 | * has trailing whitespace trimmed off. 972 | */ 973 | ___mkd_tidy(&p->text->text); 974 | } 975 | 976 | ptr = codeblock(p); 977 | } 978 | else if ( ishr(ptr) ) { 979 | p = Pp(&d, 0, HR); 980 | r = ptr; 981 | ptr = ptr->next; 982 | ___mkd_freeLine(r); 983 | } 984 | else if (( list_type = islist(ptr, &indent) )) { 985 | p = Pp(&d, ptr, list_type); 986 | ptr = listblock(p, indent, f); 987 | } 988 | else if ( isquote(ptr) ) { 989 | p = Pp(&d, ptr, QUOTE); 990 | ptr = quoteblock(p); 991 | p->down = compile(p->text, 1, f); 992 | p->text = 0; 993 | } 994 | else if ( ishdr(ptr, &hdr_type) ) { 995 | p = Pp(&d, ptr, HDR); 996 | ptr = headerblock(p, hdr_type); 997 | } 998 | else if ( istable(ptr) && !(f->flags & (STRICT|NOTABLES)) ) { 999 | p = Pp(&d, ptr, TABLE); 1000 | ptr = tableblock(p); 1001 | } 1002 | else { 1003 | p = Pp(&d, ptr, MARKUP); 1004 | ptr = textblock(p, toplevel); 1005 | } 1006 | 1007 | if ( (para||toplevel) && !p->align ) 1008 | p->align = PARA; 1009 | 1010 | blocks++; 1011 | para = toplevel || (blocks > 1); 1012 | ptr = consume(ptr, ¶); 1013 | 1014 | if ( para && !p->align ) 1015 | p->align = PARA; 1016 | 1017 | } 1018 | return T(d); 1019 | } 1020 | 1021 | 1022 | static void 1023 | initialize() 1024 | { 1025 | static int first = 1; 1026 | 1027 | if ( first-- > 0 ) { 1028 | first = 0; 1029 | INITRNG(time(0)); 1030 | qsort(blocktags, SZTAGS, sizeof blocktags[0], (stfu)casort); 1031 | } 1032 | } 1033 | 1034 | 1035 | /* 1036 | * the guts of the markdown() function, ripped out so I can do 1037 | * debugging. 1038 | */ 1039 | 1040 | /* 1041 | * prepare and compile `text`, returning a Paragraph tree. 1042 | */ 1043 | int 1044 | mkd_compile(Document *doc, int flags) 1045 | { 1046 | if ( !doc ) 1047 | return 0; 1048 | 1049 | if ( doc->compiled ) 1050 | return 1; 1051 | 1052 | doc->compiled = 1; 1053 | memset(doc->ctx, 0, sizeof(MMIOT) ); 1054 | doc->ctx->flags = flags & USER_FLAGS; 1055 | doc->ctx->base = doc->base; 1056 | CREATE(doc->ctx->in); 1057 | doc->ctx->footnotes = malloc(sizeof doc->ctx->footnotes[0]); 1058 | CREATE(*doc->ctx->footnotes); 1059 | 1060 | initialize(); 1061 | 1062 | doc->code = compile_document(T(doc->content), doc->ctx); 1063 | qsort(T(*doc->ctx->footnotes), S(*doc->ctx->footnotes), 1064 | sizeof T(*doc->ctx->footnotes)[0], 1065 | (stfu)__mkd_footsort); 1066 | memset(&doc->content, 0, sizeof doc->content); 1067 | return 1; 1068 | } 1069 | 1070 | --------------------------------------------------------------------------------