rdiscount-1.6.8/0000755000175000017500000000000011643305656013507 5ustar virtualvirtualrdiscount-1.6.8/BUILDING0000644000175000017500000000227111643305656014631 0ustar virtualvirtualBUILDING rdiscount ================== You'll be needing Ruby, rake, and a basic build environment. Build the rdiscount extension for tests and local development: $ rake build Use your rdiscount working copy when running ruby programs: $ export RUBYLIB=~/rdiscount/lib:$RUBYLIB $ ruby some-program.rb Gathering changes from an upstream Orc/discount.git clone requires first grabbing the discount submodule into the root of the project and then running the rake gather task to copy discount source files into the ext/ directory: $ git submodule init Submodule 'discount' (git://github.com/rtomayko/discount.git) registered for path 'discount' $ rake gather $ rake build The rtomayko/discount.git repository's master branch is the default submodule head. It exists to merge branches for rdiscount specific patches to the upstream discount codebase. Do work in the submodule and then add a remote for your clone THAT YOU FORKED ON GITHUB BECAUSE YOU'RE GOING TO SEND ME A PULL REQUEST. After you've committed your great changes somewhere, push them up with: $ cd discount $ git remote add you git@github.com:you/discount.git $ git push you HEAD:topic-branch-name rdiscount-1.6.8/metadata.yml0000644000175000017500000000346111643305656016016 0ustar virtualvirtual--- !ruby/object:Gem::Specification name: rdiscount version: !ruby/object:Gem::Version hash: 31 prerelease: false segments: - 1 - 6 - 8 version: 1.6.8 platform: ruby authors: - Ryan Tomayko - David Loren Parsons - Andrew White autorequire: bindir: bin cert_chain: [] date: 2011-01-25 00:00:00 -08:00 default_executable: dependencies: [] description: email: rtomayko@gmail.com executables: - rdiscount extensions: - ext/extconf.rb extra_rdoc_files: - COPYING files: - BUILDING - COPYING - README.markdown - Rakefile - bin/rdiscount - ext/Csio.c - ext/amalloc.h - ext/basename.c - ext/config.h - ext/css.c - ext/cstring.h - ext/docheader.c - ext/dumptree.c - ext/emmatch.c - ext/extconf.rb - ext/generate.c - ext/html5.c - ext/markdown.c - ext/markdown.h - ext/mkdio.c - ext/mkdio.h - ext/rdiscount.c - ext/resource.c - ext/tags.c - ext/tags.h - ext/toc.c - ext/xml.c - lib/markdown.rb - lib/rdiscount.rb - man/markdown.7 - man/rdiscount.1 - man/rdiscount.1.ronn - rdiscount.gemspec - test/benchmark.rb - test/benchmark.txt - test/markdown_test.rb - test/rdiscount_test.rb has_rdoc: true homepage: http://github.com/rtomayko/rdiscount licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" requirements: [] rubyforge_project: wink rubygems_version: 1.3.7 signing_key: specification_version: 3 summary: Fast Implementation of Gruber's Markdown in C test_files: - test/markdown_test.rb - test/rdiscount_test.rb rdiscount-1.6.8/bin/0000755000175000017500000000000011643305656014257 5ustar virtualvirtualrdiscount-1.6.8/bin/rdiscount0000755000175000017500000000063111643305656016217 0ustar virtualvirtual#!/usr/bin/env ruby # Usage: rdiscount [...] # Convert one or more Markdown files to HTML and write to standard output. With # no or when is '-', read Markdown source text from standard input. if ARGV.include?('--help') File.read(__FILE__).split("\n").grep(/^# /).each do |line| puts line[2..-1] end exit 0 end require 'rdiscount' STDOUT.write(RDiscount.new(ARGF.read).to_html) rdiscount-1.6.8/ext/0000755000175000017500000000000011643305656014307 5ustar virtualvirtualrdiscount-1.6.8/ext/rdiscount.c0000644000175000017500000000631511643305656016472 0ustar virtualvirtual#include #include "ruby.h" #include "mkdio.h" static VALUE rb_cRDiscount; static VALUE rb_rdiscount_to_html(int argc, VALUE *argv, VALUE self) { /* grab char pointer to markdown input text */ char *res; int szres; VALUE encoding; VALUE text = rb_funcall(self, rb_intern("text"), 0); VALUE buf = rb_str_buf_new(1024); Check_Type(text, T_STRING); int flags = rb_rdiscount__get_flags(self); MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags); if ( mkd_compile(doc, flags) ) { szres = mkd_document(doc, &res); if ( szres != EOF ) { rb_str_cat(buf, res, szres); rb_str_cat(buf, "\n", 1); } } mkd_cleanup(doc); /* force the input encoding */ if ( rb_respond_to(text, rb_intern("encoding")) ) { encoding = rb_funcall(text, rb_intern("encoding"), 0); rb_funcall(buf, rb_intern("force_encoding"), 1, encoding); } return buf; } static VALUE rb_rdiscount_toc_content(int argc, VALUE *argv, VALUE self) { char *res; int szres; int flags = rb_rdiscount__get_flags(self); /* grab char pointer to markdown input text */ VALUE text = rb_funcall(self, rb_intern("text"), 0); Check_Type(text, T_STRING); /* allocate a ruby string buffer and wrap it in a stream */ VALUE buf = rb_str_buf_new(4096); MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags); if ( mkd_compile(doc, flags) ) { szres = mkd_toc(doc, &res); if ( szres != EOF ) { rb_str_cat(buf, res, szres); rb_str_cat(buf, "\n", 1); } } mkd_cleanup(doc); return buf; } int rb_rdiscount__get_flags(VALUE ruby_obj) { /* compile flags */ int flags = MKD_TABSTOP | MKD_NOHEADER; /* smart */ if ( rb_funcall(ruby_obj, rb_intern("smart"), 0) != Qtrue ) flags = flags | MKD_NOPANTS; /* filter_html */ if ( rb_funcall(ruby_obj, rb_intern("filter_html"), 0) == Qtrue ) flags = flags | MKD_NOHTML; /* generate_toc */ if ( rb_funcall(ruby_obj, rb_intern("generate_toc"), 0) == Qtrue) flags = flags | MKD_TOC; /* no_image */ if ( rb_funcall(ruby_obj, rb_intern("no_image"), 0) == Qtrue) flags = flags | MKD_NOIMAGE; /* no_links */ if ( rb_funcall(ruby_obj, rb_intern("no_links"), 0) == Qtrue) flags = flags | MKD_NOLINKS; /* no_tables */ if ( rb_funcall(ruby_obj, rb_intern("no_tables"), 0) == Qtrue) flags = flags | MKD_NOTABLES; /* strict */ if ( rb_funcall(ruby_obj, rb_intern("strict"), 0) == Qtrue) flags = flags | MKD_STRICT; /* autolink */ if ( rb_funcall(ruby_obj, rb_intern("autolink"), 0) == Qtrue) flags = flags | MKD_AUTOLINK; /* safelink */ if ( rb_funcall(ruby_obj, rb_intern("safelink"), 0) == Qtrue) flags = flags | MKD_SAFELINK; /* no_pseudo_protocols */ if ( rb_funcall(ruby_obj, rb_intern("no_pseudo_protocols"), 0) == Qtrue) flags = flags | MKD_NO_EXT; return flags; } void Init_rdiscount() { rb_cRDiscount = rb_define_class("RDiscount", rb_cObject); rb_define_method(rb_cRDiscount, "to_html", rb_rdiscount_to_html, -1); rb_define_method(rb_cRDiscount, "toc_content", rb_rdiscount_toc_content, -1); } /* vim: set ts=4 sw=4: */ rdiscount-1.6.8/ext/cstring.h0000644000175000017500000000462511643305656016140 0ustar virtualvirtual/* two template types: STRING(t) which defines a pascal-style string * of element (t) [STRING(char) is the closest to the pascal string], * and ANCHOR(t) which defines a baseplate that a linked list can be * built up from. [The linked list /must/ contain a ->next pointer * for linking the list together with.] */ #ifndef _CSTRING_D #define _CSTRING_D #include #include #ifndef __WITHOUT_AMALLOC # include "amalloc.h" #endif /* expandable Pascal-style string. */ #define STRING(type) struct { type *text; int size, alloc; } #define CREATE(x) T(x) = (void*)(S(x) = (x).alloc = 0) #define EXPAND(x) (S(x)++)[(S(x) < (x).alloc) \ ? (T(x)) \ : (T(x) = T(x) ? realloc(T(x), sizeof T(x)[0] * ((x).alloc += 100)) \ : malloc(sizeof T(x)[0] * ((x).alloc += 100)) )] #define DELETE(x) ALLOCATED(x) ? (free(T(x)), S(x) = (x).alloc = 0) \ : ( S(x) = 0 ) #define CLIP(t,i,sz) \ ( ((i) >= 0) && ((sz) > 0) && (((i)+(sz)) <= S(t)) ) ? \ (memmove(&T(t)[i], &T(t)[i+sz], (S(t)-(i+sz)+1)*sizeof(T(t)[0])), \ S(t) -= (sz)) : -1 #define RESERVE(x, sz) T(x) = ((x).alloc > S(x) + (sz) \ ? T(x) \ : T(x) \ ? realloc(T(x), sizeof T(x)[0] * ((x).alloc = 100+(sz)+S(x))) \ : malloc(sizeof T(x)[0] * ((x).alloc = 100+(sz)+S(x)))) #define SUFFIX(t,p,sz) \ memcpy(((S(t) += (sz)) - (sz)) + \ (T(t) = T(t) ? realloc(T(t), sizeof T(t)[0] * ((t).alloc += sz)) \ : malloc(sizeof T(t)[0] * ((t).alloc += sz))), \ (p), sizeof(T(t)[0])*(sz)) #define PREFIX(t,p,sz) \ RESERVE( (t), (sz) ); \ if ( S(t) ) { memmove(T(t)+(sz), T(t), S(t)); } \ memcpy( T(t), (p), (sz) ); \ S(t) += (sz) /* reference-style links (and images) are stored in an array */ #define T(x) (x).text #define S(x) (x).size #define ALLOCATED(x) (x).alloc /* abstract anchor type that defines a list base * with a function that attaches an element to * the end of the list. * * the list base field is named .text so that the T() * macro will work with it. */ #define ANCHOR(t) struct { t *text, *end; } #define E(t) ((t).end) #define ATTACH(t, p) ( T(t) ? ( (E(t)->next = (p)), (E(t) = (p)) ) \ : ( (T(t) = E(t) = (p)) ) ) typedef STRING(char) Cstring; extern void Csputc(int, Cstring *); extern int Csprintf(Cstring *, char *, ...); extern int Cswrite(Cstring *, char *, int); extern void Csreparse(Cstring *, char *, int, int); #endif/*_CSTRING_D*/ rdiscount-1.6.8/ext/emmatch.c0000644000175000017500000001012011643305656016063 0ustar virtualvirtual/* markdown: a C implementation of John Gruber's Markdown markup language. * * Copyright (C) 2010 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include #include #include #include #include #include #include "config.h" #include "cstring.h" #include "markdown.h" #include "amalloc.h" /* emmatch: the emphasis mangler that's run after a block * of html has been generated. * * It should create MarkdownTest_1.0 (and _1.0.3) * compatable emphasis for non-pathological cases * and it should fail in a standards-compliant way * when someone attempts to feed it junk. * * Emmatching is done after the input has been * processed into a STRING (f->Q) of text and * emphasis blocks. After ___mkd_emblock() finishes, * it truncates f->Q and leaves the rendered paragraph * if f->out. */ /* empair() -- find the NEAREST matching emphasis token (or * subtoken of a 3+ long emphasis token. */ static int empair(MMIOT *f, int first, int last, int match) { int i; block *begin, *p; begin = &T(f->Q)[first]; for (i=first+1; i <= last; i++) { p = &T(f->Q)[i]; if ( (p->b_type != bTEXT) && (p->b_count <= 0) ) continue; /* break? */ if ( p->b_type == begin->b_type ) { if ( p->b_count == match ) /* exact match */ return i; if ( p->b_count > 2 ) /* fuzzy match */ return i; } } return 0; } /* empair */ /* emfill() -- if an emphasis token has leftover stars or underscores, * convert them back into character and append them to b_text. */ static void emfill(block *p) { int j; if ( p->b_type == bTEXT ) return; for (j=0; j < p->b_count; j++) EXPAND(p->b_text) = p->b_char; p->b_count = 0; } /* emfill */ static void emclose(MMIOT *f, int first, int last) { int j; for (j=first+1; jQ)[j]); } static struct emtags { char open[10]; char close[10]; int size; } emtags[] = { { "" , "", 5 }, { "", "", 9 } }; static void emblock(MMIOT*,int,int); /* emmatch() -- match emphasis for a single emphasis token. */ static void emmatch(MMIOT *f, int first, int last) { block *start = &T(f->Q)[first]; int e, e2, match; switch (start->b_count) { case 2: if ( e = empair(f,first,last,match=2) ) break; case 1: e = empair(f,first,last,match=1); break; case 0: return; default: e = empair(f,first,last,1); e2= empair(f,first,last,2); if ( e2 >= e ) { e = e2; match = 2; } else match = 1; break; } if ( e ) { /* if we found emphasis to match, match it, recursively call * emblock to match emphasis inside the new html block, add * the emphasis markers for the block, then (tail) recursively * call ourself to match any remaining emphasis on this token. */ block *end = &T(f->Q)[e]; end->b_count -= match; start->b_count -= match; emblock(f, first, e); PREFIX(start->b_text, emtags[match-1].open, emtags[match-1].size-1); SUFFIX(end->b_post, emtags[match-1].close, emtags[match-1].size); emmatch(f, first, last); } } /* emmatch */ /* emblock() -- walk a blocklist, attempting to match emphasis */ static void emblock(MMIOT *f, int first, int last) { int i; for ( i = first; i <= last; i++ ) if ( T(f->Q)[i].b_type != bTEXT ) emmatch(f, i, last); emclose(f, first, last); } /* emblock */ /* ___mkd_emblock() -- emblock a string of blocks, then concatinate the * resulting text onto f->out. */ void ___mkd_emblock(MMIOT *f) { int i; block *p; emblock(f, 0, S(f->Q)-1); for (i=0; i < S(f->Q); i++) { p = &T(f->Q)[i]; emfill(p); if ( S(p->b_post) ) { SUFFIX(f->out, T(p->b_post), S(p->b_post)); DELETE(p->b_post); } if ( S(p->b_text) ) { SUFFIX(f->out, T(p->b_text), S(p->b_text)); DELETE(p->b_text); } } S(f->Q) = 0; } /* ___mkd_emblock */ rdiscount-1.6.8/ext/resource.c0000644000175000017500000000511111643305656016300 0ustar virtualvirtual/* markdown: a C implementation of John Gruber's Markdown markup language. * * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include #include #include #include #include #include #include "config.h" #include "cstring.h" #include "markdown.h" #include "amalloc.h" /* free a (single) line */ void ___mkd_freeLine(Line *ptr) { DELETE(ptr->text); free(ptr); } /* free a list of lines */ void ___mkd_freeLines(Line *p) { if (p->next) ___mkd_freeLines(p->next); ___mkd_freeLine(p); } /* bye bye paragraph. */ void ___mkd_freeParagraph(Paragraph *p) { if (p->next) ___mkd_freeParagraph(p->next); if (p->down) ___mkd_freeParagraph(p->down); if (p->text) ___mkd_freeLines(p->text); if (p->ident) free(p->ident); free(p); } /* bye bye footnote. */ void ___mkd_freefootnote(Footnote *f) { DELETE(f->tag); DELETE(f->link); DELETE(f->title); } /* bye bye footnotes. */ void ___mkd_freefootnotes(MMIOT *f) { int i; if ( f->footnotes ) { for (i=0; i < S(*f->footnotes); i++) ___mkd_freefootnote( &T(*f->footnotes)[i] ); DELETE(*f->footnotes); free(f->footnotes); } } /* initialize a new MMIOT */ void ___mkd_initmmiot(MMIOT *f, void *footnotes) { if ( f ) { memset(f, 0, sizeof *f); CREATE(f->in); CREATE(f->out); CREATE(f->Q); if ( footnotes ) f->footnotes = footnotes; else { f->footnotes = malloc(sizeof f->footnotes[0]); CREATE(*f->footnotes); } } } /* free the contents of a MMIOT, but leave the object alone. */ void ___mkd_freemmiot(MMIOT *f, void *footnotes) { if ( f ) { DELETE(f->in); DELETE(f->out); DELETE(f->Q); if ( f->footnotes != footnotes ) ___mkd_freefootnotes(f); memset(f, 0, sizeof *f); } } /* free lines up to an barrier. */ void ___mkd_freeLineRange(Line *anchor, Line *stop) { Line *r = anchor->next; if ( r != stop ) { while ( r && (r->next != stop) ) r = r->next; if ( r ) r->next = 0; ___mkd_freeLines(anchor->next); } anchor->next = 0; } /* clean up everything allocated in __mkd_compile() */ void mkd_cleanup(Document *doc) { if ( doc && (doc->magic == VALID_DOCUMENT) ) { if ( doc->ctx ) { ___mkd_freemmiot(doc->ctx, 0); free(doc->ctx); } if ( doc->code) ___mkd_freeParagraph(doc->code); if ( doc->headers ) ___mkd_freeLines(doc->headers); if ( T(doc->content) ) ___mkd_freeLines(T(doc->content)); memset(doc, 0, sizeof doc[0]); free(doc); } } rdiscount-1.6.8/ext/tags.c0000644000175000017500000000362411643305656015416 0ustar virtualvirtual/* block-level tags for passing html blocks through the blender */ #define __WITHOUT_AMALLOC 1 #include "cstring.h" #include "tags.h" STRING(struct kw) blocktags; /* define a html block tag */ void mkd_define_tag(char *id, int selfclose) { struct kw *p = &EXPAND(blocktags); p->id = id; p->size = strlen(id); p->selfclose = selfclose; } /* case insensitive string sort (for qsort() and bsearch() of block tags) */ static int casort(struct kw *a, struct kw *b) { if ( a->size != b->size ) return a->size - b->size; return strncasecmp(a->id, b->id, b->size); } /* stupid cast to make gcc shut up about the function types being * passed into qsort() and bsearch() */ typedef int (*stfu)(const void*,const void*); /* sort the list of html block tags for later searching */ void mkd_sort_tags() { qsort(T(blocktags), S(blocktags), sizeof(struct kw), (stfu)casort); } /* look for a token in the html block tag list */ struct kw* mkd_search_tags(char *pat, int len) { struct kw key; key.id = pat; key.size = len; return bsearch(&key, T(blocktags), S(blocktags), sizeof key, (stfu)casort); } /* load in the standard collection of html tags that markdown supports */ void mkd_prepare_tags() { #define KW(x) mkd_define_tag(x, 0) #define SC(x) mkd_define_tag(x, 1) static int populated = 0; if ( populated ) return; populated = 1; KW("STYLE"); KW("SCRIPT"); KW("ADDRESS"); KW("BDO"); KW("BLOCKQUOTE"); KW("CENTER"); KW("DFN"); KW("DIV"); KW("OBJECT"); 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"); SC("HR"); SC("BR"); KW("IFRAME"); KW("MAP"); mkd_sort_tags(); } /* mkd_prepare_tags */ rdiscount-1.6.8/ext/generate.c0000644000175000017500000007562211643305656016261 0ustar virtualvirtual/* markdown: a C implementation of John Gruber's Markdown markup language. * * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include #include #include #include #include #include #include "config.h" #include "cstring.h" #include "markdown.h" #include "amalloc.h" typedef int (*stfu)(const void*,const void*); typedef void (*spanhandler)(MMIOT*,int); /* forward declarations */ static void text(MMIOT *f); static Paragraph *display(Paragraph*, MMIOT*); /* externals from markdown.c */ int __mkd_footsort(Footnote *, Footnote *); /* * push text into the generator input buffer */ static void push(char *bfr, int size, MMIOT *f) { while ( size-- > 0 ) EXPAND(f->in) = *bfr++; } /* look characters ahead of the cursor. */ static 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; } static int isthisspace(MMIOT *f, int i) { int c = peek(f, i); return isspace(c) || (c == EOF); } static int isthisalnum(MMIOT *f, int i) { int c = peek(f, i); return (c != EOF) && isalnum(c); } static int isthisnonword(MMIOT *f, int i) { return isthisspace(f, i) || ispunct(peek(f,i)); } /* return/set the current cursor position */ #define mmiotseek(f,x) (f->isp = x) #define mmiottell(f) (f->isp) /* move n characters forward ( or -n characters backward) in the input buffer. */ static void shift(MMIOT *f, int i) { if (f->isp + i >= 0 ) f->isp += i; } /* Qchar() */ static void Qchar(int c, MMIOT *f) { block *cur; if ( S(f->Q) == 0 ) { cur = &EXPAND(f->Q); memset(cur, 0, sizeof *cur); cur->b_type = bTEXT; } else cur = &T(f->Q)[S(f->Q)-1]; EXPAND(cur->b_text) = c; } /* Qstring() */ static void Qstring(char *s, MMIOT *f) { while (*s) Qchar(*s++, f); } /* Qwrite() */ static void Qwrite(char *s, int size, MMIOT *f) { while (size-- > 0) Qchar(*s++, f); } /* Qprintf() */ static void Qprintf(MMIOT *f, char *fmt, ...) { char bfr[80]; va_list ptr; va_start(ptr,fmt); vsnprintf(bfr, sizeof bfr, fmt, ptr); va_end(ptr); Qstring(bfr, f); } /* Qem() */ static void Qem(MMIOT *f, char c, int count) { block *p = &EXPAND(f->Q); memset(p, 0, sizeof *p); p->b_type = (c == '*') ? bSTAR : bUNDER; p->b_char = c; p->b_count = count; memset(&EXPAND(f->Q), 0, sizeof(block)); } /* generate html from a markup fragment */ void ___mkd_reparse(char *bfr, int size, int flags, MMIOT *f) { MMIOT sub; ___mkd_initmmiot(&sub, f->footnotes); sub.flags = f->flags | flags; sub.cb = f->cb; push(bfr, size, &sub); EXPAND(sub.in) = 0; S(sub.in)--; text(&sub); ___mkd_emblock(&sub); Qwrite(T(sub.out), S(sub.out), f); ___mkd_freemmiot(&sub, f->footnotes); } /* * write out a url, escaping problematic characters */ static void puturl(char *s, int size, MMIOT *f, int display) { unsigned char c; while ( size-- > 0 ) { c = *s++; if ( c == '\\' && size-- > 0 ) { c = *s++; if ( !( ispunct(c) || isspace(c) ) ) Qchar('\\', f); } if ( c == '&' ) Qstring("&", f); else if ( c == '<' ) Qstring("<", f); else if ( c == '"' ) Qstring("%22", f); else if ( isalnum(c) || ispunct(c) || (display && isspace(c)) ) Qchar(c, f); else if ( c == 003 ) /* untokenize ^C */ Qstring(" ", f); else Qprintf(f, "%%%02X", c); } } /* advance forward until the next character is not whitespace */ static int eatspace(MMIOT *f) { int c; for ( ; ((c=peek(f, 1)) != EOF) && isspace(c); pull(f) ) ; return c; } /* (match (a (nested (parenthetical (string.))))) */ static int parenthetical(int in, int out, MMIOT *f) { int size, indent, c; for ( indent=1,size=0; indent; size++ ) { if ( (c = pull(f)) == EOF ) return EOF; else if ( (c == '\\') && (peek(f,1) == out || peek(f,1) == in) ) { ++size; pull(f); } else if ( c == in ) ++indent; else if ( c == out ) --indent; } return size ? (size-1) : 0; } /* extract a []-delimited label from the input stream. */ static int linkylabel(MMIOT *f, Cstring *res) { char *ptr = cursor(f); int size; if ( (size = parenthetical('[',']',f)) != EOF ) { T(*res) = ptr; S(*res) = size; return 1; } return 0; } /* see if the quote-prefixed linky segment is actually a title. */ static int linkytitle(MMIOT *f, char quote, Footnote *ref) { int whence = mmiottell(f); char *title = cursor(f); char *e; register int c; while ( (c = pull(f)) != EOF ) { e = cursor(f); if ( c == quote ) { if ( (c = eatspace(f)) == ')' ) { T(ref->title) = 1+title; S(ref->title) = (e-title)-2; return 1; } } } mmiotseek(f, whence); return 0; } /* extract a =HHHxWWW size from the input stream */ static int linkysize(MMIOT *f, Footnote *ref) { int height=0, width=0; int whence = mmiottell(f); int c; if ( isspace(peek(f,0)) ) { pull(f); /* eat '=' */ for ( c = pull(f); isdigit(c); c = pull(f)) width = (width * 10) + (c - '0'); if ( c == 'x' ) { for ( c = pull(f); isdigit(c); c = pull(f)) height = (height*10) + (c - '0'); if ( isspace(c) ) c = eatspace(f); if ( (c == ')') || ((c == '\'' || c == '"') && linkytitle(f, c, ref)) ) { ref->height = height; ref->width = width; return 1; } } } mmiotseek(f, whence); return 0; } /* extract a (-prefixed url from the input stream. * the label is either of the format ``, where I * extract until I find a >, or it is of the format * `text`, where I extract until I reach a ')', a quote, * or (if image) a '=' */ static int linkyurl(MMIOT *f, int image, Footnote *p) { int c; int mayneedtotrim=0; if ( (c = eatspace(f)) == EOF ) return 0; if ( c == '<' ) { pull(f); mayneedtotrim=1; } T(p->link) = cursor(f); for ( S(p->link)=0; (c = peek(f,1)) != ')'; ++S(p->link) ) { if ( c == EOF ) return 0; else if ( (c == '"' || c == '\'') && linkytitle(f, c, p) ) break; else if ( image && (c == '=') && linkysize(f, p) ) break; else if ( (c == '\\') && ispunct(peek(f,2)) ) { ++S(p->link); pull(f); } pull(f); } if ( peek(f, 1) == ')' ) pull(f); ___mkd_tidy(&p->link); if ( mayneedtotrim && (T(p->link)[S(p->link)-1] == '>') ) --S(p->link); return 1; } /* prefixes for */ static struct _protocol { char *name; int nlen; } protocol[] = { #define _aprotocol(x) { x, (sizeof x)-1 } _aprotocol( "https://" ), _aprotocol( "http://" ), _aprotocol( "news://" ), _aprotocol( "ftp://" ), #undef _aprotocol }; #define NRPROTOCOLS (sizeof protocol / sizeof protocol[0]) static int isautoprefix(char *text, int size) { int i; struct _protocol *p; for (i=0, p=protocol; i < NRPROTOCOLS; i++, p++) if ( (size >= p->nlen) && strncasecmp(text, p->name, p->nlen) == 0 ) return 1; return 0; } /* * all the tag types that linkylinky can produce are * defined by this structure. */ typedef struct linkytype { char *pat; int szpat; char *link_pfx; /* tag prefix and link pointer (eg: "" */ char *text_sfx; /* text suffix (eg: "" */ int flags; /* reparse flags */ int kind; /* tag is url or something else? */ #define IS_URL 0x01 } linkytype; static linkytype imaget = { 0, 0, "\"",", DENY_IMG|INSIDE_TAG, IS_URL }; static linkytype linkt = { 0, 0, "", "", DENY_A, IS_URL }; /* * pseudo-protocols for [][]; * * id: generates tag * class: generates tag * raw: just dump the link without any processing */ static linkytype specials[] = { { "id:", 3, "", "", 0, IS_URL }, { "raw:", 4, 0, 0, 0, 0, 0, DENY_HTML, 0 }, { "lang:", 5, "", "", 0, 0 }, { "abbr:", 5, "", "", 0, 0 }, { "class:", 6, "", "", 0, 0 }, } ; #define NR(x) (sizeof x / sizeof x[0]) /* see if t contains one of our pseudo-protocols. */ static linkytype * pseudo(Cstring t) { int i; linkytype *r; for ( i=0, r=specials; i < NR(specials); i++,r++ ) { if ( (S(t) > r->szpat) && (strncasecmp(T(t), r->pat, r->szpat) == 0) ) return r; } return 0; } /* print out the start of an `img' or `a' tag, applying callbacks as needed. */ static void printlinkyref(MMIOT *f, linkytype *tag, char *link, int size) { char *edit; Qstring(tag->link_pfx, f); if ( tag->kind & IS_URL ) { if ( f->cb->e_url && (edit = (*f->cb->e_url)(link, size, f->cb->e_data)) ) { puturl(edit, strlen(edit), f, 0); if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data); } else puturl(link + tag->szpat, size - tag->szpat, f, 0); } else ___mkd_reparse(link + tag->szpat, size - tag->szpat, INSIDE_TAG, f); Qstring(tag->link_sfx, f); if ( f->cb->e_flags && (edit = (*f->cb->e_flags)(link, size, f->cb->e_data)) ) { Qchar(' ', f); Qstring(edit, f); if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data); } } /* printlinkyref */ /* print out a linky (or fail if it's Not Allowed) */ static int linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref) { linkytype *tag; if ( image ) tag = &imaget; else if ( tag = pseudo(ref->link) ) { if ( f->flags & (NO_PSEUDO_PROTO|SAFELINK) ) return 0; } else if ( (f->flags & SAFELINK) && T(ref->link) && (T(ref->link)[0] != '/') && !isautoprefix(T(ref->link), S(ref->link)) ) /* if SAFELINK, only accept links that are local or * a well-known protocol */ return 0; else tag = &linkt; if ( f->flags & tag->flags ) return 0; if ( tag->link_pfx ) { printlinkyref(f, tag, T(ref->link), S(ref->link)); if ( tag->WxH ) { if ( ref->height ) Qprintf(f," height=\"%d\"", ref->height); if ( ref->width ) Qprintf(f, " width=\"%d\"", ref->width); } if ( S(ref->title) ) { Qstring(" title=\"", f); ___mkd_reparse(T(ref->title), S(ref->title), INSIDE_TAG, f); Qchar('"', f); } Qstring(tag->text_pfx, f); ___mkd_reparse(T(text), S(text), tag->flags, f); Qstring(tag->text_sfx, f); } else Qwrite(T(ref->link) + tag->szpat, S(ref->link) - tag->szpat, f); return 1; } /* linkyformat */ /* * process embedded links and images */ static int linkylinky(int image, MMIOT *f) { int start = mmiottell(f); Cstring name; Footnote key, *ref; int status = 0; CREATE(name); memset(&key, 0, sizeof key); if ( linkylabel(f, &name) ) { if ( peek(f,1) == '(' ) { pull(f); if ( linkyurl(f, image, &key) ) status = linkyformat(f, name, image, &key); } else { int goodlink, implicit_mark = mmiottell(f); if ( eatspace(f) == '[' ) { pull(f); /* consume leading '[' */ goodlink = linkylabel(f, &key.tag); } else { /* new markdown implicit name syntax doesn't * require a second [] */ mmiotseek(f, implicit_mark); goodlink = !(f->flags & MKD_1_COMPAT); } if ( goodlink ) { if ( !S(key.tag) ) { DELETE(key.tag); T(key.tag) = T(name); S(key.tag) = S(name); } if ( ref = bsearch(&key, T(*f->footnotes), S(*f->footnotes), sizeof key, (stfu)__mkd_footsort) ) status = linkyformat(f, name, image, ref); } } } DELETE(name); ___mkd_freefootnote(&key); if ( status == 0 ) mmiotseek(f, start); return status; } /* write a character to output, doing text escapes ( & -> &, * > -> > < -> < ) */ static void cputc(int c, MMIOT *f) { switch (c) { case '&': Qstring("&", f); break; case '>': Qstring(">", f); break; case '<': Qstring("<", f); break; default : Qchar(c, f); break; } } /* * convert an email address to a string of nonsense */ static void mangle(char *s, int len, MMIOT *f) { while ( len-- > 0 ) { Qstring("&#", f); Qprintf(f, COINTOSS() ? "x%02x;" : "%02d;", *((unsigned char*)(s++)) ); } } /* nrticks() -- count up a row of tick marks */ static int nrticks(int offset, int tickchar, MMIOT *f) { int tick = 0; while ( peek(f, offset+tick) == tickchar ) tick++; return tick; } /* nrticks */ /* matchticks() -- match a certain # of ticks, and if that fails * match the largest subset of those ticks. * * if a subset was matched, return the # of ticks * that were matched. */ static int matchticks(MMIOT *f, int tickchar, int ticks, int *endticks) { int size, count, c; int subsize=0, subtick=0; *endticks = ticks; for (size = 0; (c=peek(f,size+ticks)) != EOF; size ++) { if ( (c == tickchar) && ( count = nrticks(size+ticks,tickchar,f)) ) { if ( count == ticks ) return size; else if ( count ) { if ( (count > subtick) && (count < ticks) ) { subsize = size; subtick = count; } size += count; } } } if ( subsize ) { *endticks = subtick; return subsize; } return 0; } /* matchticks */ /* code() -- write a string out as code. The only characters that have * special meaning in a code block are * `<' and `&' , which * are /always/ expanded to < and & */ static void code(MMIOT *f, char *s, int length) { int i,c; for ( i=0; i < length; i++ ) if ( (c = s[i]) == 003) /* ^C: expand back to 2 spaces */ Qstring(" ", f); else cputc(c, f); } /* code */ /* delspan() -- write out a chunk of text, blocking with ... */ static void delspan(MMIOT *f, int size) { Qstring("", f); ___mkd_reparse(cursor(f)-1, size, 0, f); Qstring("", f); } /* codespan() -- write out a chunk of text as code, trimming one * space off the front and/or back as appropriate. */ static void codespan(MMIOT *f, int size) { int i=0; if ( size > 1 && peek(f, size-1) == ' ' ) --size; if ( peek(f,i) == ' ' ) ++i, --size; Qstring("", f); code(f, cursor(f)+(i-1), size); Qstring("", f); } /* codespan */ /* before letting a tag through, validate against * 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) && !isthisalnum(f,2) ) return 1; if ( c == 'I' && (f->flags & DENY_IMG) && strncasecmp(cursor(f)+1, "MG", 2) == 0 && !isthisalnum(f,4) ) return 1; return 0; } /* Check a string to see if it looks like a mail address * "looks like a mail address" means alphanumeric + some * specials, then a `@`, then alphanumeric + some specials, * but with a `.` */ static int maybe_address(char *p, int size) { int ok = 0; for ( ;size && (isalnum(*p) || strchr("._-+*", *p)); ++p, --size) ; if ( ! (size && *p == '@') ) return 0; --size, ++p; if ( size && *p == '.' ) return 0; for ( ;size && (isalnum(*p) || strchr("._-+", *p)); ++p, --size ) if ( *p == '.' && size > 1 ) ok = 1; return size ? 0 : ok; } /* The size-length token at cursor(f) is either a mailto:, an * implicit mailto:, one of the approved url protocols, or just * plain old text. If it's a mailto: or an approved protocol, * linkify it, otherwise say "no" */ static int process_possible_link(MMIOT *f, int size) { int address= 0; int mailto = 0; char *text = cursor(f); if ( f->flags & DENY_A ) return 0; if ( (size > 7) && strncasecmp(text, "mailto:", 7) == 0 ) { /* if it says it's a mailto, it's a mailto -- who am * I to second-guess the user? */ address = 1; mailto = 7; /* 7 is the length of "mailto:"; we need this */ } else address = maybe_address(text, size); if ( address ) { Qstring("", f); mangle(text+mailto, size-mailto, f); Qstring("", f); return 1; } else if ( isautoprefix(text, size) ) { printlinkyref(f, &linkt, text, size); Qchar('>', f); puturl(text,size,f, 1); Qstring("", f); return 1; } return 0; } /* process_possible_link */ /* a < may be just a regular character, the start of an embedded html * tag, or the start of an . If it's an automatic * link, we also need to know if it's an email address because if it * is we need to mangle it in our futile attempt to cut down on the * spaminess of the rendered page. */ static int maybe_tag_or_link(MMIOT *f) { int c, size; int maybetag = 1; if ( f->flags & INSIDE_TAG ) return 0; for ( size=0; (c = peek(f, size+1)) != '>'; size++) { if ( c == EOF ) return 0; else if ( c == '\\' ) { maybetag=0; if ( peek(f, size+2) != EOF ) size++; } else if ( isspace(c) ) break; else if ( ! (c == '/' || c == '-' || c == '_' || isalnum(c) ) ) maybetag=0; } if ( size ) { if ( maybetag || (size >= 3 && strncmp(cursor(f), "!--", 3) == 0) ) { /* It is not a html tag unless we find the closing '>' in * the same block. */ while ( (c = peek(f, size+1)) != '>' ) if ( c == EOF ) return 0; else size++; if ( forbidden_tag(f) ) return 0; Qchar('<', f); while ( ((c = peek(f, 1)) != EOF) && (c != '>') ) Qchar(pull(f), f); return 1; } else if ( !isspace(c) && process_possible_link(f, size) ) { shift(f, size+1); return 1; } } return 0; } /* autolinking means that all inline html is . A * autolink url is alphanumerics, slashes, periods, underscores, * the at sign, colon, and the % character. */ static int maybe_autolink(MMIOT *f) { register int c; int size; /* greedily scan forward for the end of a legitimate link. */ for ( size=0; (c=peek(f, size+1)) != EOF; size++ ) if ( c == '\\' ) { if ( peek(f, size+2) != EOF ) ++size; } else if ( isspace(c) || strchr("'\"()[]{}<>`", c) ) break; if ( (size > 1) && process_possible_link(f, size) ) { shift(f, size); return 1; } return 0; } /* smartyquote code that's common for single and double quotes */ static int smartyquote(int *flags, char typeofquote, MMIOT *f) { int bit = (typeofquote == 's') ? 0x01 : 0x02; if ( bit & (*flags) ) { if ( isthisnonword(f,1) ) { Qprintf(f, "&r%cquo;", typeofquote); (*flags) &= ~bit; return 1; } } else if ( isthisnonword(f,-1) && peek(f,1) != EOF ) { Qprintf(f, "&l%cquo;", typeofquote); (*flags) |= bit; return 1; } return 0; } static int islike(MMIOT *f, char *s) { int len; int i; if ( s[0] == '<' ) { if ( !isthisnonword(f, -1) ) return 0; ++s; } if ( !(len = strlen(s)) ) return 0; if ( s[len-1] == '>' ) { if ( !isthisnonword(f,len-1) ) return 0; len--; } for (i=1; i < len; i++) if (tolower(peek(f,i)) != s[i]) return 0; return 1; } static struct smarties { char c0; char *pat; char *entity; int shift; } smarties[] = { { '\'', "'s>", "rsquo", 0 }, { '\'', "'t>", "rsquo", 0 }, { '\'', "'re>", "rsquo", 0 }, { '\'', "'ll>", "rsquo", 0 }, { '\'', "'ve>", "rsquo", 0 }, { '\'', "'m>", "rsquo", 0 }, { '\'', "'d>", "rsquo", 0 }, { '-', "--", "mdash", 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|INSIDE_TAG) ) return 0; for ( i=0; i < NRSMART; i++) if ( (c == smarties[i].c0) && islike(f, smarties[i].pat) ) { if ( smarties[i].entity ) Qprintf(f, "&%s;", smarties[i].entity); shift(f, smarties[i].shift); return 1; } switch (c) { case '<' : return 0; case '\'': if ( smartyquote(flags, 's', f) ) return 1; break; case '"': if ( smartyquote(flags, 'd', f) ) return 1; break; case '`': if ( peek(f, 1) == '`' ) { int j = 2; while ( (c=peek(f,j)) != EOF ) { if ( c == '\\' ) j += 2; else if ( c == '`' ) break; else if ( c == '\'' && peek(f, j+1) == '\'' ) { Qstring("“", f); ___mkd_reparse(cursor(f)+1, j-2, 0, f); Qstring("”", f); shift(f,j+1); return 1; } else ++j; } } break; } return 0; } /* smartypants */ /* process a body of text encased in some sort of tick marks. If it * works, generate the output and return 1, otherwise just return 0 and * let the caller figure it out. */ static int tickhandler(MMIOT *f, int tickchar, int minticks, spanhandler spanner) { int endticks, size; int tick = nrticks(0, tickchar, f); if ( (tick >= minticks) && (size = matchticks(f,tickchar,tick,&endticks)) ) { if ( endticks < tick ) { size += (tick - endticks); tick = endticks; } shift(f, tick); (*spanner)(f,size); shift(f, size+tick-1); return 1; } return 0; } #define tag_text(f) (f->flags & INSIDE_TAG) static void text(MMIOT *f) { int c, j; int rep; int smartyflags = 0; while (1) { if ( (f->flags & AUTOLINK) && isalpha(peek(f,1)) && !tag_text(f) ) maybe_autolink(f); c = pull(f); if (c == EOF) break; if ( smartypants(c, &smartyflags, f) ) continue; switch (c) { case 0: break; case 3: Qstring(tag_text(f) ? " " : "
", f); break; case '>': if ( tag_text(f) ) Qstring(">", f); else Qchar(c, f); break; case '"': if ( tag_text(f) ) Qstring(""", f); else Qchar(c, f); break; case '!': if ( peek(f,1) == '[' ) { pull(f); if ( tag_text(f) || !linkylinky(1, f) ) Qstring("![", f); } else Qchar(c, f); break; case '[': if ( tag_text(f) || !linkylinky(0, f) ) Qchar(c, f); break; #if SUPERSCRIPT /* A^B -> AB */ case '^': if ( (f->flags & (STRICT|INSIDE_TAG)) || 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); ___mkd_reparse(sup, len, 0, f); Qstring("", f); } break; #endif case '_': #if RELAXED_EMPHASIS /* Underscores don't count if they're in the middle of a word */ if ( !(f->flags & STRICT) && isthisalnum(f,-1) && isthisalnum(f,1) ) { Qchar(c, f); break; } #endif case '*': /* Underscores & stars don't count if they're out in the middle * of whitespace */ if ( isthisspace(f,-1) && isthisspace(f,1) ) { Qchar(c, f); break; } /* else fall into the regular old emphasis case */ if ( tag_text(f) ) Qchar(c, f); else { for (rep = 1; peek(f,1) == c; pull(f) ) ++rep; Qem(f,c,rep); } break; case '~': if ( (f->flags & (NOSTRIKETHROUGH|INSIDE_TAG|STRICT)) || !tickhandler(f,c,2,delspan) ) Qchar(c, f); break; case '`': if ( tag_text(f) || !tickhandler(f,c,1,codespan) ) Qchar(c, 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 '`': Qchar(c, f); break; default: Qchar('\\', f); if ( c != EOF ) shift(f,-1); break; } break; case '<': if ( !maybe_tag_or_link(f) ) Qstring("<", f); break; case '&': j = (peek(f,1) == '#' ) ? 2 : 1; while ( isthisalnum(f,j) ) ++j; if ( peek(f,j) != ';' ) Qstring("&", f); else Qchar(c, f); break; default: Qchar(c, f); break; } } /* truncate the input string after we've finished processing it */ S(f->in) = f->isp = 0; } /* text */ /* print a header block */ static void printheader(Paragraph *pp, MMIOT *f) { Qprintf(f, "hnumber); if ( f->flags & TOC ) { Qprintf(f, " id=\"", pp->hnumber); mkd_string_to_anchor(T(pp->text->text), S(pp->text->text), Qchar, f); Qchar('"', f); } Qchar('>', f); push(T(pp->text->text), S(pp->text->text), f); text(f); Qprintf(f, "", pp->hnumber); } enum e_alignments { a_NONE, a_CENTER, a_LEFT, a_RIGHT }; static char* alignments[] = { "", " align=\"center\"", " align=\"left\"", " align=\"right\"" }; typedef STRING(int) Istring; static int splat(Line *p, char *block, Istring align, int force, MMIOT *f) { int first, idx = 0, colno = 0; Qstring("\n", f); while ( idx < S(p->text) ) { first = idx; if ( force && (colno >= S(align)-1) ) idx = S(p->text); else while ( (idx < S(p->text)) && (T(p->text)[idx] != '|') ) ++idx; Qprintf(f, "<%s%s>", block, alignments[ (colno < S(align)) ? T(align)[colno] : a_NONE ]); ___mkd_reparse(T(p->text)+first, idx-first, 0, f); Qprintf(f, "\n", block); idx++; colno++; } if ( force ) while (colno < S(align) ) { Qprintf(f, "<%s>\n", block, block); ++colno; } Qstring("\n", f); return colno; } static int printtable(Paragraph *pp, MMIOT *f) { /* header, dashes, then lines of content */ Line *hdr, *dash, *body; Istring align; int start; int hcols; char *p; if ( !(pp->text && pp->text->next) ) return 0; hdr = pp->text; dash= hdr->next; body= dash->next; /* first figure out cell alignments */ CREATE(align); for (p=T(dash->text), start=0; start < S(dash->text); ) { char first, last; int end; last=first=0; for (end=start ; (end < S(dash->text)) && p[end] != '|'; ++ end ) { if ( !isspace(p[end]) ) { if ( !first) first = p[end]; last = p[end]; } } EXPAND(align) = ( first == ':' ) ? (( last == ':') ? a_CENTER : a_LEFT) : (( last == ':') ? a_RIGHT : a_NONE ); start = 1+end; } Qstring("\n", f); Qstring("\n", f); hcols = splat(hdr, "th", align, 0, f); Qstring("\n", f); if ( hcols < S(align) ) S(align) = hcols; else while ( hcols > S(align) ) EXPAND(align) = a_NONE; Qstring("\n", f); for ( ; body; body = body->next) splat(body, "td", align, 1, f); Qstring("\n", f); Qstring("
\n", f); DELETE(align); return 1; } static int printblock(Paragraph *pp, MMIOT *f) { Line *t = pp->text; static char *Begin[] = { "", "

", "

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

","

" }; while (t) { if ( S(t->text) ) { if ( t->next && S(t->text) > 2 && T(t->text)[S(t->text)-2] == ' ' && T(t->text)[S(t->text)-1] == ' ' ) { push(T(t->text), S(t->text)-2, f); push("\003\n", 2, f); } else { ___mkd_tidy(&t->text); push(T(t->text), S(t->text), f); if ( t->next ) push("\n", 1, f); } } t = t->next; } Qstring(Begin[pp->align], f); text(f); Qstring(End[pp->align], f); return 1; } static void printcode(Line *t, MMIOT *f) { int blanks; Qstring("
", f);
    for ( blanks = 0; t ; t = t->next ) {
	if ( S(t->text) > t->dle ) {
	    while ( blanks ) {
		Qchar('\n', f);
		--blanks;
	    }
	    code(f, T(t->text), S(t->text));
	    Qchar('\n', f);
	}
	else blanks++;
    }
    Qstring("
", f); } static void printhtml(Line *t, MMIOT *f) { int blanks; for ( blanks=0; t ; t = t->next ) if ( S(t->text) ) { for ( ; blanks; --blanks ) Qchar('\n', f); Qwrite(T(t->text), S(t->text), f); Qchar('\n', f); } else blanks++; } static void htmlify(Paragraph *p, char *block, char *arguments, MMIOT *f) { ___mkd_emblock(f); if ( block ) Qprintf(f, arguments ? "<%s %s>" : "<%s>", block, arguments); ___mkd_emblock(f); while (( p = display(p, f) )) { ___mkd_emblock(f); Qstring("\n\n", f); } if ( block ) Qprintf(f, "", block); ___mkd_emblock(f); } #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); ___mkd_reparse(T(tag->text), S(tag->text), 0, f); Qstring("
\n", f); } htmlify(p->down, "dd", p->ident, f); Qchar('\n', f); } Qstring("
", f); } } #endif static void listdisplay(int typ, Paragraph *p, MMIOT* f) { if ( p ) { Qprintf(f, "<%cl", (typ==UL)?'u':'o'); if ( typ == AL ) Qprintf(f, " type=a"); Qprintf(f, ">\n"); for ( ; p ; p = p->next ) { htmlify(p->down, "li", p->ident, f); Qchar('\n', f); } Qprintf(f, "\n", (typ==UL)?'u':'o'); } } /* dump out a Paragraph in the desired manner */ static Paragraph* display(Paragraph *p, MMIOT *f) { if ( !p ) return 0; switch ( p->typ ) { case STYLE: case WHITESPACE: break; case HTML: printhtml(p->text, f); break; case CODE: printcode(p->text, f); break; case QUOTE: htmlify(p->down, p->ident ? "div" : "blockquote", p->ident, f); break; case UL: case OL: case AL: listdisplay(p->typ, p->down, f); break; #if DL_TAG_EXTENSION case DL: definitionlist(p->down, f); break; #endif case HR: Qstring("
", f); break; case HDR: printheader(p, f); break; case TABLE: printtable(p, f); break; case SOURCE: htmlify(p->down, 0, 0, f); break; default: printblock(p, f); break; } return p->next; } /* 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, 0, p->ctx); p->html = 1; } *res = T(p->ctx->out); return S(p->ctx->out); } return EOF; } rdiscount-1.6.8/ext/mkdio.h0000644000175000017500000000535711643305656015575 0ustar virtualvirtual#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_cleanup(MMIOT*); /* markup functions */ int mkd_dump(MMIOT*, FILE*, int, char*); int markdown(MMIOT*, FILE*, int); int mkd_line(char *, int, char **, int); void mkd_string_to_anchor(char *, int, int (*)(int,void*), void*); int mkd_xhtmlpage(MMIOT*,int,FILE*); /* header block access */ char* mkd_doc_title(MMIOT*); char* mkd_doc_author(MMIOT*); char* mkd_doc_date(MMIOT*); /* compiled data access */ int mkd_document(MMIOT*, char**); int mkd_toc(MMIOT*, char**); int mkd_css(MMIOT*, char **); int mkd_xml(char *, int, char **); /* write-to-file functions */ int mkd_generatehtml(MMIOT*,FILE*); int mkd_generatetoc(MMIOT*,FILE*); int mkd_generatexml(char *, int,FILE*); int mkd_generatecss(MMIOT*,FILE*); #define mkd_style mkd_generatecss int mkd_generateline(char *, int, FILE*, int); #define mkd_text mkd_generateline /* url generator callbacks */ typedef char * (*mkd_callback_t)(const char*, const int, void*); typedef void (*mkd_free_t)(char*, void*); void mkd_e_url(void *, mkd_callback_t); void mkd_e_flags(void *, mkd_callback_t); void mkd_e_free(void *, mkd_free_t ); void mkd_e_data(void *, void *); /* version#. */ extern char markdown_version[]; /* 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_STRICT 0x0010 /* disable SUPERSCRIPT, RELAXED_EMPHASIS */ #define MKD_TAGTEXT 0x0020 /* process text inside an html tag; no * , no , no html or [] expansion */ #define MKD_NO_EXT 0x0040 /* don't allow pseudo-protocols */ #define MKD_CDATA 0x0080 /* generate code for xml ![CDATA[...]] */ #define MKD_NOTABLES 0x0400 /* disallow tables */ #define MKD_NOSTRIKETHROUGH 0x0800/* forbid ~~strikethrough~~ */ #define MKD_TOC 0x1000 /* do table-of-contents processing */ #define MKD_1_COMPAT 0x2000 /* compatability with MarkdownTest_1.0 */ #define MKD_AUTOLINK 0x4000 /* make http://foo.com link even without <>s */ #define MKD_SAFELINK 0x8000 /* paranoid check for link protocol */ #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*/ rdiscount-1.6.8/ext/mkdio.c0000644000175000017500000001421511643305656015561 0ustar virtualvirtual/* * mkdio -- markdown front end input functions * * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include "config.h" #include #include #include #include "cstring.h" #include "markdown.h" #include "amalloc.h" typedef ANCHOR(Line) LineAnchor; /* create a new blank Document */ static Document* new_Document() { Document *ret = calloc(sizeof(Document), 1); if ( ret ) { if (( ret->ctx = calloc(sizeof(MMIOT), 1) )) { ret->magic = VALID_DOCUMENT; return ret; } free(ret); } return 0; } /* add a line to the markdown input chain */ 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 if ( isprint(c) || isspace(c) || (c & 0x80) ) 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_generatexml(doc, szdoc, output); else fwrite(doc, szdoc, 1, output); putc('\n', output); return 0; } return -1; } /* convert some markdown text to html */ int markdown(Document *document, FILE *out, int flags) { if ( mkd_compile(document, flags) ) { mkd_generatehtml(document, out); mkd_cleanup(document); return 0; } return -1; } /* write out a Cstring, mangled into a form suitable for ` 0; ) { c = *s++; if ( c == ' ' || c == '&' || c == '<' || c == '"' ) (*outchar)('+', out); else if ( isalnum(c) || ispunct(c) || (c & 0x80) ) (*outchar)(c, out); else (*outchar)('~',out); } } /* ___mkd_reparse() a line */ static void mkd_parse_line(char *bfr, int size, MMIOT *f, int flags) { ___mkd_initmmiot(f, 0); f->flags = flags & USER_FLAGS; ___mkd_reparse(bfr, size, 0, f); ___mkd_emblock(f); } /* ___mkd_reparse() a line, returning it in malloc()ed memory */ int mkd_line(char *bfr, int size, char **res, int flags) { MMIOT f; int len; mkd_parse_line(bfr, size, &f, flags); if ( len = S(f.out) ) { /* kludge alert; we know that T(f.out) is malloced memory, * so we can just steal it away. This is awful -- there * should be an opaque method that transparently moves * the pointer out of the embedded Cstring. */ *res = T(f.out); T(f.out) = 0; S(f.out) = 0; } else { *res = 0; len = EOF; } ___mkd_freemmiot(&f, 0); return len; } /* ___mkd_reparse() a line, writing it to a FILE */ int mkd_generateline(char *bfr, int size, FILE *output, int flags) { MMIOT f; mkd_parse_line(bfr, size, &f, flags); if ( flags & CDATA_OUTPUT ) mkd_generatexml(T(f.out), S(f.out), output); else fwrite(T(f.out), S(f.out), 1, output); ___mkd_freemmiot(&f, 0); return 0; } /* set the url display callback */ void mkd_e_url(Document *f, mkd_callback_t edit) { if ( f ) f->cb.e_url = edit; } /* set the url options callback */ void mkd_e_flags(Document *f, mkd_callback_t edit) { if ( f ) f->cb.e_flags = edit; } /* set the url display/options deallocator */ void mkd_e_free(Document *f, mkd_free_t dealloc) { if ( f ) f->cb.e_free = dealloc; } /* set the url display/options context data field */ void mkd_e_data(Document *f, void *data) { if ( f ) f->cb.e_data = data; } rdiscount-1.6.8/ext/toc.c0000644000175000017500000000421411643305656015241 0ustar virtualvirtual/* * toc -- spit out a table of contents based on header blocks * * Copyright (C) 2008 Jjgod Jiang, 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" /* write an header index */ int mkd_toc(Document *p, char **doc) { Paragraph *tp, *srcp; int last_hnumber = 0; Cstring res; CREATE(res); RESERVE(res, 100); *doc = 0; if ( !(p && p->ctx) ) return -1; if ( ! (p->ctx->flags & TOC) ) return 0; for ( tp = p->code; tp ; tp = tp->next ) { if ( tp->typ == SOURCE ) { for ( srcp = tp->down; srcp; srcp = srcp->next ) { if ( srcp->typ == HDR && srcp->text ) { if ( last_hnumber == srcp->hnumber ) Csprintf(&res, "%*s\n", srcp->hnumber, ""); else while ( last_hnumber > srcp->hnumber ) { Csprintf(&res, "%*s\n%*s\n", last_hnumber, "", last_hnumber-1,""); --last_hnumber; } while ( srcp->hnumber > last_hnumber ) { Csprintf(&res, "\n%*s\n", last_hnumber, "", last_hnumber, ""); --last_hnumber; } /* HACK ALERT! HACK ALERT! HACK ALERT! */ *doc = T(res); /* we know that a T(Cstring) is a character pointer */ /* so we can simply pick it up and carry it away, */ return S(res); /* leaving the husk of the Ctring on the stack */ /* END HACK ALERT */ } /* write an header index */ int mkd_generatetoc(Document *p, FILE *out) { char *buf = 0; int sz = mkd_toc(p, &buf); int ret = EOF; if ( sz > 0 ) ret = fwrite(buf, sz, 1, out); if ( buf ) free(buf); return ret; } rdiscount-1.6.8/ext/dumptree.c0000644000175000017500000000547711643305656016315 0ustar virtualvirtual/* markdown: a C implementation of John Gruber's Markdown markup language. * * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include #include "markdown.h" #include "cstring.h" #include "amalloc.h" struct frame { int indent; char c; }; typedef STRING(struct frame) Stack; static char * Pptype(int typ) { switch (typ) { case WHITESPACE: return "whitespace"; case CODE : return "code"; case QUOTE : return "quote"; case MARKUP : return "markup"; case HTML : return "html"; case DL : return "dl"; case UL : return "ul"; case OL : return "ol"; case LISTITEM : return "item"; case HDR : return "header"; case HR : return "hr"; case TABLE : return "table"; case SOURCE : return "source"; case STYLE : return "style"; default : return "mystery node!"; } } static void pushpfx(int indent, char c, Stack *sp) { struct frame *q = &EXPAND(*sp); q->indent = indent; q->c = c; } static void poppfx(Stack *sp) { S(*sp)--; } static void changepfx(Stack *sp, char c) { char ch; if ( !S(*sp) ) return; ch = T(*sp)[S(*sp)-1].c; if ( ch == '+' || ch == '|' ) T(*sp)[S(*sp)-1].c = c; } static void printpfx(Stack *sp, FILE *f) { int i; char c; if ( !S(*sp) ) return; c = T(*sp)[S(*sp)-1].c; if ( c == '+' || c == '-' ) { fprintf(f, "--%c", c); T(*sp)[S(*sp)-1].c = (c == '-') ? ' ' : '|'; } else for ( i=0; i < S(*sp); i++ ) { if ( i ) fprintf(f, " "); fprintf(f, "%*s%c", T(*sp)[i].indent + 2, " ", T(*sp)[i].c); if ( T(*sp)[i].c == '`' ) T(*sp)[i].c = ' '; } fprintf(f, "--"); } static void dumptree(Paragraph *pp, Stack *sp, FILE *f) { int count; Line *p; int d; static char *Begin[] = { 0, "P", "center" }; while ( pp ) { if ( !pp->next ) changepfx(sp, '`'); printpfx(sp, f); d = fprintf(f, "[%s", Pptype(pp->typ)); if ( pp->ident ) d += fprintf(f, " %s", pp->ident); if ( pp->align ) 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; } rdiscount-1.6.8/ext/markdown.h0000644000175000017500000001176411643305656016313 0ustar virtualvirtual#ifndef _MARKDOWN_D #define _MARKDOWN_D #include "cstring.h" /* reference-style links (and images) are stored in an array * of footnotes. */ typedef struct footnote { Cstring tag; /* the tag for the reference link */ Cstring link; /* what this footnote points to */ Cstring title; /* what it's called (TITLE= attribute) */ int height, width; /* dimensions (for image link) */ int dealloc; /* deallocation needed? */ } 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 */ char *ident; /* %id% tag for QUOTE */ enum { WHITESPACE=0, CODE, QUOTE, MARKUP, HTML, STYLE, DL, UL, OL, AL, LISTITEM, HDR, HR, TABLE, SOURCE } typ; enum { IMPLICIT=0, PARA, CENTER} align; int hnumber; /* for typ == HDR */ } Paragraph; enum { ETX, SETEXT }; /* header types */ typedef struct block { enum { bTEXT, bSTAR, bUNDER } b_type; int b_count; char b_char; Cstring b_text; Cstring b_post; } block; typedef STRING(block) Qblock; typedef char* (*mkd_callback_t)(const char*, const int, void*); typedef void (*mkd_free_t)(char*, void*); typedef struct callback_data { void *e_data; /* private data for callbacks */ mkd_callback_t e_url; /* url edit callback */ mkd_callback_t e_flags; /* extra href flags callback */ mkd_free_t e_free; /* edit/flags callback memory deallocator */ } Callback_data; /* a magic markdown io thing holds all the data structures needed to * do the backend processing of a markdown document */ typedef struct mmiot { Cstring out; Cstring in; Qblock Q; int isp; STRING(Footnote) *footnotes; int flags; #define DENY_A 0x0001 #define DENY_IMG 0x0002 #define DENY_SMARTY 0x0004 #define DENY_HTML 0x0008 #define STRICT 0x0010 #define INSIDE_TAG 0x0020 #define NO_PSEUDO_PROTO 0x0040 #define CDATA_OUTPUT 0x0080 #define NOTABLES 0x0400 #define NOSTRIKETHROUGH 0x0800 #define TOC 0x1000 #define MKD_1_COMPAT 0x2000 #define AUTOLINK 0x4000 #define SAFELINK 0x8000 #define USER_FLAGS 0xFCFF #define EMBEDDED DENY_A|DENY_IMG|NO_PSEUDO_PROTO|CDATA_OUTPUT Callback_data *cb; } MMIOT; /* * the mkdio text input functions return a document structure, * which contains a header (retrieved from the document if * markdown was configured * with the * --enable-pandoc-header * and the document begins with a pandoc-style header) and the * root of the linked list of Lines. */ typedef struct document { int magic; /* "I AM VALID" magic number */ #define VALID_DOCUMENT 0x19600731 Line *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 */ Callback_data cb; /* callback functions & private data */ } 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 int mkd_css(Document *, char **); extern int mkd_generatecss(Document *, FILE *); #define mkd_style mkd_generatecss extern int mkd_xml(char *, int , char **); extern int mkd_generatexml(char *, int, FILE *); extern void mkd_cleanup(Document *); extern int mkd_line(char *, int, char **, int); extern int mkd_generateline(char *, int, FILE*, int); #define mkd_text mkd_generateline extern void mkd_basename(Document*, char *); extern void mkd_string_to_anchor(char*,int, void(*)(int,void*), void*); 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_freefootnote(Footnote *); extern void ___mkd_freefootnotes(MMIOT *); extern void ___mkd_initmmiot(MMIOT *, void *); extern void ___mkd_freemmiot(MMIOT *, void *); extern void ___mkd_freeLineRange(Line *, Line *); extern void ___mkd_xml(char *, int, FILE *); extern void ___mkd_reparse(char *, int, int, MMIOT*); extern void ___mkd_emblock(MMIOT*); extern void ___mkd_tidy(Cstring *); #endif/*_MARKDOWN_D*/ rdiscount-1.6.8/ext/css.c0000644000175000017500000000277011643305656015251 0ustar virtualvirtual/* markdown: a C implementation of John Gruber's Markdown markup language. * * Copyright (C) 2009 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include #include #include #include #include #include #include "config.h" #include "cstring.h" #include "markdown.h" #include "amalloc.h" /* * dump out stylesheet sections. */ static void stylesheets(Paragraph *p, Cstring *f) { Line* q; for ( ; p ; p = p->next ) { if ( p->typ == STYLE ) { for ( q = p->text; q ; q = q->next ) Cswrite(f, T(q->text), S(q->text)); Csputc('\n', f); } if ( p->down ) stylesheets(p->down, f); } } /* dump any embedded styles to a string */ int mkd_css(Document *d, char **res) { Cstring f; if ( res && *res && d && d->compiled ) { CREATE(f); RESERVE(f, 100); stylesheets(d->code, &f); /* HACK ALERT! HACK ALERT! HACK ALERT! */ *res = T(f); /* we know that a T(Cstring) is a character pointer */ /* so we can simply pick it up and carry it away, */ return S(f); /* leaving the husk of the Ctring on the stack */ /* END HACK ALERT */ } return EOF; } /* dump any embedded styles to a file */ int mkd_generatecss(Document *d, FILE *f) { char *res; int written = EOF, size = mkd_css(d, &res); if ( size > 0 ) written = fwrite(res, size, 1, f); if ( res ) free(res); return (written == size) ? size : EOF; } rdiscount-1.6.8/ext/extconf.rb0000644000175000017500000000031311643305656016277 0ustar virtualvirtualrequire 'mkmf' dir_config('rdiscount') HAVE_RANDOM = have_func('random') HAVE_SRANDOM = have_func('srandom') HAVE_RAND = have_func('rand') HAVE_SRAND = have_func('srand') create_makefile('rdiscount') rdiscount-1.6.8/ext/html5.c0000644000175000017500000000074011643305656015505 0ustar virtualvirtual/* block-level tags for passing html5 blocks through the blender */ #include "tags.h" void mkd_with_html5_tags() { static int populated = 0; if ( populated ) return; populated = 1; mkd_prepare_tags(); mkd_define_tag("ASIDE", 0); mkd_define_tag("FOOTER", 0); mkd_define_tag("HEADER", 0); mkd_define_tag("HGROUP", 0); mkd_define_tag("NAV", 0); mkd_define_tag("SECTION", 0); mkd_define_tag("ARTICLE", 0); mkd_sort_tags(); } rdiscount-1.6.8/ext/tags.h0000644000175000017500000000045211643305656015417 0ustar virtualvirtual/* block-level tags for passing html blocks through the blender */ #ifndef _TAGS_D #define _TAGS_D struct kw { char *id; int size; int selfclose; } ; struct kw* mkd_search_tags(char *, int); void mkd_prepare_tags(); void mkd_sort_tags(); void mkd_define_tag(char *, int); #endif rdiscount-1.6.8/ext/docheader.c0000644000175000017500000000152311643305656016372 0ustar virtualvirtual/* * 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; } rdiscount-1.6.8/ext/Csio.c0000644000175000017500000000175511643305656015360 0ustar virtualvirtual#include #include #include #include "cstring.h" #include "markdown.h" #include "amalloc.h" /* putc() into a cstring */ void Csputc(int c, Cstring *iot) { EXPAND(*iot) = c; } /* printf() into a cstring */ int Csprintf(Cstring *iot, char *fmt, ...) { va_list ptr; int siz=100; do { RESERVE(*iot, siz); va_start(ptr, fmt); siz = vsnprintf(T(*iot)+S(*iot), ALLOCATED(*iot)-S(*iot), fmt, ptr); va_end(ptr); } while ( siz > (ALLOCATED(*iot)-S(*iot)) ); S(*iot) += siz; return siz; } /* write() into a cstring */ int Cswrite(Cstring *iot, char *bfr, int size) { RESERVE(*iot, size); memcpy(T(*iot)+S(*iot), bfr, size); S(*iot) += size; return size; } /* reparse() into a cstring */ void Csreparse(Cstring *iot, char *buf, int size, int flags) { MMIOT f; ___mkd_initmmiot(&f, 0); ___mkd_reparse(buf, size, 0, &f); ___mkd_emblock(&f); SUFFIX(*iot, T(f.out), S(f.out)); ___mkd_freemmiot(&f, 0); } rdiscount-1.6.8/ext/amalloc.h0000644000175000017500000000075411643305656016076 0ustar virtualvirtual/* * 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*/ rdiscount-1.6.8/ext/config.h0000644000175000017500000000055011643305656015725 0ustar virtualvirtual /* rdiscount extension configuration */ #undef USE_AMALLOC #define TABSTOP 4 #if HAVE_RANDOM #define COINTOSS() (random()&1) #elif HAVE_RAND #define COINTOSS() (rand()&1) #endif #if HAVE_SRANDOM #define INITRNG(x) srandom((unsigned int)x) #elif HAVE_SRAND #define INITRNG(x) srand((unsigned int)x) #endif #define RELAXED_EMPHASIS 1 #define SUPERSCRIPT 1 rdiscount-1.6.8/ext/xml.c0000644000175000017500000000316511643305656015260 0ustar virtualvirtual/* markdown: a C implementation of John Gruber's Markdown markup language. * * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include #include #include #include #include #include #include "config.h" #include "cstring.h" #include "markdown.h" #include "amalloc.h" /* return the xml version of a character */ static char * mkd_xmlchar(unsigned char c) { switch (c) { case '<': return "<"; case '>': return ">"; case '&': return "&"; case '"': return """; case '\'': return "'"; default: if ( isascii(c) || (c & 0x80) ) return 0; return ""; } } /* write output in XML format */ int mkd_generatexml(char *p, int size, FILE *out) { unsigned char c; char *entity; while ( size-- > 0 ) { c = *p++; if ( entity = mkd_xmlchar(c) ) fputs(entity, out); else fputc(c, out); } return 0; } /* build a xml'ed version of a string */ int mkd_xml(char *p, int size, char **res) { unsigned char c; char *entity; Cstring f; CREATE(f); RESERVE(f, 100); while ( size-- > 0 ) { c = *p++; if ( entity = mkd_xmlchar(c) ) Cswrite(&f, entity, strlen(entity)); else Csputc(c, &f); } /* HACK ALERT! HACK ALERT! HACK ALERT! */ *res = T(f); /* we know that a T(Cstring) is a character pointer */ /* so we can simply pick it up and carry it away, */ return S(f); /* leaving the husk of the Ctring on the stack */ /* END HACK ALERT */ } rdiscount-1.6.8/ext/markdown.c0000644000175000017500000005150211643305656016300 0ustar virtualvirtual/* markdown: a C implementation of John Gruber's Markdown markup language. * * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include "config.h" #include #include #include #include #include #include #include "cstring.h" #include "markdown.h" #include "amalloc.h" #include "tags.h" typedef int (*stfu)(const void*,const void*); typedef ANCHOR(Paragraph) ParagraphRoot; /* 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; } void ___mkd_tidy(Cstring *t) { while ( S(*t) && isspace(T(*t)[S(*t)-1]) ) --S(*t); } static struct kw comment = { "!--", 3, 0 }; static struct kw * isopentag(Line *p) { int i=0, len; char *line; if ( !p ) return 0; line = T(p->text); len = S(p->text); if ( len < 3 || line[0] != '<' ) return 0; if ( line[1] == '!' && line[2] == '-' && line[3] == '-' ) /* comments need special case handling, because * the !-- doesn't need to end in a whitespace */ return &comment; /* find how long the tag is so we can check to see if * it's a block-level tag */ for ( i=1; i < len && T(p->text)[i] != '>' && T(p->text)[i] != '/' && !isspace(T(p->text)[i]); ++i ) ; return mkd_search_tags(T(p->text)+1, i-1); } typedef struct _flo { Line *t; int i; } FLO; #define floindex(x) (x.i) static int flogetc(FLO *f) { if ( f && f->t ) { if ( f->i < S(f->t->text) ) return T(f->t->text)[f->i++]; f->t = f->t->next; f->i = 0; return flogetc(f); } return EOF; } static void splitline(Line *t, int cutpoint) { if ( t && (cutpoint < S(t->text)) ) { Line *tmp = calloc(1, sizeof *tmp); tmp->next = t->next; t->next = tmp; tmp->dle = t->dle; SUFFIX(tmp->text, T(t->text)+cutpoint, S(t->text)-cutpoint); S(t->text) = cutpoint; } } static Line * commentblock(Paragraph *p) { Line *t, *ret; char *end; for ( t = p->text; t ; t = t->next) { if ( end = strstr(T(t->text), "-->") ) { splitline(t, 3 + (end - T(t->text)) ); ret = t->next; t->next = 0; return ret; } } return t; } static Line * htmlblock(Paragraph *p, struct kw *tag) { Line *ret; FLO f = { p->text, 0 }; int c; int i, closing, depth=0; if ( tag == &comment ) return commentblock(p); if ( tag->selfclose ) { ret = f.t->next; f.t->next = 0; return ret; } while ( (c = flogetc(&f)) != EOF ) { if ( c == '<' ) { /* tag? */ c = flogetc(&f); if ( c == '!' ) { /* comment? */ if ( flogetc(&f) == '-' && flogetc(&f) == '-' ) { /* yes */ while ( (c = flogetc(&f)) != EOF ) { if ( c == '-' && flogetc(&f) == '-' && flogetc(&f) == '>') /* consumed whole comment */ break; } } } else { if ( closing = (c == '/') ) c = flogetc(&f); for ( i=0; i < tag->size; c=flogetc(&f) ) { if ( tag->id[i++] != toupper(c) ) break; } if ( (i == tag->size) && !isalnum(c) ) { depth = depth + (closing ? -1 : 1); if ( depth == 0 ) { while ( c != EOF && c != '>' ) { /* consume trailing gunk in close tag */ c = flogetc(&f); } if ( !f.t ) return 0; splitline(f.t, floindex(f)); ret = f.t->next; f.t->next = 0; return ret; } } } } } return 0; } /* tables look like * header|header{|header} * ------|------{|......} * {body lines} */ static int istable(Line *t) { char *p; Line *dashes = t->next; int contains = 0; /* found character bits; 0x01 is |, 0x02 is - */ /* two lines, first must contain | */ if ( !(dashes && memchr(T(t->text), '|', S(t->text))) ) return 0; /* second line must contain - or | and nothing * else except for whitespace or : */ for ( p = T(dashes->text)+S(dashes->text)-1; p >= T(dashes->text); --p) if ( *p == '|' ) contains |= 0x01; else if ( *p == '-' ) contains |= 0x02; else if ( ! ((*p == ':') || isspace(*p)) ) return 0; return (contains & 0x03); } /* footnotes look like ^{0,3}[stuff]: $ */ static int isfootnote(Line *t) { int i; if ( ( (i = t->dle) > 3) || (T(t->text)[i] != '[') ) return 0; for ( ++i; i < S(t->text) ; ++i ) { if ( T(t->text)[i] == '[' ) return 0; else if ( T(t->text)[i] == ']' ) return ( T(t->text)[i+1] == ':' ) ; } return 0; } static int isquote(Line *t) { int j; for ( j=0; j < 4; j++ ) if ( T(t->text)[j] == '>' ) return 1; else if ( !isspace(T(t->text)[j]) ) return 0; return 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 issetext(Line *t, int *htyp) { int i; /* then check for setext-style HEADER * ====== */ if ( t->next ) { char *q = T(t->next->text); int last = S(t->next->text); if ( (*q == '=') || (*q == '-') ) { /* ignore trailing whitespace */ while ( (last > 1) && isspace(q[last-1]) ) --last; for (i=1; i < last; i++) if ( q[0] != q[i] ) return 0; *htyp = SETEXT; return 1; } } return 0; } static int ishdr(Line *t, int *htyp) { int i; /* first check for etx-style ###HEADER### */ /* leading run of `#`'s ? */ for ( i=0; T(t->text)[i] == '#'; ++i) ; /* ANY leading `#`'s make this into an ETX header */ if ( i && (i < S(t->text) || i > 1) ) { *htyp = ETX; return 1; } return issetext(t, htyp); } 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] == '.' ) { #if ALPHA_LIST if ( (j == t->dle + 2) && isalpha(T(t->text)[t->dle]) ) { j = nextnonblank(t,j); *trim = j; return AL; } #endif 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 < S(p->text)-1) && (i < 6); i++) ; pp->hnumber = i; while ( (i < S(p->text)) && isspace(T(p->text)[i]) ) ++i; CLIP(p->text, 0, i); for (j=S(p->text); (j > 1) && (T(p->text)[j-1] == '#'); --j) ; while ( j && isspace(T(p->text)[j-1]) ) --j; S(p->text) = j; ret = p->next; p->next = 0; break; } return ret; } static Line * codeblock(Paragraph *p) { Line *t = p->text, *r; for ( ; t; t = r ) { CLIP(t->text,0,4); t->dle = mkd_firstnonblank(t); if ( !( (r = skipempty(t->next)) && iscode(r)) ) { ___mkd_freeLineRange(t,r); t->next = 0; return r; } } return t; } 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; } /* length of the id: or class: kind in a special div-not-quote block */ static int szmarkerclass(char *p) { if ( strncasecmp(p, "id:", 3) == 0 ) return 3; if ( strncasecmp(p, "class:", 6) == 0 ) return 6; return 0; } /* * check if the first line of a quoted block is the special div-not-quote * marker %[kind:]name% */ static int isdivmarker(Line *p, int start) { #if DIV_QUOTE char *s = T(p->text); int len = S(p->text); int i; if ( !(len && s[start] == '%' && s[len-1] == '%') ) return 0; i = szmarkerclass(s+start+1)+start; len -= start+1; while ( ++i < len ) if ( !isalnum(s[i]) ) return 0; return 1; #else return 0; #endif } /* * 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) ) { /* clip leading spaces */ for (qp = 0; T(t->text)[qp] != '>'; qp ++) /* assert: the first nonblank character on this line * will be a > */; /* clip '>' */ qp++; /* clip next space, if any */ if ( T(t->text)[qp] == ' ' ) qp++; CLIP(t->text, 0, qp); t->dle = mkd_firstnonblank(t); } q = skipempty(t->next); if ( (q == 0) || ((q != t->next) && (!isquote(q) || isdivmarker(q,1))) ) { ___mkd_freeLineRange(t, q); t = q; break; } } if ( isdivmarker(p->text,0) ) { char *prefix = "class"; int i; q = p->text; p->text = p->text->next; if ( (i = szmarkerclass(1+T(q->text))) == 3 ) /* and this would be an "%id:" prefix */ prefix="id"; if ( p->ident = malloc(4+strlen(prefix)+S(q->text)) ) sprintf(p->ident, "%s=\"%.*s\"", prefix, S(q->text)-(i+2), T(q->text)+(i+1) ); ___mkd_freeLine(q); } return t; } /* * A table block starts with a table header (see istable()), and continues * until EOF or a line that /doesn't/ contain a |. */ static Line * tableblock(Paragraph *p) { Line *t, *q; for ( t = p->text; t && (q = t->next); t = t->next ) { if ( !memchr(T(q->text), '|', S(q->text)) ) { t->next = 0; return q; } } return 0; } 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(? -- reference implementation allows a 1 * character indent, but that has unfortunate side effects here) * spaces, but after that the line doesn't need any indentation */ if ( q != t->next ) { if (q->dle < indent) { q = t->next; t->next = 0; return q; } /* indent at least 2, and at most as * as far as the initial line was indented. */ indent = clip ? clip : 2; } if ( (q->dle < indent) && (ishr(q) || islist(q,&z)) && !issetext(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, *label; int isdl = (top->typ == DL), para = 0, ltype; 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 ) p->down->align = PARA; if ( !(q = skipempty(text)) || ((ltype = islist(q, &trim)) == 0) || (isdl != (ltype == DL)) ) break; if ( para = (q != text) ) { Line anchor; anchor.next = text; ___mkd_freeLineRange(&anchor, q); } if ( para && (top->typ != DL) && p->down ) p->down->align = PARA; } top->text = 0; top->down = T(d); return text; } static int tgood(char c) { switch (c) { case '\'': case '"': return c; case '(': return ')'; } return 0; } /* * add a new (image or link) footnote to the footnote table */ static Line* addfootnote(Line *p, MMIOT* f) { int j, i; int c; Line *np = p->next; Footnote *foot = &EXPAND(*f->footnotes); CREATE(foot->tag); CREATE(foot->link); CREATE(foot->title); foot->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; } /* * top-level compilation; break the document into * style, html, and source blocks with footnote links * weeded out. */ static Paragraph * compile_document(Line *ptr, MMIOT *f) { ParagraphRoot d = { 0, 0 }; ANCHOR(Line) source = { 0, 0 }; Paragraph *p = 0; struct kw *tag; int eaten; while ( ptr ) { if ( !(f->flags & DENY_HTML) && (tag = isopentag(ptr)) ) { /* If we encounter a html/style block, compile and save all * of the cached source BEFORE processing the html/style. */ if ( T(source) ) { E(source)->next = 0; p = Pp(&d, 0, SOURCE); p->down = compile(T(source), 1, f); T(source) = E(source) = 0; } p = Pp(&d, ptr, strcmp(tag->id, "STYLE") == 0 ? STYLE : HTML); ptr = htmlblock(p, tag); } else if ( isfootnote(ptr) ) { /* footnotes, like cats, sleep anywhere; pull them * out of the input stream and file them away for * later processing */ ptr = consume(addfootnote(ptr, f), &eaten); } else { /* source; cache it up to wait for eof or the * next html/style block */ ATTACH(source,ptr); ptr = ptr->next; } } if ( T(source) ) { /* if there's any cached source at EOF, compile * it now. */ E(source)->next = 0; p = Pp(&d, 0, SOURCE); p->down = compile(T(source), 1, f); } return T(d); } /* * break a collection of markdown input into * blocks of lists, code, html, and text to * be marked up. */ static Paragraph * compile(Line *ptr, int toplevel, MMIOT *f) { ParagraphRoot d = { 0, 0 }; Paragraph *p = 0; Line *r; int para = toplevel; int blocks = 0; int hdr_type, list_type, indent; ptr = consume(ptr, ¶); while ( ptr ) { if ( iscode(ptr) ) { p = Pp(&d, ptr, CODE); if ( f->flags & MKD_1_COMPAT) { /* HORRIBLE STANDARDS KLUDGE: the first line of every block * has trailing whitespace trimmed off. */ ___mkd_tidy(&p->text->text); } ptr = codeblock(p); } 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 ( istable(ptr) && !(f->flags & (STRICT|NOTABLES)) ) { p = Pp(&d, ptr, TABLE); ptr = tableblock(p); } else { p = Pp(&d, ptr, MARKUP); ptr = textblock(p, toplevel); } if ( (para||toplevel) && !p->align ) p->align = PARA; blocks++; para = toplevel || (blocks > 1); ptr = consume(ptr, ¶); if ( para && !p->align ) p->align = PARA; } return T(d); } void mkd_initialize() { static int first = 1; if ( first-- > 0 ) { first = 0; INITRNG(time(0)); mkd_prepare_tags(); } } /* * 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->cb = &(doc->cb); doc->ctx->flags = flags & USER_FLAGS; CREATE(doc->ctx->in); doc->ctx->footnotes = malloc(sizeof doc->ctx->footnotes[0]); CREATE(*doc->ctx->footnotes); mkd_initialize(); doc->code = compile_document(T(doc->content), doc->ctx); qsort(T(*doc->ctx->footnotes), S(*doc->ctx->footnotes), sizeof T(*doc->ctx->footnotes)[0], (stfu)__mkd_footsort); memset(&doc->content, 0, sizeof doc->content); return 1; } rdiscount-1.6.8/ext/basename.c0000644000175000017500000000157311643305656016234 0ustar virtualvirtual/* * mkdio -- markdown front end input functions * * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include "config.h" #include #include #include #include "mkdio.h" #include "cstring.h" #include "amalloc.h" static char * e_basename(const char *string, const int size, void *context) { char *ret; char *base = (char*)context; if ( base && string && (*string == '/') && (ret=malloc(strlen(base)+size+2)) ) { strcpy(ret, base); strncat(ret, string, size); return ret; } return 0; } static void e_free(char *string, void *context) { if ( string ) free(string); } void mkd_basename(MMIOT *document, char *base) { mkd_e_url(document, e_basename); mkd_e_data(document, base); mkd_e_free(document, e_free); } rdiscount-1.6.8/lib/0000755000175000017500000000000011643305656014255 5ustar virtualvirtualrdiscount-1.6.8/lib/rdiscount.rb0000644000175000017500000000623611643305656016623 0ustar virtualvirtual# Discount is an implementation of John Gruber's Markdown markup # language in C. It implements all of the language as described in # {Markdown Syntax}[http://daringfireball.net/projects/markdown/syntax] # and passes the Markdown 1.0 test suite. The RDiscount extension makes # the Discount processor available via a Ruby C Extension library. # # == Usage # # RDiscount implements the basic protocol popularized by RedCloth and adopted # by BlueCloth: # require 'rdiscount' # markdown = RDiscount.new("Hello World!") # puts markdown.to_html # # == Replacing BlueCloth # # Inject RDiscount into your BlueCloth-using code by replacing your bluecloth # require statements with the following: # begin # require 'rdiscount' # BlueCloth = RDiscount # rescue LoadError # require 'bluecloth' # end # class RDiscount VERSION = '1.6.8' # Original Markdown formatted text. attr_reader :text # Set true to have smarty-like quote translation performed. attr_accessor :smart # Do not output