pax_global_header00006660000000000000000000000064110657047130014516gustar00rootroot0000000000000052 comment=8296fcbfd077a767380ab0320e2aaeae60c93c4d lua-discount-1.2.10.1/000077500000000000000000000000001106570471300143455ustar00rootroot00000000000000lua-discount-1.2.10.1/LICENSE000066400000000000000000000047021106570471300153550ustar00rootroot00000000000000The core Discount C sources are Copyright (C) 2007 David Loren Parsons. The Discount Lua extension sources are Copyright (C) 2008 A.S. Bradbury. Copyright (C) 2008 Tim Channon. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution, and in the same place and form as other copyright, license and disclaimer information. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: This product includes software developed by David Loren Parsons in the same place and form as other third-party acknowledgments. Alternately, this acknowledgment may appear in the software itself, in the same form and location as other such third-party acknowledgments. 4. Except as contained in this notice, the name of David Loren Parsons shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from David Loren Parsons. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID LOREN PARSONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. lua-discount-1.2.10.1/Makefile000066400000000000000000000012771106570471300160140ustar00rootroot00000000000000LIB_NAME= lua-discount VERSION= 1.2.10.1 # change these to reflect your Lua installation LUA= /usr LUAINC= $(LUA)/include LUALIB= $(LUA)/lib LUABIN= $(LUA)/bin # probably no need to change anything below here CC= gcc CFLAGS= $(INCS) $(WARN) -O2 -fPIC ${DEFS} WARN= -Wall INCS= -I$(LUAINC) DEFS = DISCOUNT_OBJS = docheader.o \ dumptree.o \ generate.o \ markdown.o \ mkdio.o \ resource.o OBJS= $(DISCOUNT_OBJS) ldiscount.o SOS= discount.so all: $(SOS) $(SOS): $(OBJS) $(CC) -o $@ -shared $(OBJS) $(LIBS) .PHONY: clean tar clean: rm -f $(OBJS) $(SOS) core core.* a.out tar: clean git archive --format=tar --prefix=$(LIB_NAME)-$(VERSION)/ $(VERSION) | gzip > $(LIB_NAME)-$(VERSION).tar.gz lua-discount-1.2.10.1/README.mkd000066400000000000000000000065431106570471300160070ustar00rootroot00000000000000# lua-discount A binding to [Discount](http://www.pell.portland.or.us/~orc/Code/discount/), a fast C implementation of the [Markdown](http://daringfireball.net/projects/markdown) text to HTML markup system. Discount passes the Markdown test suite. ## Project links * [Home](http://asbradbury.org/projects/lua-discount/) * [Download](http://luaforge.net/projects/lua-discount/) * [Documentation](http://asbradbury.org/projects/lua-discount/#usage) * [Source](http://github.com/asb/lua-discount/) ## Release history * lua-discount-1.2.10.1 (2008-09-22) * Windows is now a supported platform (thanks to contributions from Tim Channon) * lua-discount-1.2.10 (2008-09-03) * update to upstream Discount 1.2.10 * support the `"nohtml"` option, to disable embedded html. * compile to use relaxed emphasis, meaning underscores don't count when they're in the middle of a word. * add some tests * include results of a simple benchmark in the readme * lua-discount-1.2.7 (2008-08-03) * first public release ## See also * [Discount](http://www.pell.portland.or.us/~orc/Code/discount/) * [Markdown syntax](http://daringfireball.net/projects/markdown/syntax) * [markdown.lua](http://www.frykholm.se/files/markdown.lua) ## Performance Thanks to the underlying Discount implementation, lua-discount is incredibly fast. Benchmarking markdown.lua 0.32 against lua-discount 1.2.10 by parsing the [Markdown syntax document](http://daringfireball.net/projects/markdown/syntax.text) 100 times gives the following result (all figures are in seconds): user system total real lua-discount 0.170000 0.000000 0.170000 0.177374 markdown.lua 48.530000 0.000000 48.530000 48.524910 ## [Usage](id:usage) Note that `require("discount")` returns a single function, which you are responsible for giving a suitable name. Example: discount = require("discount") local markdown_string = [[ # Demonstration This is a demonstration of lua-discount. Passing the options `"nolinks"` disables links such as [this](http://example.com). ]] local html_string = discount(markdown_string, "nolinks") The `discount` function takes as its first argument the Markdown string to convert, and for its subsequent arguments takes any combination of the following strings as options: =`"nolinks"`= do not allow ` Homepage: lua-discount-1.2.10.1/amalloc.h000066400000000000000000000007541106570471300161340ustar00rootroot00000000000000/* * debugging malloc()/realloc()/calloc()/free() that attempts * to keep track of just what's been allocated today. */ #ifndef AMALLOC_D #define AMALLOC_D #include "config.h" #ifdef USE_AMALLOC extern void *amalloc(int); extern void *acalloc(int,int); extern void *arealloc(void*,int); extern void afree(void*); extern void adump(); #define malloc amalloc #define calloc acalloc #define realloc arealloc #define free afree #else #define adump() (void)1 #endif #endif/*AMALLOC_D*/ lua-discount-1.2.10.1/bench.lua000066400000000000000000000011061106570471300161250ustar00rootroot00000000000000require("Benchmark") require('markdown') discount = require('discount') local function read_file(fn) local file = assert(io.open(fn)) local contents = assert(file:read('*a')) file:close() return contents end local bench = Benchmark:new() local REPS = 100 local input = read_file("syntax.text") print("Benchmarking using http://daringfireball.net/projects/markdown/syntax.text\n") bench:add("lua-discount", function() for i=1, REPS do discount(input) end end) bench:add("markdown.lua", function() for i=1, REPS do markdown(input) end end) bench:run() lua-discount-1.2.10.1/config.h000066400000000000000000000003671106570471300157710ustar00rootroot00000000000000#undef USE_AMALLOC #ifdef WINDOWS #define strcasecmp stricmp #define strncasecmp strnicmp #endif #define DL_TAG_EXTENSION 1 #define TABSTOP 4 #define COINTOSS() (rand()&1) #define INITRNG(x) srand((unsigned int)x) #define RELAXED_EMPHASIS 1 lua-discount-1.2.10.1/cstring.h000066400000000000000000000042201106570471300161650ustar00rootroot00000000000000/* two template types: STRING(t) which defines a pascal-style string * of element (t) [STRING(char) is the closest to the pascal string], * and ANCHOR(t) which defines a baseplate that a linked list can be * built up from. [The linked list /must/ contain a ->next pointer * for linking the list together with.] */ #ifndef _CSTRING_D #define _CSTRING_D #include #include #include "amalloc.h" /* expandable Pascal-style string. */ #define STRING(type) struct { type *text; int size, alloc; } #define CREATE(x) T(x) = (void*)(S(x) = (x).alloc = 0) #define EXPAND(x) (S(x)++)[(S(x) < (x).alloc) \ ? (T(x)) \ : (T(x) = T(x) ? realloc(T(x), sizeof T(x)[0] * ((x).alloc += 100)) \ : malloc(sizeof T(x)[0] * ((x).alloc += 100)) )] #define DELETE(x) (x).alloc ? (free(T(x)), S(x) = (x).alloc = 0) \ : ( S(x) = 0 ) #define CLIP(t,i,sz) \ ( ((i) >= 0) && ((sz) > 0) && (((i)+(sz)) <= S(t)) ) ? \ (memmove(&T(t)[i], &T(t)[i+sz], (S(t)-(i+sz)+1)*sizeof(T(t)[0])), \ S(t) -= (sz)) : -1 #define RESERVE(x, sz) T(x) = ((x).alloc > S(x) + (sz) \ ? T(x) \ : T(x) \ ? realloc(T(x), sizeof T(x)[0] * ((x).alloc = 100+(sz)+S(x))) \ : malloc(sizeof T(x)[0] * ((x).alloc = 100+(sz)+S(x)))) #define SUFFIX(t,p,sz) \ memcpy(((S(t) += (sz)) - (sz)) + \ (T(t) = T(t) ? realloc(T(t), sizeof T(t)[0] * ((t).alloc += sz)) \ : malloc(sizeof T(t)[0] * ((t).alloc += sz))), \ (p), sizeof(T(t)[0])*(sz)) #define PREFIX(t,p,sz) \ RESERVE( (t), (sz) ); \ if ( S(t) ) { memmove(T(t)+(sz), T(t), S(t)); } \ memcpy( T(t), (p), (sz) ); \ S(t) += (sz) /* reference-style links (and images) are stored in an array */ #define T(x) (x).text #define S(x) (x).size /* abstract anchor type that defines a list base * with a function that attaches an element to * the end of the list. * * the list base field is named .text so that the T() * macro will work with it. */ #define ANCHOR(t) struct { t *text, *end; } #define ATTACH(t, p) ( (t).text ?( ((t).end->next = (p)), ((t).end = (p)) ) \ :( ((t).text = (t).end = (p)) ) ) typedef STRING(char) Cstring; #endif/*_CSTRING_D*/ lua-discount-1.2.10.1/docheader.c000066400000000000000000000015231106570471300164300ustar00rootroot00000000000000/* * docheader -- get values from the document header * * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include "config.h" #include #include #include #include "cstring.h" #include "markdown.h" #include "amalloc.h" #define afterdle(t) (T((t)->text) + (t)->dle) char * mkd_doc_title(Document *doc) { if ( doc && doc->headers ) return afterdle(doc->headers); return 0; } char * mkd_doc_author(Document *doc) { if ( doc && doc->headers && doc->headers->next ) return afterdle(doc->headers->next); return 0; } char * mkd_doc_date(Document *doc) { if ( doc && doc->headers && doc->headers->next && doc->headers->next->next ) return afterdle(doc->headers->next->next); return 0; } lua-discount-1.2.10.1/dumptree.c000066400000000000000000000052251106570471300163420ustar00rootroot00000000000000/* markdown: a C implementation of John Gruber's Markdown markup language. * * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include #include "markdown.h" #include "cstring.h" #include "amalloc.h" struct frame { int indent; char c; }; typedef STRING(struct frame) Stack; static char * Pptype(int typ) { switch (typ) { case WHITESPACE: return "whitespace"; case CODE : return "code"; case QUOTE : return "quote"; case MARKUP : return "markup"; case HTML : return "html"; case DL : return "dl"; case UL : return "ul"; case OL : return "ol"; case LISTITEM : return "item"; case HDR : return "header"; case HR : return "HR"; default : return "mystery node!"; } } static void pushpfx(int indent, char c, Stack *sp) { struct frame *q = &EXPAND(*sp); q->indent = indent; q->c = c; } static void poppfx(Stack *sp) { S(*sp)--; } static void changepfx(Stack *sp, char c) { char ch; if ( !S(*sp) ) return; ch = T(*sp)[S(*sp)-1].c; if ( ch == '+' || ch == '|' ) T(*sp)[S(*sp)-1].c = c; } static void printpfx(Stack *sp, FILE *f) { int i; char c; if ( !S(*sp) ) return; c = T(*sp)[S(*sp)-1].c; if ( c == '+' || c == '-' ) { fprintf(f, "--%c", c); T(*sp)[S(*sp)-1].c = (c == '-') ? ' ' : '|'; } else for ( i=0; i < S(*sp); i++ ) { if ( i ) fprintf(f, " "); fprintf(f, "%*s%c", T(*sp)[i].indent + 2, " ", T(*sp)[i].c); if ( T(*sp)[i].c == '`' ) T(*sp)[i].c = ' '; } fprintf(f, "--"); } static void dumptree(Paragraph *pp, Stack *sp, FILE *f) { int count; Line *p; int d; static char *Begin[] = { 0, "P", "center" }; while ( pp ) { if ( !pp->next ) changepfx(sp, '`'); printpfx(sp, f); d = fprintf(f, "[%s", Pptype(pp->typ)); if ( pp->align ) d += fprintf(f, ", <%s>", Begin[pp->align]); for (count=0, p=pp->text; p; ++count, (p = p->next) ) ; if ( count ) d += fprintf(f, ", %d line%s", count, (count==1)?"":"s"); d += fprintf(f, "]"); if ( pp->down ) { pushpfx(d, pp->down->next ? '+' : '-', sp); dumptree(pp->down, sp, f); poppfx(sp); } else fputc('\n', f); pp = pp->next; } } int mkd_dump(Document *doc, FILE *out, int flags, char *title) { Stack stack; if (mkd_compile(doc, flags) ) { CREATE(stack); pushpfx(fprintf(out, "%s", title), doc->code->next ? '+' : '-', &stack); dumptree(doc->code, &stack, out); DELETE(stack); mkd_cleanup(doc); return 0; } return -1; } lua-discount-1.2.10.1/generate.c000066400000000000000000000610401106570471300163040ustar00rootroot00000000000000/* markdown: a C implementation of John Gruber's Markdown markup language. * * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include #include #include #include #include #include #include "config.h" #include "cstring.h" #include "markdown.h" #include "amalloc.h" /* prefixes for */ static char *autoprefix[] = { "http://", "https://", "ftp://", "news://" }; #define SZAUTOPREFIX (sizeof autoprefix / sizeof autoprefix[0]) typedef int (*stfu)(const void*,const void*); /* forward declarations */ static void code(int, MMIOT*); static void text(MMIOT *f); static Paragraph *display(Paragraph*, MMIOT*); /* externals from markdown.c */ int __mkd_footsort(Footnote *, Footnote *); /* * push text into the generator input buffer */ static void push(char *bfr, int size, MMIOT *f) { while ( size-- > 0 ) EXPAND(f->in) = *bfr++; } /* look characters ahead of the cursor. */ static int peek(MMIOT *f, int i) { i += (f->isp-1); return (i >= 0) && (i < S(f->in)) ? T(f->in)[i] : EOF; } /* pull a byte from the input buffer */ static int pull(MMIOT *f) { return ( f->isp < S(f->in) ) ? T(f->in)[f->isp++] : EOF; } /* return a pointer to the current position in the input buffer. */ static char* cursor(MMIOT *f) { return T(f->in) + f->isp; } /* return/set the current cursor position */ #define mmiotseek(f,x) (f->isp = x) #define mmiottell(f) (f->isp) /* move n characters forward ( or -n characters backward) in the input buffer. */ static void shift(MMIOT *f, int i) { if (f->isp + i >= 0 ) f->isp += i; } /* Qchar() */ static void Qchar(char c, MMIOT *f) { block *cur; if ( S(f->Q) == 0 ) { cur = &EXPAND(f->Q); memset(cur, 0, sizeof *cur); cur->b_type = bTEXT; } else cur = &T(f->Q)[S(f->Q)-1]; EXPAND(cur->b_text) = c; } /* Qstring() */ static void Qstring(char *s, MMIOT *f) { while (*s) Qchar(*s++, f); } /* Qwrite() */ static void Qwrite(char *s, int size, MMIOT *f) { while (size-- > 0) Qchar(*s++, f); } /* Qprintf() */ static void Qprintf(MMIOT *f, char *fmt, ...) { char bfr[80]; va_list ptr; va_start(ptr,fmt); vsnprintf(bfr, sizeof bfr, fmt, ptr); va_end(ptr); Qstring(bfr, f); } /* Qem() */ static void Qem(MMIOT *f, char c, int count) { block *p = &EXPAND(f->Q); memset(p, 0, sizeof *p); p->b_type = (c == '*') ? bSTAR : bUNDER; p->b_char = c; p->b_count = count; memset(&EXPAND(f->Q), 0, sizeof(block)); } /* empair() */ static int empair(MMIOT *f, int go, int level) { int i; block *begin, *p; begin = &T(f->Q)[go]; for (i=go+1; i < S(f->Q); i++) { p = &T(f->Q)[i]; if ( (p->b_type != bTEXT) && (p->b_count <= 0) ) break; if ( p->b_type == begin->b_type ) { if ( p->b_count == level ) /* exact match */ return i-go; if ( p->b_count > 2 ) /* fuzzy match */ return i-go; } } return EOF; } static struct emtags { char open[10]; char close[10]; int size; } emtags[] = { { "" , "", 5 }, { "", "", 9 } }; static void emclose(Cstring *s, int level) { PREFIX(*s, emtags[level-1].close, emtags[level-1].size); } static void emopen(Cstring *s, int level) { SUFFIX(*s, emtags[level-1].open, emtags[level-1].size-1); } /* emmatch() */ static void emmatch(MMIOT *f, int go) { block *start = &T(f->Q)[go], *end; int e, e2, i, match; while ( start->b_count ) { switch (start->b_count) { case 2: e = empair(f,go,match=2); if ( e != EOF ) break; case 1: e = empair(f,go,match=1); break; default: e = empair(f,go,1); e2= empair(f,go,2); if ( e == EOF || ((e2 != EOF) && (e2 >= e)) ) { e = e2; match = 2; } else match = 1; } if ( e != EOF ) { end = &T(f->Q)[go+e]; emclose(&end->b_post, match); emopen(&start->b_text, match); end->b_count -= match; } else { for (i=0; i < match; i++) EXPAND(start->b_text) = start->b_char; } start->b_count -= match; } } /* emblock() */ static void emblock(MMIOT *f) { int i; block *p; for (i=0; i < S(f->Q); i++) { p = &T(f->Q)[i]; if ( p->b_type != bTEXT ) emmatch(f, i); if ( S(p->b_post) ) { SUFFIX(f->out, T(p->b_post), S(p->b_post)); DELETE(p->b_post); } if ( S(p->b_text) ) { SUFFIX(f->out, T(p->b_text), S(p->b_text)); DELETE(p->b_text); } } S(f->Q) = 0; } /* generate html from a markup fragment */ static void reparse(char *bfr, int size, int flags, MMIOT *f) { MMIOT sub; ___mkd_initmmiot(&sub, f->footnotes); sub.flags = f->flags | flags; sub.base = f->base; push(bfr, size, &sub); EXPAND(sub.in) = 0; S(sub.in)--; text(&sub); emblock(&sub); Qwrite(T(sub.out), S(sub.out), f); ___mkd_freemmiot(&sub, f->footnotes); } /* * write out a url, escaping problematic characters */ static void puturl(char *s, int size, MMIOT *f) { unsigned char c; while ( size-- > 0 ) { c = *s++; if ( c == '&' ) Qstring("&", f); else if ( c == '<' ) Qstring("<", f); else if ( isalnum(c) || c == '.' || c == '-' || c == '_' || c == '/' || c == '=' || c == '?' || c == ':' || c == '#' ) Qchar(c, f); else Qprintf(f, "%%%02X", c); } } /* advance forward until the next character is not whitespace */ static int eatspace(MMIOT *f) { int c; for ( ; ((c=peek(f, 1)) != EOF) && isspace(c); pull(f) ) ; return c; } /* (match (a (nested (parenthetical (string.))))) */ static int parenthetical(int in, int out, MMIOT *f) { int size, indent, c; for ( indent=1,size=0; indent; size++ ) { if ( (c = pull(f)) == EOF ) return EOF; else if ( c == in ) ++indent; else if ( c == out ) --indent; } return size-1; } /* extract a []-delimited label from the input stream. */ static char * linkylabel(MMIOT *f, int *sizep) { char *ptr = cursor(f); if ( (*sizep = parenthetical('[',']',f)) != EOF ) return ptr; return 0; } /* extract a (-prefixed url from the input stream. * the label is either of the format ``, where I * extract until I find a >, or it is of the format * `text`, where I extract until I reach a ')' or * whitespace. */ static char* linkyurl(MMIOT *f, int *sizep) { int size = 0; char *ptr; int c; if ( (c = eatspace(f)) == EOF ) return 0; ptr = cursor(f); if ( c == '<' ) { pull(f); ptr++; if ( (size = parenthetical('<', '>', f)) == EOF ) return 0; } else { for ( ; ((c=pull(f)) != ')') && !isspace(c); size++) if ( c == EOF ) return 0; if ( c == ')' ) shift(f, -1); } *sizep = size; return ptr; } /* extract a =HHHxWWW size from the input stream */ static int linkysize(MMIOT *f, int *heightp, int *widthp) { int height=0, width=0; int c; *heightp = 0; *widthp = 0; if ( (c = eatspace(f)) != '=' ) return (c != EOF); pull(f); /* eat '=' */ for ( c = pull(f); isdigit(c); c = pull(f)) width = (width * 10) + (c - '0'); if ( c == 'x' ) { for ( c = pull(f); isdigit(c); c = pull(f)) height = (height*10) + (c - '0'); if ( c != EOF ) { if ( !isspace(c) ) shift(f, -1); *heightp = height; *widthp = width; return 1; } } return 0; } /* extract a )-terminated title from the input stream. */ static char* linkytitle(MMIOT *f, int *sizep) { int countq=0, qc, c, size; char *ret, *lastqc = 0; eatspace(f); if ( (qc=pull(f)) != '"' && qc != '\'' && qc != '(' ) return 0; if ( qc == '(' ) qc = ')'; for ( ret = cursor(f); (c = pull(f)) != EOF; ) { if ( (c == ')') && countq ) { size = (lastqc ? lastqc : cursor(f)) - ret; *sizep = size-1; return ret; } else if ( c == qc ) { lastqc = cursor(f); countq++; } } return 0; } /* look up (or construct) a footnote from the [xxx] link * at the head of the stream. */ static int linkykey(int image, Footnote *val, MMIOT *f) { Footnote *ret; Cstring mylabel; memset(val, 0, sizeof *val); if ( (T(val->tag) = linkylabel(f, &S(val->tag))) == 0 ) return 0; eatspace(f); switch ( pull(f) ) { case '(': /* embedded link */ if ( (T(val->link) = linkyurl(f,&S(val->link))) == 0 ) return 0; if ( image && !linkysize(f, &val->height, &val->width) ) return 0; T(val->title) = linkytitle(f, &S(val->title)); return peek(f,0) == ')'; case '[': /* footnote link */ mylabel = val->tag; if ( (T(val->tag) = linkylabel(f, &S(val->tag))) == 0 ) return 0; if ( !S(val->tag) ) val->tag = mylabel; ret = bsearch(val, T(*f->footnotes), S(*f->footnotes), sizeof *val, (stfu)__mkd_footsort); if ( ret ) { val->tag = mylabel; val->link = ret->link; val->title = ret->title; val->height = ret->height; val->width = ret->width; return 1; } } return 0; } /* * all the tag types that linkylinky can produce are * defined by this structure. */ typedef struct linkytype { char *pat; int szpat; char *link_pfx; /* tag prefix and link pointer (eg: "" */ char *text_sfx; /* text suffix (eg: "" */ int flags; /* reparse flags */ } linkytype; static linkytype imaget = { 0, 0, "\"",", DENY_IMG|INSIDE_TAG }; static linkytype linkt = { 0, 0, "", "", DENY_A }; /* * pseudo-protocols for [][]; * * id: generates tag * class: generates tag * raw: just dump the link without any processing */ static linkytype specials[] = { { "id:", 3, "", "", 0 }, { "class:", 6, "", "", 0 }, { "raw:", 4, 0, 0, 0, 0, 0, 0 }, } ; #define NR(x) (sizeof x / sizeof x[0]) /* see if t contains one of our pseudo-protocols. */ static linkytype * extratag(Cstring t) { int i; linkytype *r; for ( i=0; i < NR(specials); i++ ) { r = &specials[i]; if ( (S(t) > r->szpat) && (strncasecmp(T(t), r->pat, r->szpat) == 0) ) return r; } return 0; } /* * process embedded links and images */ static int linkylinky(int image, MMIOT *f) { int start = mmiottell(f); Footnote link; linkytype *tag; if ( !linkykey(image, &link, f) ) { mmiotseek(f, start); return 0; } if ( image ) tag = &imaget; else if ( (f->flags & NO_PSEUDO_PROTO) || (tag = extratag(link.link)) == 0 ) tag = &linkt; if ( f->flags & tag-> flags ) { mmiotseek(f, start); return 0; } if ( tag->link_pfx ) { Qstring(tag->link_pfx, f); if ( f->base && (T(link.link)[tag->szpat] == '/') ) puturl(f->base, strlen(f->base), f); puturl(T(link.link) + tag->szpat, S(link.link) - tag->szpat, f); Qstring(tag->link_sfx, f); if ( tag->WxH && link.height && link.width ) { Qprintf(f," height=\"%d\"", link.height); Qprintf(f, " width=\"%d\"", link.width); } if ( S(link.title) ) { Qstring(" title=\"", f); reparse(T(link.title), S(link.title), INSIDE_TAG, f); Qchar('"', f); } Qstring(tag->text_pfx, f); reparse(T(link.tag), S(link.tag), tag->flags, f); Qstring(tag->text_sfx, f); } else Qwrite(T(link.link) + tag->szpat, S(link.link) - tag->szpat, f); return 1; } /* write a character to output, doing text escapes ( & -> &, * > -> > < -> < ) */ static void cputc(int c, MMIOT *f) { switch (c) { case '&': Qstring("&", f); break; case '>': Qstring(">", f); break; case '<': Qstring("<", f); break; default : Qchar(c, f); break; } } /* * convert an email address to a string of nonsense */ static void mangle(char *s, int len, MMIOT *f) { while ( len-- > 0 ) { Qstring("&#", f); Qprintf(f, COINTOSS() ? "x%02x;" : "%02d;", *((unsigned char*)(s++)) ); } } /* before letting a tag through, validate against * DENY_A and DENY_IMG */ static int forbidden_tag(MMIOT *f) { int c = toupper(peek(f, 1)); if ( f->flags & DENY_HTML ) return 1; if ( c == 'A' && (f->flags & DENY_A) && !isalnum(peek(f,2)) ) return 1; if ( c == 'I' && (f->flags & DENY_IMG) && strncasecmp(cursor(f)+1, "MG", 2) == 0 && !isalnum(peek(f,4)) ) return 1; return 0; } /* a < may be just a regular character, the start of an embedded html * tag, or the start of an . If it's an automatic * link, we also need to know if it's an email address because if it * is we need to mangle it in our futile attempt to cut down on the * spaminess of the rendered page. */ static int maybe_tag_or_link(MMIOT *f) { char *text; int c, size, i; int maybetag=1, maybeaddress=0; int mailto; if ( f->flags & INSIDE_TAG ) return 0; for ( size=0; ((c = peek(f,size+1)) != '>') && !isspace(c); size++ ) { if ( ! (c == '/' || isalnum(c) || c == '~') ) maybetag=0; if ( c == '@' ) maybeaddress=1; else if ( c == EOF ) return 0; } if ( size == 0 ) return 0; if ( maybetag || (size >= 3 && strncmp(cursor(f), "!--", 3) == 0) ) { Qstring(forbidden_tag(f) ? "<" : "<", f); while ( ((c = peek(f, 1)) != EOF) && (c != '>') ) cputc(pull(f), f); return 1; } if ( f->flags & DENY_A ) return 0; text = cursor(f); shift(f, size+1); for ( i=0; i < SZAUTOPREFIX; i++ ) if ( strncasecmp(text, autoprefix[i], strlen(autoprefix[i])) == 0 ) { Qstring("", f); puturl(text,size,f); Qstring("", f); return 1; } if ( maybeaddress ) { Qstring(" 7) && strncasecmp(text, "mailto:", 7) == 0 ) mailto = 7; else { mailto = 0; /* supply a mailto: protocol if one wasn't attached */ mangle("mailto:", 7, f); } mangle(text, size, f); Qstring("\">", f); mangle(text+mailto, size-mailto, f); Qstring("", f); return 1; } shift(f, -(size+1)); return 0; } /* maybe_tag_or_link */ static int isthisspace(MMIOT *f, int i) { int c = peek(f, i); return isspace(c) || (c == EOF); } static int isthisnonword(MMIOT *f, int i) { return isthisspace(f, i) || ispunct(peek(f,i)); } /* smartyquote code that's common for single and double quotes */ static int smartyquote(int *flags, char typeofquote, MMIOT *f) { int bit = (typeofquote == 's') ? 0x01 : 0x02; if ( bit & (*flags) ) { if ( isthisnonword(f,1) ) { Qprintf(f, "&r%cquo;", typeofquote); (*flags) &= ~bit; return 1; } } else if ( isthisnonword(f,-1) && peek(f,1) != EOF ) { Qprintf(f, "&l%cquo;", typeofquote); (*flags) |= bit; return 1; } return 0; } static int islike(MMIOT *f, char *s) { int len; int i; if ( s[0] == '<' ) { if ( !isthisnonword(f, -1) ) return 0; ++s; } if ( !(len = strlen(s)) ) return 0; if ( s[len-1] == '>' ) { if ( !isthisnonword(f,len-1) ) return 0; len--; } for (i=1; i < len; i++) if (tolower(peek(f,i)) != s[i]) return 0; return 1; } static struct smarties { char c0; char *pat; char *entity; int shift; } smarties[] = { { '\'', "'s>", "rsquo", 0 }, { '\'', "'t>", "rsquo", 0 }, { '-', "--", "mdash", 1 }, { '-', "<->", "ndash", 0 }, { '.', "...", "hellip", 2 }, { '.', ". . .", "hellip", 4 }, { '(', "(c)", "copy", 2 }, { '(', "(r)", "reg", 2 }, { '(', "(tm)", "trade", 3 }, { '3', "<3/4>", "frac34", 2 }, { '3', "<3/4ths>", "frac34", 2 }, { '1', "<1/2>", "frac12", 2 }, { '1', "<1/4>", "frac14", 2 }, { '1', "<1/4th>", "frac14", 2 }, { '&', "�", 0, 3 }, } ; #define NRSMART ( sizeof smarties / sizeof smarties[0] ) /* Smarty-pants-style chrome for quotes, -, ellipses, and (r)(c)(tm) */ static int smartypants(int c, int *flags, MMIOT *f) { int i; if ( f->flags & DENY_SMARTY ) return 0; for ( i=0; i < NRSMART; i++) if ( (c == smarties[i].c0) && islike(f, smarties[i].pat) ) { if ( smarties[i].entity ) Qprintf(f, "&%s;", smarties[i].entity); shift(f, smarties[i].shift); return 1; } switch (c) { case '<' : return 0; case '\'': if ( smartyquote(flags, 's', f) ) return 1; break; case '"': if ( smartyquote(flags, 'd', f) ) return 1; break; case '`': if ( peek(f, 1) == '`' ) { int j = 2; while ( (c=peek(f,j)) != EOF ) { if ( c == '\\' ) j += 2; else if ( c == '`' ) break; else if ( c == '\'' && peek(f, j+1) == '\'' ) { Qstring("“", f); reparse(cursor(f)+1, j-2, 0, f); Qstring("”", f); shift(f,j+1); return 1; } else ++j; } } break; } return 0; } /* smartypants */ #define tag_text(f) (f->flags & INSIDE_TAG) static void text(MMIOT *f) { int c, j; int rep; int smartyflags = 0; while ( (c = pull(f)) != EOF ) { if ( smartypants(c, &smartyflags, f) ) continue; switch (c) { case 0: break; case '>': if ( tag_text(f) ) Qstring(">", f); else Qchar(c, f); break; case '"': if ( tag_text(f) ) Qstring(""", f); else Qchar(c, f); break; case '!': if ( peek(f,1) == '[' ) { pull(f); if ( tag_text(f) || !linkylinky(1, f) ) Qstring("![", f); } else Qchar(c, f); break; case '[': if ( tag_text(f) || !linkylinky(0, f) ) Qchar(c, f); break; #if SUPERSCRIPT case '^': if ( isthisspace(f,-1) || isthisspace(f,1) ) Qchar(c,f); else { char *sup = cursor(f); int len = 0; Qstring("",f); while ( !isthisspace(f,1+len) ) { ++len; } shift(f,len); reparse(sup, len, 0, f); Qstring("", f); } break; #endif case '_': #if RELAXED_EMPHASIS /* If RELAXED_EMPHASIS, underscores don't count when * they're in the middle of a word. */ if ( (isthisspace(f,-1) && isthisspace(f,1)) || (isalnum(peek(f,-1)) && isalnum(peek(f,1))) ) { Qchar(c, f); break; } /* else fall into the regular old emphasis case */ #endif case '*': if ( tag_text(f) ) Qchar(c, f); else { for (rep = 1; peek(f,1) == c; pull(f) ) ++rep; Qem(f,c,rep); } break; case '`': if ( tag_text(f) ) Qchar(c, f); else { Qstring("", f); if ( peek(f, 1) == '`' ) { pull(f); code(2, f); } else code(1, f); Qstring("", f); } break; case '\\': switch ( c = pull(f) ) { case '&': Qstring("&", f); break; case '<': Qstring("<", f); break; case '\\': case '>': case '#': case '.': case '-': case '+': case '{': case '}': case ']': case '(': case ')': case '"': case '\'': case '!': case '[': case '*': case '_': case '`': Qchar(c, f); break; default: Qchar('\\', f); if ( c != EOF ) shift(f,-1); break; } break; case '<': if ( !maybe_tag_or_link(f) ) Qstring("<", f); break; case '&': j = (peek(f,1) == '#' ) ? 2 : 1; while ( isalnum(peek(f,j)) ) ++j; if ( peek(f,j) != ';' ) Qstring("&", f); else Qchar(c, f); break; default: Qchar(c, f); break; } } } /* text */ static int endofcode(int escape, int offset, MMIOT *f) { switch (escape) { case 2: if ( peek(f, offset+1) == '`' ) { shift(f,1); case 1: shift(f,offset); return 1; } default:return 0; } } /* the only characters that have special meaning in a code block are * `<' and `&' , which are /always/ expanded to < and & */ static void code(int escape, MMIOT *f) { int c; if ( escape && (peek(f,1) == ' ') ) shift(f,1); while ( (c = pull(f)) != EOF ) { switch (c) { case ' ': if ( peek(f,1) == '`' && endofcode(escape, 1, f) ) return; Qchar(c, f); break; case '`': if ( endofcode(escape, 0, f) ) return; Qchar(c, f); break; case '\\': cputc(c, f); if ( peek(f,1) == '>' || (c = pull(f)) == EOF ) break; default: cputc(c, f); break; } } } /* code */ /* print a header block */ static void printheader(Paragraph *pp, MMIOT *f) { Qprintf(f, "", pp->hnumber); push(T(pp->text->text), S(pp->text->text), f); text(f); Qprintf(f, "", pp->hnumber); } static int printblock(Paragraph *pp, MMIOT *f) { Line *t = pp->text; static char *Begin[] = { "", "

", "

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

","
" }; while (t) { if ( S(t->text) ) { if ( S(t->text) > 2 && T(t->text)[S(t->text)-2] == ' ' && T(t->text)[S(t->text)-1] == ' ') { push(T(t->text), S(t->text)-2, f); push("
\n", 6, f); } else { push(T(t->text), S(t->text), f); if ( t->next ) push("\n", 1, f); } } t = t->next; } Qstring(Begin[pp->align], f); text(f); Qstring(End[pp->align], f); return 1; } static void printcode(Line *t, MMIOT *f) { int blanks; for ( blanks = 0; t ; t = t->next ) if ( S(t->text) > t->dle ) { while ( blanks ) { push("\n", 1, f); --blanks; } push(T(t->text), S(t->text), f); push("\n", 1, f); } else blanks++; Qstring("
", f);
    code(0, f);
    Qstring("
", f); } static void printhtml(Line *t, MMIOT *f) { int blanks; for ( blanks=0; t ; t = t->next ) if ( S(t->text) ) { for ( ; blanks; --blanks ) Qchar('\n', f); Qwrite(T(t->text), S(t->text), f); Qchar('\n', f); } else blanks++; } static void htmlify(Paragraph *p, char *block, MMIOT *f) { emblock(f); if ( block ) Qprintf(f, "<%s>", block); emblock(f); while (( p = display(p, f) )) { emblock(f); Qstring("\n\n", f); } if ( block ) Qprintf(f, "", block); emblock(f); } #if DL_TAG_EXTENSION static void definitionlist(Paragraph *p, MMIOT *f) { Line *tag; if ( p ) { Qstring("
\n", f); for ( ; p ; p = p->next) { for ( tag = p->text; tag; tag = tag->next ) { Qstring("
", f); reparse(T(tag->text), S(tag->text), 0, f); Qstring("
\n", f); } htmlify(p->down, "dd", f); } Qstring("
", f); } } #endif static void listdisplay(int typ, Paragraph *p, MMIOT* f) { if ( p ) { Qprintf(f, "<%cl>\n", (typ==UL)?'u':'o'); for ( ; p ; p = p->next ) { htmlify(p->down, "li", f); Qchar('\n', f); } Qprintf(f, "\n", (typ==UL)?'u':'o'); } } /* dump out a Paragraph in the desired manner */ static Paragraph* display(Paragraph *p, MMIOT *f) { if ( !p ) return 0; switch ( p->typ ) { case STYLE: case WHITESPACE: break; case HTML: printhtml(p->text, f); break; case CODE: printcode(p->text, f); break; case QUOTE: htmlify(p->down, "blockquote", f); break; case UL: case OL: listdisplay(p->typ, p->down, f); break; #if DL_TAG_EXTENSION case DL: definitionlist(p->down, f); break; #endif case HR: Qstring("
", f); break; case HDR: printheader(p, f); break; default: printblock(p, f); break; } return p->next; } /* * dump out stylesheet sections. */ static int stylesheets(Paragraph *p, FILE *f) { Line* q; for ( ; p ; p = p->next ) { if ( p->typ == STYLE ) { for ( q = p->text; q ; q = q->next ) if ( fwrite(T(q->text), S(q->text), 1, f) == 1 ) putc('\n', f); else return EOF; } if ( p->down && (stylesheets(p->down, f) == EOF) ) return EOF; } return 0; } /* return a pointer to the compiled markdown * document. */ int mkd_document(Document *p, char **res) { if ( p && p->compiled ) { if ( ! p->html ) { htmlify(p->code, 0, p->ctx); p->html = 1; } *res = T(p->ctx->out); return S(p->ctx->out); } return EOF; } /* public interface for reparse() */ int mkd_text(char *bfr, int size, FILE *output, int flags) { MMIOT f; ___mkd_initmmiot(&f, 0); f.flags = flags & USER_FLAGS; reparse(bfr, size, 0, &f); emblock(&f); if ( flags & CDATA_OUTPUT ) ___mkd_xml(T(f.out), S(f.out), output); else fwrite(T(f.out), S(f.out), 1, output); ___mkd_freemmiot(&f, 0); return 0; } /* dump any embedded styles */ int mkd_style(Document *d, FILE *f) { if ( d && d->compiled ) return stylesheets(d->code, f); return EOF; } lua-discount-1.2.10.1/ldiscount.c000066400000000000000000000060211106570471300165140ustar00rootroot00000000000000#include #include #include "lua.h" #include "lauxlib.h" #include "markdown.h" /* copied from mkdio.h */ /* special flags for markdown() and mkd_text() */ #define MKD_NOLINKS 0x0001 /* don't do link processing, block tags */ #define MKD_NOIMAGE 0x0002 /* don't do image processing, block */ #define MKD_NOPANTS 0x0004 /* don't run smartypants() */ #define MKD_NOHTML 0x0008 /* don't allow raw html through AT ALL */ #define MKD_TAGTEXT 0x0020 /* don't expand `_` and `*` */ #define MKD_NO_EXT 0x0040 /* don't allow pseudo-protocols */ #define MKD_CDATA 0x0080 /* generate code for xml ![CDATA[...]] */ #define MKD_EMBED MKD_NOLINKS|MKD_NOIMAGE|MKD_TAGTEXT /* special flags for mkd_in() and mkd_string() */ #define MKD_NOHEADER 0x0100 /* don't process header blocks */ #define MKD_TABSTOP 0x0200 /* expand tabs to 4 spaces */ static const char *const discount_opts[] = { "nolinks", "noimages", "nopants", "nohtml", "tagtext", "noext", "cdata", "embed", NULL }; static const int discount_opts_codes[] = { MKD_NOLINKS, MKD_NOIMAGE, MKD_NOPANTS, MKD_NOHTML, MKD_TAGTEXT, MKD_NO_EXT, MKD_CDATA, MKD_EMBED }; /* routines duplicated from markdown source without filesystem access */ /* write output in XML format */ static void local___mkd_xml(char *p, int size, luaL_Buffer *b) { char c; while (size-- > 0) { if (!isascii(c = *p++)) continue; switch (c) { case '<': luaL_addlstring(b, "<", 4); break; case '>': luaL_addlstring(b, ">", 4); break; case '&': luaL_addlstring(b, "&", 5); break; case '"': luaL_addlstring(b, """, 6); break; case '\'':luaL_addlstring(b, "'", 6); break; default: luaL_addchar(b, c); } } } /* write the html to a buffer (xmlified if necessary) */ static int local_mkd_generatehtml(Document *p, luaL_Buffer *b) { char *doc; int szdoc; if ((szdoc = mkd_document(p, &doc)) != EOF) { if (p->ctx->flags & CDATA_OUTPUT) local___mkd_xml(doc, szdoc, b); else luaL_addlstring(b, doc, szdoc); luaL_addchar(b, '\n'); return 0; } return -1; } /* convert some markdown text to html. */ static int local_markdown(Document *document, luaL_Buffer *b, int flags) { if (mkd_compile(document, flags)) { local_mkd_generatehtml(document, b); mkd_cleanup(document); return 0; } return -1; } static int ldiscount(lua_State *L) { size_t len; const char *str = luaL_checklstring(L, 1, &len); int flags = 0; int num_args = lua_gettop(L); luaL_Buffer b; Document *doc; int ret, i; for (i = 2; i <= num_args; i++) { int opt_index = luaL_checkoption(L, i, NULL, discount_opts); flags |= discount_opts_codes[opt_index]; } luaL_buffinit(L, &b); doc = mkd_string(str, len, MKD_TABSTOP|MKD_NOHEADER); ret = local_markdown(doc, &b, flags); luaL_pushresult(&b); if (ret < 0) return luaL_error(L, "error in markdown conversion"); return 1; } LUALIB_API int luaopen_discount(lua_State *L) { lua_pushcfunction(L, ldiscount); return 1; } lua-discount-1.2.10.1/lua-discount-dev-1.rockspec000066400000000000000000000012601106570471300214200ustar00rootroot00000000000000package="lua-discount" version="dev-1" source = { url = "" } description = { summary = "Binding to a fast C implementation of the Markdown text-to-html markup system", homepage = "http://asbradbury.org/projects/lua-discount/", license = "BSD" } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { discount = { "docheader.c", "dumptree.c", "generate.c", "markdown.c", "mkdio.c", "resource.c", "ldiscount.c" } }, platforms = { windows = { modules = { discount = { defines = {"WINDOWS"} } } } } } lua-discount-1.2.10.1/markdown.c000066400000000000000000000404541106570471300163420ustar00rootroot00000000000000/* markdown: a C implementation of John Gruber's Markdown markup language. * * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include #include #include #include #include #include #include "config.h" #include "cstring.h" #include "markdown.h" #include "amalloc.h" /* block-level tags for passing html blocks through the blender */ struct kw { char *id; int siz; } ; #define KW(x) { x, sizeof(x)-1 } static struct kw blocktags[] = { KW("!--"), KW("STYLE"), KW("SCRIPT"), KW("ADDRESS"), KW("BDO"), KW("BLOCKQUOTE"), KW("CENTER"), KW("DFN"), KW("DIV"), KW("H1"), KW("H2"), KW("H3"), KW("H4"), KW("H5"), KW("H6"), KW("LISTING"), KW("NOBR"), KW("UL"), KW("P"), KW("OL"), KW("DL"), KW("PLAINTEXT"), KW("PRE"), KW("TABLE"), KW("WBR"), KW("XMP"), KW("HR"), KW("BR") }; #define SZTAGS (sizeof blocktags / sizeof blocktags[0]) #define MAXTAG 11 /* sizeof "BLOCKQUOTE" */ typedef int (*stfu)(const void*,const void*); typedef ANCHOR(Paragraph) ParagraphRoot; /* case insensitive string sort (for qsort() and bsearch() of block tags) */ static int casort(struct kw *a, struct kw *b) { if ( a->siz != b->siz ) return a->siz - b->siz; return strncasecmp(a->id, b->id, b->siz); } /* case insensitive string sort for Footnote tags. */ int __mkd_footsort(Footnote *a, Footnote *b) { int i; char ac, bc; if ( S(a->tag) != S(b->tag) ) return S(a->tag) - S(b->tag); for ( i=0; i < S(a->tag); i++) { ac = tolower(T(a->tag)[i]); bc = tolower(T(b->tag)[i]); if ( isspace(ac) && isspace(bc) ) continue; if ( ac != bc ) return ac - bc; } return 0; } /* find the first blank character after position */ static int nextblank(Line *t, int i) { while ( (i < S(t->text)) && !isspace(T(t->text)[i]) ) ++i; return i; } /* find the next nonblank character after position */ static int nextnonblank(Line *t, int i) { while ( (i < S(t->text)) && isspace(T(t->text)[i]) ) ++i; return i; } /* find the first nonblank character on the Line. */ int mkd_firstnonblank(Line *p) { return nextnonblank(p,0); } static int blankline(Line *p) { return ! (p && (S(p->text) > p->dle) ); } static Line * skipempty(Line *p) { while ( p && (p->dle == S(p->text)) ) p = p->next; return p; } static char * isopentag(Line *p) { int i=0, len; struct kw key, *ret; if ( !p ) return 0; len = S(p->text); if ( len < 3 || T(p->text)[0] != '<' ) return 0; /* find how long the tag is so we can check to see if * it's a block-level tag */ for ( i=1; i < len && T(p->text)[i] != '>' && T(p->text)[i] != '/' && !isspace(T(p->text)[i]); ++i ) ; key.id = T(p->text)+1; key.siz = i-1; if ( ret = bsearch(&key,blocktags,SZTAGS,sizeof key, (stfu)casort)) return ret->id; return 0; } static int selfclose(Line *t, char *tag) { char *q = T(t->text); int siz = strlen(tag); int i; if ( strcasecmp(tag, "HR") == 0 || strcasecmp(tag, "BR") == 0 ) /*
and
are self-closing block-level tags, */ return 1; i = S(t->text) - (siz + 3); /* we specialcase start and end tags on the same line. */ return ( i > 0 ) && (q[i] == '<') && (q[i+1] == '/') && (q[i+2+siz] == '>') && (strncasecmp(&q[i+2], tag, siz) == 0); } static Line * htmlblock(Paragraph *p, char *tag) { Line *t = p->text, *ret; int closesize; char close[MAXTAG+4]; if ( selfclose(t, tag) || (strlen(tag) >= MAXTAG) ) { ret = t->next; t->next = 0; return ret; } closesize = sprintf(close, "", tag); for ( ; t ; t = t->next) { if ( strncasecmp(T(t->text), close, closesize) == 0 ) { ret = t->next; t->next = 0; return ret; } } return 0; } static Line * comment(Paragraph *p, char *key) { Line *t, *ret; for ( t = p->text; t ; t = t->next) { if ( strstr(T(t->text), "-->") ) { ret = t->next; t->next = 0; return ret; } } return t; } /* footnotes look like ^{0,3}[stuff]: $ */ static int isfootnote(Line *t) { int i; if ( ( (i = t->dle) > 3) || (T(t->text)[i] != '[') ) return 0; for ( ++i; i < S(t->text) ; ++i ) { if ( T(t->text)[i] == '[' ) return 0; else if ( T(t->text)[i] == ']' && T(t->text)[i+1] == ':' ) return 1; } return 0; } static int isquote(Line *t) { return ( T(t->text)[0] == '>' ); } static int dashchar(char c) { return (c == '*') || (c == '-') || (c == '_'); } static int iscode(Line *t) { return (t->dle >= 4); } static int ishr(Line *t) { int i, count=0; char dash = 0; char c; if ( iscode(t) ) return 0; for ( i = 0; i < S(t->text); i++) { c = T(t->text)[i]; if ( (dash == 0) && dashchar(c) ) dash = c; if ( c == dash ) ++count; else if ( !isspace(c) ) return 0; } return (count >= 3); } static int ishdr(Line *t, int *htyp) { int i, j; /* first check for etx-style ###HEADER### */ /* leading run of `#`'s ? */ for ( i=0; T(t->text)[i] == '#'; ++i) ; if ( i ) { i = nextnonblank(t, i); j = S(t->text)-1; while ( (j > i) && (T(t->text)[j] == '#') ) --j; while ( (j > 1) && isspace(T(t->text)[j]) ) --j; if ( i < j ) { *htyp = ETX; return 1; } } /* then check for setext-style HEADER * ====== */ if ( t->next ) { char *q = T(t->next->text); if ( (*q == '=') || (*q == '-') ) { for (i=1; i < S(t->next->text); i++) if ( q[0] != q[i] ) return 0; *htyp = SETEXT; return 1; } } return 0; } static int isdefinition(Line *t) { #if DL_TAG_EXTENSION return t && t->next && (S(t->text) > 2) && (t->dle == 0) && (T(t->text)[0] == '=') && (T(t->text)[S(t->text)-1] == '=') && ( (t->next->dle >= 4) || isdefinition(t->next) ); #else return 0; #endif } static int islist(Line *t, int *trim) { int i, j; char *q; if ( iscode(t) || blankline(t) || ishdr(t,&i) || ishr(t) ) return 0; if ( isdefinition(t) ) { *trim = 4; return DL; } if ( strchr("*-+", T(t->text)[t->dle]) && isspace(T(t->text)[t->dle+1]) ) { i = nextnonblank(t, t->dle+1); *trim = (i > 4) ? 4 : i; return UL; } if ( (j = nextblank(t,t->dle)) > t->dle ) { if ( T(t->text)[j-1] == '.' ) { strtoul(T(t->text)+t->dle, &q, 10); if ( (q > T(t->text)+t->dle) && (q == T(t->text) + (j-1)) ) { j = nextnonblank(t,j); *trim = j; return OL; } } } return 0; } static Line * headerblock(Paragraph *pp, int htyp) { Line *ret = 0; Line *p = pp->text; int i, j; switch (htyp) { case SETEXT: /* p->text is header, p->next->text is -'s or ='s */ pp->hnumber = (T(p->next->text)[0] == '=') ? 1 : 2; ret = p->next->next; ___mkd_freeLine(p->next); p->next = 0; break; case ETX: /* p->text is ###header###, so we need to trim off * the leading and trailing `#`'s */ for (i=0; T(p->text)[i] == T(p->text)[0]; i++) ; pp->hnumber = i; while ( (i < S(p->text)) && isspace(T(p->text)[i]) ) ++i; CLIP(p->text, 0, i); for (j=S(p->text); j && (T(p->text)[j-1] == '#'); --j) ; S(p->text) = j; ret = p->next; p->next = 0; break; } return ret; } static Line * codeblock(Paragraph *p) { Line *t = p->text, *r; /* HORRIBLE STANDARDS KLUDGE: the first line of every block * has trailing whitespace trimmed off. */ while ( S(t->text) && isspace(T(t->text)[S(t->text)-1]) ) --S(t->text); for ( ; t; t = r ) { CLIP(t->text,0,4); t->dle = mkd_firstnonblank(t); if ( !( (r = skipempty(t->next)) && iscode(r)) ) { ___mkd_freeLineRange(t,r); t->next = 0; return r; } } return t; } static int centered(Line *first, Line *last) { if ( first&&last ) { int len = S(last->text); if ( (len > 2) && (strncmp(T(first->text), "->", 2) == 0) && (strncmp(T(last->text)+len-2, "<-", 2) == 0) ) { CLIP(first->text, 0, 2); S(last->text) -= 2; return CENTER; } } return 0; } static int endoftextblock(Line *t, int toplevelblock) { int z; if ( blankline(t)||isquote(t)||iscode(t)||ishdr(t,&z)||ishr(t) ) return 1; /* HORRIBLE STANDARDS KLUDGE: Toplevel paragraphs eat absorb adjacent * list items, but sublevel blocks behave properly. */ return toplevelblock ? 0 : islist(t,&z); } static Line * textblock(Paragraph *p, int toplevel) { Line *t, *next; for ( t = p->text; t ; t = next ) if ( ((next = t->next) == 0) || endoftextblock(next, toplevel) ) { p->align = centered(p->text, t); t->next = 0; return next; } return t; } /* * accumulate a blockquote. * * one sick horrible thing about blockquotes is that even though * it just takes ^> to start a quote, following lines, if quoted, * assume that the prefix is ``>''. This means that code needs * to be indented *5* spaces from the leading '>', but *4* spaces * from the start of the line. This does not appear to be * documented in the reference implementation, but it's the * way the markdown sample web form at Daring Fireball works. */ static Line * quoteblock(Paragraph *p) { Line *t, *q; int qp; for ( t = p->text; t ; t = q ) { if ( isquote(t) ) { qp = (T(t->text)[1] == ' ') ? 2 : 1; CLIP(t->text, 0, qp); t->dle = mkd_firstnonblank(t); } if ( !(q = skipempty(t->next)) || ((q != t->next) && !isquote(q)) ) { ___mkd_freeLineRange(t, q); return q; } } return t; } static Paragraph *Pp(ParagraphRoot *, Line *, int); static Paragraph *compile(Line *, int, MMIOT *); /* * pull in a list block. A list block starts with a list marker and * runs until the next list marker, the next non-indented paragraph, * or EOF. You do not have to indent nonblank lines after the list * marker, but multiple paragraphs need to start with a 4-space indent. */ static Line * listitem(Paragraph *p, int indent) { Line *t, *q; int clip = indent; int z; for ( t = p->text; t ; t = q) { CLIP(t->text, 0, clip); t->dle = mkd_firstnonblank(t); if ( (q = skipempty(t->next)) == 0 ) { ___mkd_freeLineRange(t,q); return 0; } /* after a blank line, the next block needs to start with a line * that's indented 4 spaces, but after that the line doesn't * need any indentation */ if ( q != t->next ) { if (q->dle < 4) { q = t->next; t->next = 0; return q; } indent = 4; } if ( (q->dle < indent) && (ishr(q) || ishdr(q,&z) || islist(q,&z)) ) { q = t->next; t->next = 0; return q; } clip = (q->dle > indent) ? indent : q->dle; } return t; } static Line * listblock(Paragraph *top, int trim, MMIOT *f) { ParagraphRoot d = { 0, 0 }; Paragraph *p; Line *q = top->text, *text; Line *label; int para = 0; while (( text = q )) { if ( top->typ == DL ) { Line *lp; for ( lp = label = text; lp ; lp = lp->next ) { text = lp->next; CLIP(lp->text, 0, 1); S(lp->text)--; if ( !isdefinition(lp->next) ) lp->next = 0; } } else label = 0; p = Pp(&d, text, LISTITEM); text = listitem(p, trim); p->down = compile(p->text, 0, f); p->text = label; if ( para && (top->typ != DL) ) p->down->align = PARA; if ( !(q = skipempty(text)) || (islist(q,&trim) != top->typ) ) break; if ( para = (q != text) ) { Line anchor; anchor.next = text; ___mkd_freeLineRange(&anchor, q); } if ( para && (top->typ != DL) ) p->down->align = PARA; } top->text = 0; top->down = T(d); return text; } static int tgood(char c) { switch (c) { case '\'': case '"': return c; case '(': return ')'; } return 0; } /* * add a new (image or link) footnote to the footnote table */ static Line* addfootnote(Line *p, MMIOT* f) { int j, i; int c; Line *np = p->next; Footnote *foot = &EXPAND(*f->footnotes); CREATE(foot->tag); CREATE(foot->link); CREATE(foot->title); foot->height = foot->width = 0; for (j=i=p->dle+1; T(p->text)[j] != ']'; j++) EXPAND(foot->tag) = T(p->text)[j]; EXPAND(foot->tag) = 0; S(foot->tag)--; j = nextnonblank(p, j+2); while ( (j < S(p->text)) && !isspace(T(p->text)[j]) ) EXPAND(foot->link) = T(p->text)[j++]; EXPAND(foot->link) = 0; S(foot->link)--; j = nextnonblank(p,j); if ( T(p->text)[j] == '=' ) { sscanf(T(p->text)+j, "=%dx%d", &foot->width, &foot->height); while ( (j < S(p->text)) && !isspace(T(p->text)[j]) ) ++j; j = nextnonblank(p,j); } if ( (j >= S(p->text)) && np && np->dle && tgood(T(np->text)[np->dle]) ) { ___mkd_freeLine(p); p = np; np = p->next; j = p->dle; } if ( (c = tgood(T(p->text)[j])) ) { /* Try to take the rest of the line as a comment; read to * EOL, then shrink the string back to before the final * quote. */ ++j; /* skip leading quote */ while ( j < S(p->text) ) EXPAND(foot->title) = T(p->text)[j++]; while ( S(foot->title) && T(foot->title)[S(foot->title)-1] != c ) --S(foot->title); if ( S(foot->title) ) /* skip trailing quote */ --S(foot->title); EXPAND(foot->title) = 0; --S(foot->title); } ___mkd_freeLine(p); return np; } /* * allocate a paragraph header, link it to the * tail of the current document */ static Paragraph * Pp(ParagraphRoot *d, Line *ptr, int typ) { Paragraph *ret = calloc(sizeof *ret, 1); ret->text = ptr; ret->typ = typ; return ATTACH(*d, ret); } static Line* consume(Line *ptr, int *eaten) { Line *next; int blanks=0; for (; ptr && blankline(ptr); ptr = next, blanks++ ) { next = ptr->next; ___mkd_freeLine(ptr); } if ( ptr ) *eaten = blanks; return ptr; } /* * break a collection of markdown input into * blocks of lists, code, html, and text to * be marked up. */ static Paragraph * compile(Line *ptr, int toplevel, MMIOT *f) { ParagraphRoot d = { 0, 0 }; Paragraph *p = 0; char *key; Line *r; int para = toplevel; int hdr_type, list_type, indent; ptr = consume(ptr, ¶); while ( ptr ) { if ( toplevel && !(f->flags & DENY_HTML) && (key = isopentag(ptr)) ) { p = Pp(&d, ptr, strcmp(key, "STYLE") == 0 ? STYLE : HTML); if ( strcmp(key, "!--") == 0 ) ptr = comment(p, key); else ptr = htmlblock(p, key); } else if ( iscode(ptr) ) { p = Pp(&d, ptr, CODE); ptr = codeblock(p); } else if ( ishr(ptr) ) { p = Pp(&d, 0, HR); r = ptr; ptr = ptr->next; ___mkd_freeLine(r); } else if (( list_type = islist(ptr, &indent) )) { p = Pp(&d, ptr, list_type); ptr = listblock(p, indent, f); } else if ( isquote(ptr) ) { p = Pp(&d, ptr, QUOTE); ptr = quoteblock(p); p->down = compile(p->text, 1, f); p->text = 0; } else if ( ishdr(ptr, &hdr_type) ) { p = Pp(&d, ptr, HDR); ptr = headerblock(p, hdr_type); } else if ( toplevel && (isfootnote(ptr)) ) { ptr = consume(addfootnote(ptr, f), ¶); continue; } else { p = Pp(&d, ptr, MARKUP); ptr = textblock(p, toplevel); } if ( (para||toplevel) && !p->align ) p->align = PARA; para = toplevel; ptr = consume(ptr, ¶); if ( para && !p->align ) p->align = PARA; } return T(d); } static void initialize() { static int first = 1; if ( first-- > 0 ) { first = 0; INITRNG(time(0)); qsort(blocktags, SZTAGS, sizeof blocktags[0], (stfu)casort); } } /* * the guts of the markdown() function, ripped out so I can do * debugging. */ /* * prepare and compile `text`, returning a Paragraph tree. */ int mkd_compile(Document *doc, int flags) { if ( !doc ) return 0; if ( doc->compiled ) return 1; doc->compiled = 1; memset(doc->ctx, 0, sizeof(MMIOT) ); doc->ctx->flags = flags & USER_FLAGS; doc->ctx->base = doc->base; CREATE(doc->ctx->in); doc->ctx->footnotes = malloc(sizeof doc->ctx->footnotes[0]); CREATE(*doc->ctx->footnotes); initialize(); doc->code = compile(T(doc->content), 1, doc->ctx); qsort(T(*doc->ctx->footnotes), S(*doc->ctx->footnotes), sizeof T(*doc->ctx->footnotes)[0], (stfu)__mkd_footsort); memset(&doc->content, 0, sizeof doc->content); return 1; } lua-discount-1.2.10.1/markdown.h000066400000000000000000000073121106570471300163430ustar00rootroot00000000000000#ifndef _MARKDOWN_D #define _MARKDOWN_D #include "cstring.h" /* reference-style links (and images) are stored in an array * of footnotes. */ typedef struct footnote { Cstring tag; /* the tag for the reference link */ Cstring link; /* what this footnote points to */ Cstring title; /* what it's called (TITLE= attribute) */ int height, width; /* dimensions (for image link) */ } Footnote; /* each input line is read into a Line, which contains the line, * the offset of the first non-space character [this assumes * that all tabs will be expanded to spaces!], and a pointer to * the next line. */ typedef struct line { Cstring text; struct line *next; int dle; } Line; /* a paragraph is a collection of Lines, with links to the next paragraph * and (if it's a QUOTE, UL, or OL) to the reparsed contents of this * paragraph. */ typedef struct paragraph { struct paragraph *next; /* next paragraph */ struct paragraph *down; /* recompiled contents of this paragraph */ struct line *text; /* all the text in this paragraph */ enum { WHITESPACE=0, CODE, QUOTE, MARKUP, HTML, STYLE, DL, UL, OL, LISTITEM, HDR, HR } typ; enum { IMPLICIT=0, PARA, CENTER} align; int hnumber; /* for typ == HDR */ } Paragraph; enum { ETX, SETEXT }; /* header types */ typedef struct block { enum { bTEXT, bSTAR, bUNDER } b_type; int b_count; char b_char; Cstring b_text; Cstring b_post; } block; typedef STRING(block) Qblock; /* a magic markdown io thing holds all the data structures needed to * do the backend processing of a markdown document */ typedef struct mmiot { Cstring out; Cstring in; Qblock Q; int isp; STRING(Footnote) *footnotes; int flags; #define DENY_A 0x0001 #define DENY_IMG 0x0002 #define DENY_SMARTY 0x0004 #define DENY_HTML 0x0008 #define INSIDE_TAG 0x0020 #define NO_PSEUDO_PROTO 0x0040 #define CDATA_OUTPUT 0x0080 #define USER_FLAGS 0x00FF #define EMBEDDED DENY_A|DENY_IMG|NO_PSEUDO_PROTO|CDATA_OUTPUT char *base; } MMIOT; /* * the mkdio text input functions return a document structure, * which contains a header (retrieved from the document if * markdown was configured * with the * --enable-pandoc-header * and the document begins with a pandoc-style header) and the * root of the linked list of Lines. */ typedef struct document { Line *headers; /* title -> author(s) -> date */ ANCHOR(Line) content; /* uncompiled text, not valid after compile() */ Paragraph *code; /* intermediate code generated by compile() */ int compiled; /* set after mkd_compile() */ int html; /* set after (internal) htmlify() */ int tabstop; /* for properly expanding tabs (ick) */ MMIOT *ctx; /* backend buffers, flags, and structures */ char *base; /* url basename for url fragments */ } Document; extern int mkd_firstnonblank(Line *); extern int mkd_compile(Document *, int); extern int mkd_document(Document *, char **); extern int mkd_generatehtml(Document *, FILE *); extern void mkd_cleanup(Document *); extern int mkd_text(char *, int, FILE*, int); extern void mkd_basename(Document*, char *); extern Document *mkd_in(FILE *, int); extern Document *mkd_string(char*,int, int); #define NO_HEADER 0x0100 #define STD_TABSTOP 0x0200 #define INPUT_MASK (NO_HEADER|STD_TABSTOP) /* internal resource handling functions. */ extern void ___mkd_freeLine(Line *); extern void ___mkd_freeLines(Line *); extern void ___mkd_freeParagraph(Paragraph *); extern void ___mkd_freefootnotes(MMIOT *); extern void ___mkd_initmmiot(MMIOT *, void *); extern void ___mkd_freemmiot(MMIOT *, void *); extern void ___mkd_freeLineRange(Line *, Line *); extern void ___mkd_xml(char *, int, FILE *); #endif/*_MARKDOWN_D*/ lua-discount-1.2.10.1/mkdio.c000066400000000000000000000100671106570471300156200ustar00rootroot00000000000000/* * mkdio -- markdown front end input functions * * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include "config.h" #include #include #include #include "cstring.h" #include "markdown.h" #include "amalloc.h" typedef ANCHOR(Line) LineAnchor; /* create a new blank Document */ static Document* new_Document() { Document *ret = calloc(sizeof(Document), 1); if ( ret ) { if (( ret->ctx = calloc(sizeof(MMIOT), 1) )) return ret; free(ret); } return 0; } /* add a line to the markdown input chain */ static void queue(Document* a, Cstring *line) { Line *p = calloc(sizeof *p, 1); unsigned char c; int xp = 0; int size = S(*line); unsigned char *str = (unsigned char*)T(*line); CREATE(p->text); ATTACH(a->content, p); while ( size-- ) { if ( (c = *str++) == '\t' ) { /* expand tabs into ->tabstop spaces. We use ->tabstop * because the ENTIRE FREAKING COMPUTER WORLD uses editors * that don't do ^T/^D, but instead use tabs for indentation, * and, of course, set their tabs down to 4 spaces */ do { EXPAND(p->text) = ' '; } while ( ++xp % a->tabstop ); } else if ( c >= ' ' ) { EXPAND(p->text) = c; ++xp; } } EXPAND(p->text) = 0; S(p->text)--; p->dle = mkd_firstnonblank(p); } #ifdef PANDOC_HEADER /* trim leading blanks from a header line */ static void snip(Line *p) { CLIP(p->text, 0, 1); p->dle = mkd_firstnonblank(p); } #endif /* build a Document from any old input. */ typedef int (*getc_func)(void*); Document * populate(getc_func getc, void* ctx, int flags) { Cstring line; Document *a = new_Document(); int c; #ifdef PANDOC_HEADER int pandoc = 0; #endif if ( !a ) return 0; a->tabstop = (flags & STD_TABSTOP) ? 4 : TABSTOP; CREATE(line); while ( (c = (*getc)(ctx)) != EOF ) { if ( c == '\n' ) { #ifdef PANDOC_HEADER if ( pandoc != EOF && pandoc < 3 ) { if ( S(line) && (T(line)[0] == '%') ) pandoc++; else pandoc = EOF; } #endif queue(a, &line); S(line) = 0; } else EXPAND(line) = c; } if ( S(line) ) queue(a, &line); DELETE(line); #ifdef PANDOC_HEADER if ( (pandoc == 3) && !(flags & NO_HEADER) ) { /* the first three lines started with %, so we have a header. * clip the first three lines out of content and hang them * off header. */ a->headers = T(a->content); T(a->content) = a->headers->next->next->next; a->headers->next->next->next = 0; snip(a->headers); snip(a->headers->next); snip(a->headers->next->next); } #endif return a; } /* convert a file into a linked list */ Document * mkd_in(FILE *f, int flags) { return populate((getc_func)fgetc, f, flags & INPUT_MASK); } /* return a single character out of a buffer */ struct string_ctx { char *data; /* the unread data */ int size; /* and how much is there? */ } ; static int strget(struct string_ctx *in) { if ( !in->size ) return EOF; --(in->size); return *(in->data)++; } /* convert a block of text into a linked list */ Document * mkd_string(char *buf, int len, int flags) { struct string_ctx about; about.data = buf; about.size = len; return populate((getc_func)strget, &about, flags & INPUT_MASK); } /* write the html to a file (xmlified if necessary) */ int mkd_generatehtml(Document *p, FILE *output) { char *doc; int szdoc; if ( (szdoc = mkd_document(p, &doc)) != EOF ) { if ( p->ctx->flags & CDATA_OUTPUT ) ___mkd_xml(doc, szdoc, output); else fwrite(doc, szdoc, 1, output); putc('\n', output); return 0; } return -1; } /* convert some markdown text to html */ int markdown(Document *document, FILE *out, int flags) { if ( mkd_compile(document, flags) ) { mkd_generatehtml(document, out); mkd_cleanup(document); return 0; } return -1; } void mkd_basename(Document *document, char *base) { if ( document ) document->base = base; } lua-discount-1.2.10.1/mkdio.h000066400000000000000000000030661106570471300156260ustar00rootroot00000000000000#ifndef _MKDIO_D #define _MKDIO_D #include typedef void MMIOT; /* line builder for markdown() */ MMIOT *mkd_in(FILE*,int); /* assemble input from a file */ MMIOT *mkd_string(char*,int,int); /* assemble input from a buffer */ void mkd_basename(MMIOT*,char*); /* compilation, debugging, cleanup */ int mkd_compile(MMIOT*, int); int mkd_generatehtml(MMIOT*,FILE*); int mkd_cleanup(MMIOT*); /* markup functions */ int mkd_text(char *, int, FILE*, int); int mkd_style(MMIOT*, FILE*); int mkd_dump(MMIOT*, FILE*, int, char*); int markdown(MMIOT*, FILE*, int); void mkd_basename(MMIOT*,char*); /* header block access */ char* mkd_doc_title(MMIOT*); char* mkd_doc_author(MMIOT*); char* mkd_doc_date(MMIOT*); /* compiled data access */ int mkd_document(MMIOT*, char**); /* version#. */ extern char markdown_version[]; /* special flags for markdown() and mkd_text() */ #define MKD_NOLINKS 0x0001 /* don't do link processing, block
tags */ #define MKD_NOIMAGE 0x0002 /* don't do image processing, block */ #define MKD_NOPANTS 0x0004 /* don't run smartypants() */ #define MKD_NOHTML 0x0008 /* don't allow raw html through AT ALL */ #define MKD_TAGTEXT 0x0020 /* don't expand `_` and `*` */ #define MKD_NO_EXT 0x0040 /* don't allow pseudo-protocols */ #define MKD_CDATA 0x0080 /* generate code for xml ![CDATA[...]] */ #define MKD_EMBED MKD_NOLINKS|MKD_NOIMAGE|MKD_TAGTEXT /* special flags for mkd_in() and mkd_string() */ #define MKD_NOHEADER 0x0100 /* don't process header blocks */ #define MKD_TABSTOP 0x0200 /* expand tabs to 4 spaces */ #endif/*_MKDIO_D*/ lua-discount-1.2.10.1/resource.c000066400000000000000000000055671106570471300163550ustar00rootroot00000000000000/* markdown: a C implementation of John Gruber's Markdown markup language. * * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include #include #include #include #include #include #include "config.h" #include "cstring.h" #include "markdown.h" #include "amalloc.h" /* free a (single) line */ void ___mkd_freeLine(Line *ptr) { DELETE(ptr->text); free(ptr); } /* free a list of lines */ void ___mkd_freeLines(Line *p) { if (p->next) ___mkd_freeLines(p->next); ___mkd_freeLine(p); } /* bye bye paragraph. */ void ___mkd_freeParagraph(Paragraph *p) { if (p->next) ___mkd_freeParagraph(p->next); if (p->down) ___mkd_freeParagraph(p->down); if (p->text) ___mkd_freeLines(p->text); free(p); } /* bye bye footnotes. */ void ___mkd_freefootnotes(MMIOT *f) { int i; if ( f->footnotes ) { for (i=0; i < S(*f->footnotes); i++) { DELETE(T(*f->footnotes)[i].tag); DELETE(T(*f->footnotes)[i].link); DELETE(T(*f->footnotes)[i].title); } DELETE(*f->footnotes); free(f->footnotes); } } /* initialize a new MMIOT */ void ___mkd_initmmiot(MMIOT *f, void *footnotes) { if ( f ) { memset(f, 0, sizeof *f); CREATE(f->in); CREATE(f->out); CREATE(f->Q); if ( footnotes ) f->footnotes = footnotes; else { f->footnotes = malloc(sizeof f->footnotes[0]); CREATE(*f->footnotes); } } } /* free the contents of a MMIOT, but leave the object alone. */ void ___mkd_freemmiot(MMIOT *f, void *footnotes) { if ( f ) { DELETE(f->in); DELETE(f->out); DELETE(f->Q); if ( f->footnotes != footnotes ) ___mkd_freefootnotes(f); memset(f, 0, sizeof *f); } } /* free lines up to an barrier. */ void ___mkd_freeLineRange(Line *anchor, Line *stop) { Line *r = anchor->next; if ( r != stop ) { while ( r && (r->next != stop) ) r = r->next; if ( r ) r->next = 0; ___mkd_freeLines(anchor->next); } anchor->next = 0; } /* clean up everything allocated in __mkd_compile() */ void mkd_cleanup(Document *doc) { if ( doc ) { if ( doc->ctx ) { ___mkd_freemmiot(doc->ctx, 0); free(doc->ctx); } if ( doc->code) ___mkd_freeParagraph(doc->code); if ( doc->headers ) ___mkd_freeLines(doc->headers); if ( T(doc->content) ) ___mkd_freeLines(T(doc->content)); memset(doc, 0, sizeof doc[0]); free(doc); } } /* write output in XML format */ void ___mkd_xml(char *p, int size, FILE *out) { char c; while ( size-- > 0 ) { if ( !isascii(c = *p++) ) continue; switch (c) { case '<': fputs("<", out); break; case '>': fputs(">", out); break; case '&': fputs("&", out); break; case '"': fputs(""", out); break; case '\'':fputs("'", out); break; default: putc(c,out); break; } } } lua-discount-1.2.10.1/test_discount.lua000066400000000000000000000031401106570471300177350ustar00rootroot00000000000000require("lunit") discount = require("discount") module("test discount", lunit.testcase, package.seeall) function test_basic_conversion() assert_equal("

Hello World.

\n", discount("Hello World.")) end function test_relaxed_emphasis() assert_equal("

Hello World!

\n", discount("_Hello World_!")) assert_equal("

under_score this_stuff

\n", discount("under_score this_stuff")) local input = "_start _ foo_bar bar_baz _ end_ *italic* **bold**
_blah_" local expected_out = "

start _ foo_bar bar_baz _ end italic bold blah

\n" assert_equal(expected_out, discount(input)) end function test_nolinks() assert_equal("

[example](http://example.com)

\n", discount("[example](http://example.com)", "nolinks")) assert_equal('

<a href="http://example.com">example

\n', discount('example', "nolinks")) end function test_noimages() assert_equal("

![example](example.png)

\n", discount("![example](example.png)", "noimages")) assert_equal('

<img src="example.png"/>

\n', discount('', "noimages")) end function test_nopants() assert_equal('

“quote”

\n', discount('"quote"')) assert_equal('

"quote"

\n', discount('"quote"', "nopants")) end function test_nohtml() local expected = "

This should <em>not</em> be allowed

\n" assert_equal(expected, discount("This should not be allowed", "nohtml")) end function test_cdata() assert_equal("<p>foo</p>\n", discount("foo", "cdata")) end