From 1547caf748a8bee075038364361633759b1fed88 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 2 May 2014 16:03:09 -0700 Subject: [PATCH 01/12] rustdoc: Fix inclusion of the new fonts These fonts were moved into place by rust's makefiles, but rustdoc is widely used outside of rustc itself. This moves the fonts into the rustdoc binary, similarly to the other static assets, and writes them to the output location whenever rustdoc generates documentation. Closes #13593 Closes #13787 --- mk/docs.mk | 20 ---------------- src/librustdoc/html/render.rs | 22 +++++++++++++----- .../html/static}/FiraSans-Medium.woff | Bin .../html/static}/FiraSans-Regular.woff | Bin .../html/static}/Heuristica-Bold.woff | Bin .../html/static}/Heuristica-Italic.woff | Bin .../html/static}/Heuristica-Regular.woff | Bin 7 files changed, 16 insertions(+), 26 deletions(-) rename src/{doc => librustdoc/html/static}/FiraSans-Medium.woff (100%) rename src/{doc => librustdoc/html/static}/FiraSans-Regular.woff (100%) rename src/{doc => librustdoc/html/static}/Heuristica-Bold.woff (100%) rename src/{doc => librustdoc/html/static}/Heuristica-Italic.woff (100%) rename src/{doc => librustdoc/html/static}/Heuristica-Regular.woff (100%) diff --git a/mk/docs.mk b/mk/docs.mk index 3e032d59728..9c79e1e8642 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -141,26 +141,6 @@ doc/footer.inc: $(D)/footer.inc | doc/ @$(call E, cp: $@) $(Q)cp -a $< $@ 2> /dev/null -doc/FiraSans-Regular.woff: $(D)/FiraSans-Regular.woff | doc/ - @$(call E, cp: $@) - $(Q)cp -a $< $@ 2> /dev/null - -doc/FiraSans-Medium.woff: $(D)/FiraSans-Medium.woff | doc/ - @$(call E, cp: $@) - $(Q)cp -a $< $@ 2> /dev/null - -doc/Heuristica-Regular.woff: $(D)/Heuristica-Regular.woff | doc/ - @$(call E, cp: $@) - $(Q)cp -a $< $@ 2> /dev/null - -doc/Heuristica-Italic.woff: $(D)/Heuristica-Italic.woff | doc/ - @$(call E, cp: $@) - $(Q)cp -a $< $@ 2> /dev/null - -doc/Heuristica-Bold.woff: $(D)/Heuristica-Bold.woff | doc/ - @$(call E, cp: $@) - $(Q)cp -a $< $@ 2> /dev/null - # The (english) documentation for each doc item. define DEF_SHOULD_BUILD_PDF_DOC diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index b8df8b772d2..a95d85741e4 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -362,11 +362,21 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { // Add all the static files. These may already exist, but we just // overwrite them anyway to make sure that they're fresh and up-to-date. try!(write(cx.dst.join("jquery.js"), - include_str!("static/jquery-2.1.0.min.js"))); - try!(write(cx.dst.join("main.js"), include_str!("static/main.js"))); - try!(write(cx.dst.join("main.css"), include_str!("static/main.css"))); + include_bin!("static/jquery-2.1.0.min.js"))); + try!(write(cx.dst.join("main.js"), include_bin!("static/main.js"))); + try!(write(cx.dst.join("main.css"), include_bin!("static/main.css"))); try!(write(cx.dst.join("normalize.css"), - include_str!("static/normalize.css"))); + include_bin!("static/normalize.css"))); + try!(write(cx.dst.join("FiraSans-Regular.woff"), + include_bin!("static/FiraSans-Regular.woff"))); + try!(write(cx.dst.join("FiraSans-Medium.woff"), + include_bin!("static/FiraSans-Medium.woff"))); + try!(write(cx.dst.join("Heuristica-Regular.woff"), + include_bin!("static/Heuristica-Regular.woff"))); + try!(write(cx.dst.join("Heuristica-Italic.woff"), + include_bin!("static/Heuristica-Italic.woff"))); + try!(write(cx.dst.join("Heuristica-Bold.woff"), + include_bin!("static/Heuristica-Bold.woff"))); // Update the search index let dst = cx.dst.join("search-index.js"); @@ -415,8 +425,8 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { /// Writes the entire contents of a string to a destination, not attempting to /// catch any errors. -fn write(dst: Path, contents: &str) -> io::IoResult<()> { - File::create(&dst).write(contents.as_bytes()) +fn write(dst: Path, contents: &[u8]) -> io::IoResult<()> { + File::create(&dst).write(contents) } /// Makes a directory on the filesystem, failing the task if an error occurs and diff --git a/src/doc/FiraSans-Medium.woff b/src/librustdoc/html/static/FiraSans-Medium.woff similarity index 100% rename from src/doc/FiraSans-Medium.woff rename to src/librustdoc/html/static/FiraSans-Medium.woff diff --git a/src/doc/FiraSans-Regular.woff b/src/librustdoc/html/static/FiraSans-Regular.woff similarity index 100% rename from src/doc/FiraSans-Regular.woff rename to src/librustdoc/html/static/FiraSans-Regular.woff diff --git a/src/doc/Heuristica-Bold.woff b/src/librustdoc/html/static/Heuristica-Bold.woff similarity index 100% rename from src/doc/Heuristica-Bold.woff rename to src/librustdoc/html/static/Heuristica-Bold.woff diff --git a/src/doc/Heuristica-Italic.woff b/src/librustdoc/html/static/Heuristica-Italic.woff similarity index 100% rename from src/doc/Heuristica-Italic.woff rename to src/librustdoc/html/static/Heuristica-Italic.woff diff --git a/src/doc/Heuristica-Regular.woff b/src/librustdoc/html/static/Heuristica-Regular.woff similarity index 100% rename from src/doc/Heuristica-Regular.woff rename to src/librustdoc/html/static/Heuristica-Regular.woff From 5d145c1c18abb1a6b81238dd1b73178635c12f0a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 2 May 2014 16:06:56 -0700 Subject: [PATCH 02/12] rustdoc: Don't have rustc emit warnings They're much more useful when building code, much less so when building documentation. Closes #13894 --- src/librustdoc/core.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 027d14babaf..c31261282fa 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -12,6 +12,7 @@ use rustc; use rustc::{driver, middle}; use rustc::metadata::creader::Loader; use rustc::middle::privacy; +use rustc::middle::lint; use syntax::ast; use syntax::parse::token; @@ -65,6 +66,7 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet, cfgs: Vec<~str>) maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()), addl_lib_search_paths: RefCell::new(libs), crate_types: vec!(driver::session::CrateTypeDylib), + lint_opts: vec!((lint::Warnings, lint::allow)), ..rustc::driver::session::basic_options().clone() }; From 50fb77f8baed29bb1014893c8a1f3e66cbd8e3e1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 2 May 2014 16:15:12 -0700 Subject: [PATCH 03/12] rustdoc: Stop requiring a crate ID attribute This is mostly just an artificial requirement as it can use similar logic to the compiler to infer the crate id. --- src/librustdoc/clean.rs | 16 +++++++++++----- src/librustdoc/core.rs | 6 ++++-- src/librustdoc/test.rs | 3 ++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 06d768b4342..9fa1c57f991 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -20,6 +20,8 @@ use syntax::codemap::Pos; use syntax::parse::token::InternedString; use syntax::parse::token; +use rustc::back::link; +use rustc::driver::driver; use rustc::metadata::cstore; use rustc::metadata::csearch; use rustc::metadata::decoder; @@ -75,7 +77,6 @@ pub struct Crate { impl<'a> Clean for visit_ast::RustdocVisitor<'a> { fn clean(&self) -> Crate { - use syntax::attr::find_crateid; let cx = local_data::get(super::ctxtkey, |x| *x.unwrap()); let mut externs = Vec::new(); @@ -83,11 +84,16 @@ impl<'a> Clean for visit_ast::RustdocVisitor<'a> { externs.push((n, meta.clean())); }); + let input = driver::FileInput(cx.src.clone()); + let t_outputs = driver::build_output_filenames(&input, + &None, + &None, + self.attrs.as_slice(), + cx.sess()); + let id = link::find_crate_id(self.attrs.as_slice(), + t_outputs.out_filestem); Crate { - name: match find_crateid(self.attrs.as_slice()) { - Some(n) => n.name, - None => fail!("rustdoc requires a `crate_id` crate attribute"), - }, + name: id.name, module: Some(self.module.clean()), externs: externs, } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c31261282fa..9f89da563cc 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -34,7 +34,8 @@ pub enum MaybeTyped { pub struct DocContext { pub krate: ast::Crate, - pub maybe_typed: MaybeTyped + pub maybe_typed: MaybeTyped, + pub src: Path, } impl DocContext { @@ -96,7 +97,8 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet, cfgs: Vec<~str>) debug!("crate: {:?}", krate); (DocContext { krate: krate, - maybe_typed: Typed(ty_cx) + maybe_typed: Typed(ty_cx), + src: cpath.clone(), }, CrateAnalysis { exported_items: exported_items, public_items: public_items, diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index b05fdc826ff..27f0d8d5223 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -55,7 +55,7 @@ pub fn run(input: &str, cfgs: Vec<~str>, diagnostic::mk_span_handler(diagnostic_handler, codemap); let sess = driver::build_session_(sessopts, - Some(input_path), + Some(input_path.clone()), span_diagnostic_handler); let mut cfg = driver::build_configuration(&sess); @@ -70,6 +70,7 @@ pub fn run(input: &str, cfgs: Vec<~str>, let ctx = @core::DocContext { krate: krate, maybe_typed: core::NotTyped(sess), + src: input_path, }; local_data::set(super::ctxtkey, ctx); From 0b7954fa809690037bcb80f44d3383329bce48ad Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 2 May 2014 16:25:45 -0700 Subject: [PATCH 04/12] rustdoc: Put bangs on the names of macros This makes them a little easier to search for and makes it clearer that they're a macro and not an item to import. Closes #13852 --- src/librustdoc/clean.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 9fa1c57f991..1cb994e1662 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -1367,7 +1367,7 @@ pub struct Macro { impl Clean for doctree::Macro { fn clean(&self) -> Item { Item { - name: Some(self.name.clean()), + name: Some(self.name.clean() + "!"), attrs: self.attrs.clean(), source: self.where.clean(), visibility: ast::Public.clean(), From 71a52a2edc76527e3bba92378da633bb1fde3743 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 2 May 2014 16:39:08 -0700 Subject: [PATCH 05/12] syntax: Fix duplicate attributes on module files The outer attributes were manually appended when a module file was parsed, but the attributes were also added higher up the stack of parsing (when the module finished parsing). This removes the append in parsing the module file. Closes #13826 --- src/libsyntax/parse/parser.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5d8443b64d5..2173a15b5f1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4155,14 +4155,11 @@ impl<'a> Parser<'a> { } }; - self.eval_src_mod_from_path(file_path, - outer_attrs.iter().map(|x| *x).collect(), - id_sp) + self.eval_src_mod_from_path(file_path, id_sp) } fn eval_src_mod_from_path(&mut self, path: Path, - outer_attrs: Vec , id_sp: Span) -> (ast::Item_, Vec ) { let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut(); match included_mod_stack.iter().position(|p| *p == path) { @@ -4187,8 +4184,7 @@ impl<'a> Parser<'a> { &path, id_sp); let mod_inner_lo = p0.span.lo; - let (inner, next) = p0.parse_inner_attrs_and_next(); - let mod_attrs = outer_attrs.append(inner.as_slice()); + let (mod_attrs, next) = p0.parse_inner_attrs_and_next(); let first_item_outer_attrs = next; let m0 = p0.parse_mod_items(token::EOF, first_item_outer_attrs, mod_inner_lo); self.sess.included_mod_stack.borrow_mut().pop(); From eb084b1818bb220928d1c99e241192f2cd98b069 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 2 May 2014 17:08:11 -0700 Subject: [PATCH 06/12] rustdoc: Make static initalizers prettier Previously, if an initializer took multiple lines or was just large in general, it was pretty poorly rendered [1] [2]. This alters the logic to just link back to the source for any multi-line static, with a placeholder of "[definition]". This should make reading statics a little easier on the eyes. All single-line statics are still inlined in the documentation. Closes #13198 [1] - http://static.rust-lang.org/doc/master/sync/mutex/index.html#statics [2] - http://static.rust-lang.org/doc/master/std/sync/atomics/index.html#statics --- src/librustdoc/html/render.rs | 53 +++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index a95d85741e4..504be2cd8ae 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -930,6 +930,23 @@ impl<'a> Item<'a> { clean::ModuleItem(..) => true, _ => false } } + + fn link(&self) -> ~str { + let mut path = Vec::new(); + clean_srcpath(self.item.source.filename.as_bytes(), |component| { + path.push(component.to_owned()); + }); + let href = if self.item.source.loline == self.item.source.hiline { + format!("{}", self.item.source.loline) + } else { + format!("{}-{}", self.item.source.loline, self.item.source.hiline) + }; + format!("{root}src/{krate}/{path}.html\\#{href}", + root = self.cx.root_path, + krate = self.cx.layout.krate, + path = path.connect("/"), + href = href) + } } impl<'a> fmt::Show for Item<'a> { @@ -977,23 +994,8 @@ impl<'a> fmt::Show for Item<'a> { // Write `src` tag if self.cx.include_sources { - let mut path = Vec::new(); - clean_srcpath(self.item.source.filename.as_bytes(), |component| { - path.push(component.to_owned()); - }); - let href = if self.item.source.loline == self.item.source.hiline { - format!("{}", self.item.source.loline) - } else { - format!("{}-{}", self.item.source.loline, self.item.source.hiline) - }; - try!(write!(fmt.buf, - "\ - [src]", - root = self.cx.root_path, - krate = self.cx.layout.krate, - path = path.connect("/"), - href = href)); + try!(write!(fmt.buf, "[src]", + self.link())); } try!(write!(fmt.buf, "\n")); @@ -1138,16 +1140,19 @@ fn item_module(w: &mut Writer, cx: &Context, match myitem.inner { clean::StaticItem(ref s) | clean::ForeignStaticItem(ref s) => { - struct Initializer<'a>(&'a str); + struct Initializer<'a>(&'a str, Item<'a>); impl<'a> fmt::Show for Initializer<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let Initializer(s) = *self; + let Initializer(s, item) = *self; if s.len() == 0 { return Ok(()); } try!(write!(f.buf, " = ")); - let tag = if s.contains("\n") { "pre" } else { "code" }; - try!(write!(f.buf, "<{tag}>{}", - s.as_slice(), tag=tag)); - Ok(()) + if s.contains("\n") { + write!(f.buf, + "[definition]", + item.link()) + } else { + write!(f.buf, "{}", s.as_slice()) + } } } @@ -1160,7 +1165,7 @@ fn item_module(w: &mut Writer, cx: &Context, VisSpace(myitem.visibility), *myitem.name.get_ref(), s.type_, - Initializer(s.expr), + Initializer(s.expr, Item { cx: cx, item: myitem }), Markdown(blank(myitem.doc_value())))); } From 52955dd661bdbb37778ff32da5746e1012119ba3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 2 May 2014 17:16:30 -0700 Subject: [PATCH 07/12] rustdoc: Allow forcing inlining of `pub use` Rustdoc currently doesn't inline documentation of a `pub use` if the target is publicly reachable. This changes rustdoc to allow a #[doc(inline)] attribute to force inlining the documentation, regardless of whether the targe is public or not. Closes #13045 --- src/librustdoc/visit_ast.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 6e764c03e90..9f1ad02decd 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -15,6 +15,7 @@ use syntax::abi; use syntax::ast; use syntax::ast_util; use syntax::ast_map; +use syntax::attr::AttrMetaMethods; use syntax::codemap::Span; use core; @@ -133,9 +134,17 @@ impl<'a> RustdocVisitor<'a> { if item.vis != ast::Public { return om.view_items.push(item.clone()); } + let please_inline = item.attrs.iter().any(|item| { + match item.meta_item_list() { + Some(list) => { + list.iter().any(|i| i.name().get() == "inline") + } + None => false, + } + }); let item = match item.node { ast::ViewItemUse(ref vpath) => { - match self.visit_view_path(*vpath, om) { + match self.visit_view_path(*vpath, om, please_inline) { None => return, Some(path) => { ast::ViewItem { @@ -151,15 +160,16 @@ impl<'a> RustdocVisitor<'a> { } fn visit_view_path(&mut self, path: @ast::ViewPath, - om: &mut Module) -> Option<@ast::ViewPath> { + om: &mut Module, + please_inline: bool) -> Option<@ast::ViewPath> { match path.node { ast::ViewPathSimple(_, _, id) => { - if self.resolve_id(id, false, om) { return None } + if self.resolve_id(id, false, om, please_inline) { return None } } ast::ViewPathList(ref p, ref paths, ref b) => { let mut mine = Vec::new(); for path in paths.iter() { - if !self.resolve_id(path.node.id, false, om) { + if !self.resolve_id(path.node.id, false, om, please_inline) { mine.push(path.clone()); } } @@ -173,14 +183,14 @@ impl<'a> RustdocVisitor<'a> { // these are feature gated anyway ast::ViewPathGlob(_, id) => { - if self.resolve_id(id, true, om) { return None } + if self.resolve_id(id, true, om, please_inline) { return None } } } return Some(path); } fn resolve_id(&mut self, id: ast::NodeId, glob: bool, - om: &mut Module) -> bool { + om: &mut Module, please_inline: bool) -> bool { let tcx = match self.cx.maybe_typed { core::Typed(ref tcx) => tcx, core::NotTyped(_) => return false @@ -190,7 +200,9 @@ impl<'a> RustdocVisitor<'a> { let analysis = match self.analysis { Some(analysis) => analysis, None => return false }; - if analysis.public_items.contains(&def.node) { return false } + if !please_inline && analysis.public_items.contains(&def.node) { + return false + } match tcx.map.get(def.node) { ast_map::NodeItem(it) => { From 9ac9245564356d4fbefc6d71276423079bf5307b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 2 May 2014 17:19:19 -0700 Subject: [PATCH 08/12] rustdoc: Have no_run imply no_trans This allows writing code examples which pass all analysis of the compiler, but don't actually link. A good example is examples that use extern {} blocks. Closes #12903 --- src/doc/guide-ffi.md | 32 +++++++++++--------------------- src/librustdoc/test.rs | 1 + 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/doc/guide-ffi.md b/src/doc/guide-ffi.md index f0ffd46e6c2..d4267fd57a4 100644 --- a/src/doc/guide-ffi.md +++ b/src/doc/guide-ffi.md @@ -11,16 +11,14 @@ snappy includes a C interface (documented in The following is a minimal example of calling a foreign function which will compile if snappy is installed: -~~~~ +~~~~no_run extern crate libc; use libc::size_t; #[link(name = "snappy")] -# #[cfg(ignore_this)] extern { fn snappy_max_compressed_length(source_length: size_t) -> size_t; } -# unsafe fn snappy_max_compressed_length(a: size_t) -> size_t { a } fn main() { let x = unsafe { snappy_max_compressed_length(100) }; @@ -46,7 +44,7 @@ keeping the binding correct at runtime. The `extern` block can be extended to cover the entire snappy API: -~~~~ {.ignore} +~~~~no_run extern crate libc; use libc::{c_int, size_t}; @@ -67,6 +65,7 @@ extern { fn snappy_validate_compressed_buffer(compressed: *u8, compressed_length: size_t) -> c_int; } +# fn main() {} ~~~~ # Creating a safe interface @@ -209,19 +208,16 @@ A basic example is: Rust code: -~~~~ +~~~~no_run extern fn callback(a:i32) { println!("I'm called from C with value {0}", a); } #[link(name = "extlib")] -# #[cfg(ignore)] extern { fn register_callback(cb: extern fn(i32)) -> i32; fn trigger_callback(); } -# unsafe fn register_callback(cb: extern fn(i32)) -> i32 { 0 } -# unsafe fn trigger_callback() { } fn main() { unsafe { @@ -265,7 +261,7 @@ referenced Rust object. Rust code: -~~~~ +~~~~no_run struct RustObject { a: i32, @@ -281,15 +277,11 @@ extern fn callback(target: *mut RustObject, a:i32) { } #[link(name = "extlib")] -# #[cfg(ignore)] extern { fn register_callback(target: *mut RustObject, cb: extern fn(*mut RustObject, i32)) -> i32; fn trigger_callback(); } -# unsafe fn register_callback(a: *mut RustObject, -# b: extern fn(*mut RustObject, i32)) -> i32 { 0 } -# unsafe fn trigger_callback() {} fn main() { // Create the object that will be referenced in the callback @@ -398,9 +390,12 @@ the `link_args` attribute. This attribute is applied to `extern` blocks and specifies raw flags which need to get passed to the linker when producing an artifact. An example usage would be: -~~~ {.ignore} +~~~ no_run +#![feature(link_args)] + #[link_args = "-foo -bar -baz"] extern {} +# fn main() {} ~~~ Note that this feature is currently hidden behind the `feature(link_args)` gate @@ -434,15 +429,13 @@ Foreign APIs often export a global variable which could do something like track global state. In order to access these variables, you declare them in `extern` blocks with the `static` keyword: -~~~ +~~~no_run extern crate libc; #[link(name = "readline")] -# #[cfg(ignore)] extern { static rl_readline_version: libc::c_int; } -# static rl_readline_version: libc::c_int = 0; fn main() { println!("You have readline version {} installed.", @@ -454,16 +447,14 @@ Alternatively, you may need to alter global state provided by a foreign interface. To do this, statics can be declared with `mut` so rust can mutate them. -~~~ +~~~no_run extern crate libc; use std::ptr; #[link(name = "readline")] -# #[cfg(ignore)] extern { static mut rl_prompt: *libc::c_char; } -# static mut rl_prompt: *libc::c_char = 0 as *libc::c_char; fn main() { "[my-awesome-shell] $".with_c_str(|buf| { @@ -488,7 +479,6 @@ extern crate libc; extern "stdcall" { fn SetEnvironmentVariableA(n: *u8, v: *u8) -> libc::c_int; } - # fn main() { } ~~~~ diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 27f0d8d5223..5976856172b 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -103,6 +103,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet, should_fail: bool, addl_lib_search_paths: RefCell::new(libs), crate_types: vec!(session::CrateTypeExecutable), output_types: vec!(link::OutputTypeExe), + no_trans: no_run, cg: session::CodegenOptions { prefer_dynamic: true, .. session::basic_codegen_options() From 9306e840f59ac22651c6177a89352bf5d607fcbd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 2 May 2014 17:56:35 -0700 Subject: [PATCH 09/12] rustdoc: Migrate from sundown to hoedown This primary fix brought on by this upgrade is the proper matching of the ``` and ~~~ doc blocks. This also moves hoedown to a git submodule rather than a bundled repository. Additionally, hoedown is stricter about code blocks, so this ended up fixing a lot of invalid code blocks (ending with " ```" instead of "```", or ending with "~~~~" instead of "~~~"). Closes #12776 --- .gitmodules | 3 + mk/crates.mk | 4 +- mk/dist.mk | 3 +- mk/rt.mk | 21 +- src/doc/complement-cheatsheet.md | 4 +- src/doc/complement-lang-faq.md | 2 +- src/doc/guide-container.md | 2 +- src/doc/guide-tasks.md | 4 +- src/doc/rust.md | 2 +- src/doc/rustdoc.md | 79 +- src/doc/tutorial.md | 2 +- src/libfourcc/lib.rs | 2 +- src/libhexfloat/lib.rs | 2 +- src/librustdoc/html/markdown.rs | 218 +- src/libstd/c_str.rs | 2 +- src/libstd/iter.rs | 2 +- src/libstd/local_data.rs | 2 +- src/libstd/slice.rs | 8 +- src/libstd/str.rs | 2 +- src/libuuid/lib.rs | 2 +- src/rt/hoedown | 1 + src/rt/sundown/.gitignore | 5 - src/rt/sundown/CONTRIBUTING.md | 10 - src/rt/sundown/Makefile | 83 - src/rt/sundown/Makefile.win | 33 - src/rt/sundown/README.markdown | 131 -- src/rt/sundown/examples/smartypants.c | 72 - src/rt/sundown/examples/sundown.c | 80 - src/rt/sundown/html/houdini.h | 37 - src/rt/sundown/html/houdini_href_e.c | 108 - src/rt/sundown/html/houdini_html_e.c | 84 - src/rt/sundown/html/html.c | 635 ------ src/rt/sundown/html/html.h | 77 - src/rt/sundown/html/html_smartypants.c | 389 ---- src/rt/sundown/html_block_names.txt | 25 - src/rt/sundown/src/autolink.c | 297 --- src/rt/sundown/src/autolink.h | 51 - src/rt/sundown/src/buffer.c | 225 --- src/rt/sundown/src/buffer.h | 96 - src/rt/sundown/src/html_blocks.h | 206 -- src/rt/sundown/src/markdown.c | 2556 ------------------------ src/rt/sundown/src/markdown.h | 138 -- src/rt/sundown/src/stack.c | 81 - src/rt/sundown/src/stack.h | 29 - 44 files changed, 185 insertions(+), 5630 deletions(-) create mode 160000 src/rt/hoedown delete mode 100644 src/rt/sundown/.gitignore delete mode 100644 src/rt/sundown/CONTRIBUTING.md delete mode 100644 src/rt/sundown/Makefile delete mode 100644 src/rt/sundown/Makefile.win delete mode 100644 src/rt/sundown/README.markdown delete mode 100644 src/rt/sundown/examples/smartypants.c delete mode 100644 src/rt/sundown/examples/sundown.c delete mode 100644 src/rt/sundown/html/houdini.h delete mode 100644 src/rt/sundown/html/houdini_href_e.c delete mode 100644 src/rt/sundown/html/houdini_html_e.c delete mode 100644 src/rt/sundown/html/html.c delete mode 100644 src/rt/sundown/html/html.h delete mode 100644 src/rt/sundown/html/html_smartypants.c delete mode 100644 src/rt/sundown/html_block_names.txt delete mode 100644 src/rt/sundown/src/autolink.c delete mode 100644 src/rt/sundown/src/autolink.h delete mode 100644 src/rt/sundown/src/buffer.c delete mode 100644 src/rt/sundown/src/buffer.h delete mode 100644 src/rt/sundown/src/html_blocks.h delete mode 100644 src/rt/sundown/src/markdown.c delete mode 100644 src/rt/sundown/src/markdown.h delete mode 100644 src/rt/sundown/src/stack.c delete mode 100644 src/rt/sundown/src/stack.h diff --git a/.gitmodules b/.gitmodules index 597086229b8..f9da507b72a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,3 +12,6 @@ [submodule "src/compiler-rt"] path = src/compiler-rt url = https://github.com/rust-lang/compiler-rt.git +[submodule "src/rt/hoedown"] + path = src/rt/hoedown + url = https://github.com/rust-lang/hoedown.git diff --git a/mk/crates.mk b/mk/crates.mk index fc0afa6df62..e91955a1ee1 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -38,7 +38,7 @@ # DEPS_ # These lists are the dependencies of the that is to be built. # Rust dependencies are listed bare (i.e. std, green) and native -# dependencies have a "native:" prefix (i.e. native:sundown). All deps +# dependencies have a "native:" prefix (i.e. native:hoedown). All deps # will be built before the crate itself is built. # # TOOL_DEPS_/TOOL_SOURCE_ @@ -63,7 +63,7 @@ DEPS_native := std DEPS_syntax := std term serialize collections log DEPS_rustc := syntax native:rustllvm flate arena serialize sync getopts \ collections time log -DEPS_rustdoc := rustc native:sundown serialize sync getopts collections \ +DEPS_rustdoc := rustc native:hoedown serialize sync getopts collections \ test time DEPS_flate := std native:miniz DEPS_arena := std collections diff --git a/mk/dist.mk b/mk/dist.mk index b14c6f279ef..6dc44a422cf 100644 --- a/mk/dist.mk +++ b/mk/dist.mk @@ -35,7 +35,8 @@ LICENSE.txt: $(S)COPYRIGHT $(S)LICENSE-APACHE $(S)LICENSE-MIT PKG_TAR = dist/$(PKG_NAME).tar.gz -PKG_GITMODULES := $(S)src/libuv $(S)src/llvm $(S)src/gyp $(S)src/compiler-rt +PKG_GITMODULES := $(S)src/libuv $(S)src/llvm $(S)src/gyp $(S)src/compiler-rt \ + $(S)src/rt/hoedown PKG_FILES := \ $(S)COPYRIGHT \ $(S)LICENSE-APACHE \ diff --git a/mk/rt.mk b/mk/rt.mk index d0fc5774589..df47f4a12d9 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -35,19 +35,20 @@ # that's per-target so you're allowed to conditionally add files based on the # target. ################################################################################ -NATIVE_LIBS := rustrt sundown uv_support morestack miniz context_switch +NATIVE_LIBS := rustrt hoedown uv_support morestack miniz context_switch # $(1) is the target triple define NATIVE_LIBRARIES -NATIVE_DEPS_sundown_$(1) := sundown/src/autolink.c \ - sundown/src/buffer.c \ - sundown/src/stack.c \ - sundown/src/markdown.c \ - sundown/html/houdini_href_e.c \ - sundown/html/houdini_html_e.c \ - sundown/html/html_smartypants.c \ - sundown/html/html.c +NATIVE_DEPS_hoedown_$(1) := hoedown/src/autolink.c \ + hoedown/src/buffer.c \ + hoedown/src/document.c \ + hoedown/src/escape.c \ + hoedown/src/html.c \ + hoedown/src/html_blocks.c \ + hoedown/src/html_smartypants.c \ + hoedown/src/stack.c \ + hoedown/src/version.c NATIVE_DEPS_uv_support_$(1) := rust_uv.c NATIVE_DEPS_miniz_$(1) = miniz.c NATIVE_DEPS_rustrt_$(1) := rust_builtin.c \ @@ -79,7 +80,7 @@ $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS) @mkdir -p $$(@D) @$$(call E, compile: $$@) $$(Q)$$(call CFG_COMPILE_C_$(1), $$@, \ - -I $$(S)src/rt/sundown/src -I $$(S)src/rt/sundown/html \ + -I $$(S)src/rt/hoedown/src \ -I $$(S)src/libuv/include -I $$(S)src/rt \ $$(RUNTIME_CFLAGS_$(1))) $$< diff --git a/src/doc/complement-cheatsheet.md b/src/doc/complement-cheatsheet.md index 84a000fce57..804d878398b 100644 --- a/src/doc/complement-cheatsheet.md +++ b/src/doc/complement-cheatsheet.md @@ -62,7 +62,7 @@ use std::str; let x: Option<~str> = str::from_utf8_owned(~[104u8,105u8]); let y: ~str = x.unwrap(); -~~~~ +~~~ To return a [`MaybeOwned`](http://static.rust-lang.org/doc/master/std/str/enum.MaybeOwned.html) use the str helper function [`from_utf8_lossy`](http://static.rust-lang.org/doc/master/std/str/fn.from_utf8_owned.html). This function also replaces non-valid utf-8 sequences with U+FFFD replacement character. @@ -71,7 +71,7 @@ use std::str; let x = bytes!(72u8,"ello ",0xF0,0x90,0x80,"World!"); let y = str::from_utf8_lossy(x); -~~~~ +~~~ # File operations diff --git a/src/doc/complement-lang-faq.md b/src/doc/complement-lang-faq.md index 8bb99e80282..a357f9ef195 100644 --- a/src/doc/complement-lang-faq.md +++ b/src/doc/complement-lang-faq.md @@ -135,7 +135,7 @@ For simplicity, we do not plan to do so. Implementing automatic semicolon insert **Short answer** set the RUST_LOG environment variable to the name of your source file, sans extension. -``` {.sh .notrust} +```notrust,sh rustc hello.rs export RUST_LOG=hello ./hello diff --git a/src/doc/guide-container.md b/src/doc/guide-container.md index 4fb75111f3b..6a54dc7ea18 100644 --- a/src/doc/guide-container.md +++ b/src/doc/guide-container.md @@ -81,7 +81,7 @@ impl Iterator for ZeroStream { Some(0) } } -~~~~ +~~~ Reaching the end of the iterator is signalled by returning `None` instead of `Some(item)`: diff --git a/src/doc/guide-tasks.md b/src/doc/guide-tasks.md index e6eb4f235e5..7bf2adfde76 100644 --- a/src/doc/guide-tasks.md +++ b/src/doc/guide-tasks.md @@ -496,7 +496,7 @@ fn stringifier(channel: &sync::DuplexStream<~str, uint>) { } } # } -~~~~ +~~~ The implementation of `DuplexStream` supports both sending and receiving. The `stringifier` function takes a `DuplexStream` that can @@ -538,7 +538,7 @@ assert!(from_child.recv() == "23".to_owned()); assert!(from_child.recv() == "0".to_owned()); # } -~~~~ +~~~ The parent task first calls `DuplexStream` to create a pair of bidirectional endpoints. It then uses `task::spawn` to create the child task, which captures diff --git a/src/doc/rust.md b/src/doc/rust.md index 12d2911f529..99b3d516af5 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -4085,7 +4085,7 @@ fn main() { These four log levels correspond to levels 1-4, as controlled by `RUST_LOG`: -``` {.bash .notrust} +```notrust,bash $ RUST_LOG=rust=3 ./rust This is an error log This is a warn log diff --git a/src/doc/rustdoc.md b/src/doc/rustdoc.md index 2170e16f932..06ee875f6d6 100644 --- a/src/doc/rustdoc.md +++ b/src/doc/rustdoc.md @@ -107,44 +107,35 @@ code blocks as testable-by-default. In order to not run a test over a block of code, the `ignore` string can be added to the three-backtick form of markdown code block. - /** - # nested code fences confuse sundown => indentation + comment to - # avoid failing tests - ``` - // This is a testable code block - ``` +~~~notrust +``` +// This is a testable code block +``` - ```ignore - // This is not a testable code block - ``` +```ignore +// This is not a testable code block +``` - // This is a testable code block (4-space indent) - */ - # fn foo() {} + // This is a testable code block (4-space indent) +~~~ You can specify that the test's execution should fail with the `should_fail` directive. - /** - # nested code fences confuse sundown => indentation + comment to - # avoid failing tests - ```should_fail - // This code block is expected to generate a failure when run - ``` - */ - # fn foo() {} +~~~notrust +```should_fail +// This code block is expected to generate a failure when run +``` +~~~ You can specify that the code block should be compiled but not run with the `no_run` directive. - /** - # nested code fences confuse sundown => indentation + comment to - # avoid failing tests - ```no_run - // This code will be compiled but not executed - ``` - */ - # fn foo() {} +~~~notrust +```no_run +// This code will be compiled but not executed +``` +~~~ Rustdoc also supplies some extra sugar for helping with some tedious documentation examples. If a line is prefixed with `# `, then the line @@ -152,23 +143,19 @@ will not show up in the HTML documentation, but it will be used when testing the code block (NB. the space after the `#` is required, so that one can still write things like `#[deriving(Eq)]`). - /** - # nested code fences confuse sundown => indentation + comment to - # avoid failing tests - ```rust - # /!\ The three following lines are comments, which are usually stripped off by - # the doc-generating tool. In order to display them anyway in this particular - # case, the character following the leading '#' is not a usual space like in - # these first five lines but a non breakable one. - # - # // showing 'fib' in this documentation would just be tedious and detracts from - # // what's actually being documented. - # fn fib(n: int) { n + 2 } +~~~notrust +``` +# /!\ The three following lines are comments, which are usually stripped off by +# the doc-generating tool. In order to display them anyway in this particular +# case, the character following the leading '#' is not a usual space like in +# these first five lines but a non breakable one. +# // showing 'fib' in this documentation would just be tedious and detracts from +# // what's actually being documented. +# fn fib(n: int) { n + 2 } - spawn(proc() { fib(200); }) - ``` - */ - # fn foo() {} +spawn(proc() { fib(200); }) +``` +~~~ The documentation online would look like `spawn(proc() { fib(200); })`, but when testing this code, the `fib` function will be included (so it can compile). @@ -182,10 +169,10 @@ rustc's `--test` flag. Extra arguments can be passed to rustdoc's test harness with the `--test-args` flag. ~~~ {.notrust} -$ # Only run tests containing 'foo' in their name +# Only run tests containing 'foo' in their name $ rustdoc --test lib.rs --test-args 'foo' -$ # See what's possible when running tests +# See what's possible when running tests $ rustdoc --test lib.rs --test-args '--help' ~~~ diff --git a/src/doc/tutorial.md b/src/doc/tutorial.md index abb713f5e72..74f3cdd9aa4 100644 --- a/src/doc/tutorial.md +++ b/src/doc/tutorial.md @@ -1408,7 +1408,7 @@ struct Point { x: f64, y: f64 } -~~~~ +~~~ We can use this simple definition to allocate points in many different ways. For example, in this code, each of these local variables diff --git a/src/libfourcc/lib.rs b/src/libfourcc/lib.rs index fe0b6bcfd0f..04fa139168f 100644 --- a/src/libfourcc/lib.rs +++ b/src/libfourcc/lib.rs @@ -31,7 +31,7 @@ fn main() { let little_val = fourcc!("foo ", little); assert_eq!(little_val, 0x21EEFFC0u32); } - ``` +``` # References diff --git a/src/libhexfloat/lib.rs b/src/libhexfloat/lib.rs index 72528e96917..100bec23775 100644 --- a/src/libhexfloat/lib.rs +++ b/src/libhexfloat/lib.rs @@ -27,7 +27,7 @@ extern crate hexfloat; fn main() { let val = hexfloat!("0x1.ffffb4", f32); } - ``` +``` # References diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index fab3ca80099..432f089cf42 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -10,7 +10,7 @@ //! Markdown formatting for rustdoc //! -//! This module implements markdown formatting through the sundown C-library +//! This module implements markdown formatting through the hoedown C-library //! (bundled into the rust runtime). This module self-contains the C bindings //! and necessary legwork to render markdown, and exposes all of the //! functionality through a unit-struct, `Markdown`, which has an implementation @@ -27,11 +27,9 @@ #![allow(non_camel_case_types)] use libc; -use std::cast; use std::fmt; use std::io; use std::local_data; -use std::mem; use std::str; use std::slice; use collections::HashMap; @@ -47,67 +45,76 @@ pub struct Markdown<'a>(pub &'a str); /// table of contents. pub struct MarkdownWithToc<'a>(pub &'a str); -static OUTPUT_UNIT: libc::size_t = 64; -static MKDEXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 0; -static MKDEXT_TABLES: libc::c_uint = 1 << 1; -static MKDEXT_FENCED_CODE: libc::c_uint = 1 << 2; -static MKDEXT_AUTOLINK: libc::c_uint = 1 << 3; -static MKDEXT_STRIKETHROUGH: libc::c_uint = 1 << 4; +static DEF_OUNIT: libc::size_t = 64; +static HOEDOWN_EXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 10; +static HOEDOWN_EXT_TABLES: libc::c_uint = 1 << 0; +static HOEDOWN_EXT_FENCED_CODE: libc::c_uint = 1 << 1; +static HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3; +static HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4; -type sd_markdown = libc::c_void; // this is opaque to us +type hoedown_document = libc::c_void; // this is opaque to us -struct sd_callbacks { - blockcode: Option, - blockquote: Option, - blockhtml: Option, - header: Option, - other: [libc::size_t, ..22], +struct hoedown_renderer { + opaque: *mut hoedown_html_renderer_state, + blockcode: Option, + blockquote: Option, + blockhtml: Option, + header: Option, + other: [libc::size_t, ..28], +} + +struct hoedown_html_renderer_state { + opaque: *mut libc::c_void, + toc_data: html_toc_data, + flags: libc::c_uint, + link_attributes: Option, } struct html_toc_data { header_count: libc::c_int, current_level: libc::c_int, level_offset: libc::c_int, + nesting_level: libc::c_int, } -struct html_renderopt { - toc_data: html_toc_data, - flags: libc::c_uint, - link_attributes: Option, -} - -struct my_opaque { - opt: html_renderopt, - dfltblk: extern "C" fn(*buf, *buf, *buf, *libc::c_void), +struct MyOpaque { + dfltblk: extern "C" fn(*mut hoedown_buffer, *hoedown_buffer, + *hoedown_buffer, *mut libc::c_void), toc_builder: Option, } -struct buf { +struct hoedown_buffer { data: *u8, size: libc::size_t, asize: libc::size_t, unit: libc::size_t, } -// sundown FFI -#[link(name = "sundown", kind = "static")] +// hoedown FFI +#[link(name = "hoedown", kind = "static")] extern { - fn sdhtml_renderer(callbacks: *sd_callbacks, - options_ptr: *html_renderopt, - render_flags: libc::c_uint); - fn sd_markdown_new(extensions: libc::c_uint, - max_nesting: libc::size_t, - callbacks: *sd_callbacks, - opaque: *libc::c_void) -> *sd_markdown; - fn sd_markdown_render(ob: *buf, - document: *u8, - doc_size: libc::size_t, - md: *sd_markdown); - fn sd_markdown_free(md: *sd_markdown); + fn hoedown_html_renderer_new(render_flags: libc::c_uint, + nesting_level: libc::c_int) + -> *mut hoedown_renderer; + fn hoedown_html_renderer_free(renderer: *mut hoedown_renderer); - fn bufnew(unit: libc::size_t) -> *buf; - fn bufputs(b: *buf, c: *libc::c_char); - fn bufrelease(b: *buf); + fn hoedown_document_new(rndr: *mut hoedown_renderer, + extensions: libc::c_uint, + max_nesting: libc::size_t) -> *mut hoedown_document; + fn hoedown_document_render(doc: *mut hoedown_document, + ob: *mut hoedown_buffer, + document: *u8, + doc_size: libc::size_t); + fn hoedown_document_free(md: *mut hoedown_document); + + fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer; + fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *libc::c_char); + fn hoedown_buffer_free(b: *mut hoedown_buffer); } @@ -127,15 +134,19 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { local_data_key!(used_header_map: HashMap<~str, uint>) pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result { - extern fn block(ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) { + extern fn block(ob: *mut hoedown_buffer, text: *hoedown_buffer, + lang: *hoedown_buffer, opaque: *mut libc::c_void) { unsafe { - let my_opaque: &my_opaque = cast::transmute(opaque); + let opaque = opaque as *mut hoedown_html_renderer_state; + let my_opaque: &MyOpaque = &*((*opaque).opaque as *MyOpaque); slice::raw::buf_as_slice((*text).data, (*text).size as uint, |text| { let text = str::from_utf8(text).unwrap(); - let mut lines = text.lines().filter(|l| stripped_filtered_line(*l).is_none()); + let mut lines = text.lines().filter(|l| { + stripped_filtered_line(*l).is_none() + }); let text = lines.collect::>().connect("\n"); - let buf = buf { + let buf = hoedown_buffer { data: text.as_bytes().as_ptr(), size: text.len() as libc::size_t, asize: text.len() as libc::size_t, @@ -148,7 +159,8 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result { (*lang).size as uint, |rlang| { let rlang = str::from_utf8(rlang).unwrap(); if rlang.contains("notrust") { - (my_opaque.dfltblk)(ob, &buf, lang, opaque); + (my_opaque.dfltblk)(ob, &buf, lang, + opaque as *mut libc::c_void); true } else { false @@ -159,17 +171,17 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result { if !rendered { let output = highlight::highlight(text, None).to_c_str(); output.with_ref(|r| { - bufputs(ob, r) + hoedown_buffer_puts(ob, r) }) } }) } } - extern fn header(ob: *buf, text: *buf, level: libc::c_int, - opaque: *libc::c_void) { - // sundown does this, we may as well too - "\n".with_c_str(|p| unsafe { bufputs(ob, p) }); + extern fn header(ob: *mut hoedown_buffer, text: *hoedown_buffer, + level: libc::c_int, opaque: *mut libc::c_void) { + // hoedown does this, we may as well too + "\n".with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) }); // Extract the text provided let s = if text.is_null() { @@ -188,7 +200,12 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result { } }).collect::>().connect("-"); - let opaque = unsafe {&mut *(opaque as *mut my_opaque)}; + // This is a terrible hack working around how hoedown gives us rendered + // html for text rather than the raw text. + let id = id.replace("", "").replace("", ""); + + let opaque = opaque as *mut hoedown_html_renderer_state; + let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) }; // Make sure our hyphenated ID is unique for this page let id = local_data::get_mut(used_header_map, |map| { @@ -214,40 +231,29 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result { s, lvl = level, id = id, sec_len = sec.len(), sec = sec); - text.with_c_str(|p| unsafe { bufputs(ob, p) }); + text.with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) }); } - // This code is all lifted from examples/sundown.c in the sundown repo unsafe { - let ob = bufnew(OUTPUT_UNIT); - let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES | - MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK | - MKDEXT_STRIKETHROUGH; - let options = html_renderopt { - toc_data: html_toc_data { - header_count: 0, - current_level: 0, - level_offset: 0, - }, - flags: 0, - link_attributes: None, - }; - let mut callbacks: sd_callbacks = mem::init(); - - sdhtml_renderer(&callbacks, &options, 0); - let mut opaque = my_opaque { - opt: options, - dfltblk: callbacks.blockcode.unwrap(), + let ob = hoedown_buffer_new(DEF_OUNIT); + let extensions = HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES | + HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK | + HOEDOWN_EXT_STRIKETHROUGH; + let renderer = hoedown_html_renderer_new(0, 0); + let mut opaque = MyOpaque { + dfltblk: (*renderer).blockcode.unwrap(), toc_builder: if print_toc {Some(TocBuilder::new())} else {None} }; - callbacks.blockcode = Some(block); - callbacks.header = Some(header); - let markdown = sd_markdown_new(extensions, 16, &callbacks, - &mut opaque as *mut my_opaque as *libc::c_void); + (*(*renderer).opaque).opaque = &mut opaque as *mut _ as *mut libc::c_void; + (*renderer).blockcode = Some(block); + (*renderer).header = Some(header); + let document = hoedown_document_new(renderer, extensions, 16); + hoedown_document_render(document, ob, s.as_ptr(), + s.len() as libc::size_t); + hoedown_document_free(document); - sd_markdown_render(ob, s.as_ptr(), s.len() as libc::size_t, markdown); - sd_markdown_free(markdown); + hoedown_html_renderer_free(renderer); let mut ret = match opaque.toc_builder { Some(b) => write!(w, "", b.into_toc()), @@ -259,13 +265,14 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result { w.write(buf) }); } - bufrelease(ob); + hoedown_buffer_free(ob); ret } } pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { - extern fn block(_ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) { + extern fn block(_ob: *mut hoedown_buffer, text: *hoedown_buffer, + lang: *hoedown_buffer, opaque: *mut libc::c_void) { unsafe { if text.is_null() { return } let (should_fail, no_run, ignore, notrust) = if lang.is_null() { @@ -282,17 +289,23 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { }; if notrust { return } slice::raw::buf_as_slice((*text).data, (*text).size as uint, |text| { - let tests = &mut *(opaque as *mut ::test::Collector); + let opaque = opaque as *mut hoedown_html_renderer_state; + let tests = &mut *((*opaque).opaque as *mut ::test::Collector); let text = str::from_utf8(text).unwrap(); - let mut lines = text.lines().map(|l| stripped_filtered_line(l).unwrap_or(l)); + let mut lines = text.lines().map(|l| { + stripped_filtered_line(l).unwrap_or(l) + }); let text = lines.collect::>().connect("\n"); tests.add_test(text, should_fail, no_run, ignore); }) } } - extern fn header(_ob: *buf, text: *buf, level: libc::c_int, opaque: *libc::c_void) { + + extern fn header(_ob: *mut hoedown_buffer, text: *hoedown_buffer, + level: libc::c_int, opaque: *mut libc::c_void) { unsafe { - let tests = &mut *(opaque as *mut ::test::Collector); + let opaque = opaque as *mut hoedown_html_renderer_state; + let tests = &mut *((*opaque).opaque as *mut ::test::Collector); if text.is_null() { tests.register_header("", level as u32); } else { @@ -305,25 +318,22 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { } unsafe { - let ob = bufnew(OUTPUT_UNIT); - let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES | - MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK | - MKDEXT_STRIKETHROUGH; - let callbacks = sd_callbacks { - blockcode: Some(block), - blockquote: None, - blockhtml: None, - header: Some(header), - other: mem::init() - }; + let ob = hoedown_buffer_new(DEF_OUNIT); + let extensions = HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES | + HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK | + HOEDOWN_EXT_STRIKETHROUGH; + let renderer = hoedown_html_renderer_new(0, 0); + (*renderer).blockcode = Some(block); + (*renderer).header = Some(header); + (*(*renderer).opaque).opaque = tests as *mut _ as *mut libc::c_void; - let tests = tests as *mut ::test::Collector as *libc::c_void; - let markdown = sd_markdown_new(extensions, 16, &callbacks, tests); + let document = hoedown_document_new(renderer, extensions, 16); + hoedown_document_render(document, ob, doc.as_ptr(), + doc.len() as libc::size_t); + hoedown_document_free(document); - sd_markdown_render(ob, doc.as_ptr(), doc.len() as libc::size_t, - markdown); - sd_markdown_free(markdown); - bufrelease(ob); + hoedown_html_renderer_free(renderer); + hoedown_buffer_free(ob); } } diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs index 310bc861cd3..7de74dbe507 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -61,7 +61,7 @@ fn main() { unsafe { puts(c_buffer); } }); } - ``` +``` */ diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs index 18532c39443..62088e5b646 100644 --- a/src/libstd/iter.rs +++ b/src/libstd/iter.rs @@ -52,7 +52,7 @@ loop { None => { break } } } - ``` +``` This `for` loop syntax can be applied to any iterator over any type. diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs index a6199aa43ab..072884a1f74 100644 --- a/src/libstd/local_data.rs +++ b/src/libstd/local_data.rs @@ -33,7 +33,7 @@ local_data::get(key_int, |opt| assert_eq!(opt.map(|x| *x), Some(3))); local_data::set(key_vector, ~[4]); local_data::get(key_vector, |opt| assert_eq!(*opt.unwrap(), ~[4])); - ``` +``` */ diff --git a/src/libstd/slice.rs b/src/libstd/slice.rs index 64f6b59be24..43159bcb44a 100644 --- a/src/libstd/slice.rs +++ b/src/libstd/slice.rs @@ -19,7 +19,7 @@ homogeneous types: ```rust let int_vector = [1,2,3]; let str_vector = ["one", "two", "three"]; - ``` +``` This is a big module, but for a high-level overview: @@ -44,7 +44,7 @@ a vector or a vector slice from the index interval `[a, b)`: let numbers = [0, 1, 2]; let last_numbers = numbers.slice(1, 3); // last_numbers is now &[1, 2] - ``` +``` Traits defined for the `~[T]` type, like `OwnedVector`, can only be called on such vectors. These methods deal with adding elements or otherwise changing @@ -57,7 +57,7 @@ of the vector: let mut numbers = vec![0, 1, 2]; numbers.push(7); // numbers is now vec![0, 1, 2, 7]; - ``` +``` ## Implementations of other traits @@ -79,7 +79,7 @@ let numbers = [0, 1, 2]; for &x in numbers.iter() { println!("{} is a number!", x); } - ``` +``` * `.mut_iter()` returns an iterator that allows modifying each value. * `.move_iter()` converts an owned vector into an iterator that diff --git a/src/libstd/str.rs b/src/libstd/str.rs index b105dd0ca5a..adb0c299876 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -37,7 +37,7 @@ fn main() { let borrowed_string1 = "This string is borrowed with the 'static lifetime"; let borrowed_string2: &str = owned_string; // owned strings can be borrowed } - ``` +``` From the example above, you can see that Rust has 2 different kinds of string literals. The owned literals correspond to the owned string types, but the diff --git a/src/libuuid/lib.rs b/src/libuuid/lib.rs index 2ee096dad42..eef7cc67934 100644 --- a/src/libuuid/lib.rs +++ b/src/libuuid/lib.rs @@ -35,7 +35,7 @@ fn main() { let uuid1 = Uuid::new_v4(); println!("{}", uuid1.to_str()); } - ``` +``` # Strings diff --git a/src/rt/hoedown b/src/rt/hoedown new file mode 160000 index 00000000000..238c4d57cce --- /dev/null +++ b/src/rt/hoedown @@ -0,0 +1 @@ +Subproject commit 238c4d57cce10d33b05cf52a91fc62a09f31ffbb diff --git a/src/rt/sundown/.gitignore b/src/rt/sundown/.gitignore deleted file mode 100644 index 4415b791735..00000000000 --- a/src/rt/sundown/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.o -libsundown.so* -sundown -smartypants -*.exe diff --git a/src/rt/sundown/CONTRIBUTING.md b/src/rt/sundown/CONTRIBUTING.md deleted file mode 100644 index bf1ac1e585a..00000000000 --- a/src/rt/sundown/CONTRIBUTING.md +++ /dev/null @@ -1,10 +0,0 @@ -Contributing to Sundown -======================= - -Do not. - -Unfortunately, Sundown is currently frozen as we're working with the Reddit, StackOverflow and Meteor developers to design a formal Markdown standard and parser that will supersede Sundown in all these websites (and in GitHub, of course). Our goal is to deprecate Sundown altogether before the end of the year. - -The new parser will be smaller, faster, safer and most importantly, more consistent. - -Please stay tuned. diff --git a/src/rt/sundown/Makefile b/src/rt/sundown/Makefile deleted file mode 100644 index b8b198cb992..00000000000 --- a/src/rt/sundown/Makefile +++ /dev/null @@ -1,83 +0,0 @@ -# Makefile - -# Copyright (c) 2009, Natacha Porté -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -DEPDIR=depends - -# "Machine-dependent" options -#MFLAGS=-fPIC - -CFLAGS=-c -g -O3 -fPIC -Wall -Werror -Wsign-compare -Isrc -Ihtml -LDFLAGS=-g -O3 -Wall -Werror -CC=gcc - - -SUNDOWN_SRC=\ - src/markdown.o \ - src/stack.o \ - src/buffer.o \ - src/autolink.o \ - html/html.o \ - html/html_smartypants.o \ - html/houdini_html_e.o \ - html/houdini_href_e.o - -all: libsundown.so sundown smartypants html_blocks - -.PHONY: all clean - -# libraries - -libsundown.so: libsundown.so.1 - ln -f -s $^ $@ - -libsundown.so.1: $(SUNDOWN_SRC) - $(CC) $(LDFLAGS) -shared -Wl $^ -o $@ - -# executables - -sundown: examples/sundown.o $(SUNDOWN_SRC) - $(CC) $(LDFLAGS) $^ -o $@ - -smartypants: examples/smartypants.o $(SUNDOWN_SRC) - $(CC) $(LDFLAGS) $^ -o $@ - -# perfect hashing -html_blocks: src/html_blocks.h - -src/html_blocks.h: html_block_names.txt - gperf -N find_block_tag -H hash_block_tag -C -c -E --ignore-case $^ > $@ - - -# housekeeping -clean: - rm -f src/*.o html/*.o examples/*.o - rm -f libsundown.so libsundown.so.1 sundown smartypants - rm -f sundown.exe smartypants.exe - rm -rf $(DEPDIR) - - -# dependencies - -include $(wildcard $(DEPDIR)/*.d) - - -# generic object compilations - -%.o: src/%.c examples/%.c html/%.c - @mkdir -p $(DEPDIR) - @$(CC) -MM $< > $(DEPDIR)/$*.d - $(CC) $(CFLAGS) -o $@ $< - diff --git a/src/rt/sundown/Makefile.win b/src/rt/sundown/Makefile.win deleted file mode 100644 index ea668b2cdc1..00000000000 --- a/src/rt/sundown/Makefile.win +++ /dev/null @@ -1,33 +0,0 @@ - -CFLAGS=/O2 /EHsc /I"src/" /I"examples"/ /I"html"/ -CC=cl - -SUNDOWN_SRC=\ - src\markdown.obj \ - src\stack.obj \ - src\buffer.obj \ - src\autolink.obj \ - html\html.obj \ - html\html_smartypants.obj \ - html\houdini_html_e.obj \ - html\houdini_href_e.obj - -all: sundown.dll sundown.exe - -sundown.dll: $(SUNDOWN_SRC) sundown.def - $(CC) $(SUNDOWN_SRC) sundown.def /link /DLL $(LDFLAGS) /out:$@ - -sundown.exe: examples\sundown.obj $(SUNDOWN_SRC) - $(CC) examples\sundown.obj $(SUNDOWN_SRC) /link $(LDFLAGS) /out:$@ - -# housekeeping -clean: - del $(SUNDOWN_SRC) - del sundown.dll sundown.exe - del sundown.exp sundown.lib - -# generic object compilations - -.c.obj: - $(CC) $(CFLAGS) /c $< /Fo$@ - diff --git a/src/rt/sundown/README.markdown b/src/rt/sundown/README.markdown deleted file mode 100644 index 61736025ca9..00000000000 --- a/src/rt/sundown/README.markdown +++ /dev/null @@ -1,131 +0,0 @@ -Sundown -======= - -`Sundown` is a Markdown parser based on the original code of the -[Upskirt library](http://fossil.instinctive.eu/libupskirt/index) by Natacha Porté. - -Features --------- - -* **Fully standards compliant** - - `Sundown` passes out of the box the official Markdown v1.0.0 and v1.0.3 - test suites, and has been extensively tested with additional corner cases - to make sure its output is as sane as possible at all times. - -* **Massive extension support** - - `Sundown` has optional support for several (unofficial) Markdown extensions, - such as non-strict emphasis, fenced code blocks, tables, autolinks, - strikethrough and more. - -* **UTF-8 aware** - - `Sundown` is fully UTF-8 aware, both when parsing the source document and when - generating the resulting (X)HTML code. - -* **Tested & Ready to be used on production** - - `Sundown` has been extensively security audited, and includes protection against - all possible DOS attacks (stack overflows, out of memory situations, malformed - Markdown syntax...) and against client attacks through malicious embedded HTML. - - We've worked very hard to make `Sundown` never crash or run out of memory - under *any* input. `Sundown` renders all the Markdown content in GitHub and so - far hasn't crashed a single time. - -* **Customizable renderers** - - `Sundown` is not stuck with XHTML output: the Markdown parser of the library - is decoupled from the renderer, so it's trivial to extend the library with - custom renderers. A fully functional (X)HTML renderer is included. - -* **Optimized for speed** - - `Sundown` is written in C, with a special emphasis on performance. When wrapped - on a dynamic language such as Python or Ruby, it has shown to be up to 40 - times faster than other native alternatives. - -* **Zero-dependency** - - `Sundown` is a zero-dependency library composed of 3 `.c` files and their headers. - No dependencies, no bullshit. Only standard C99 that builds everywhere. - -Credits -------- - -`Sundown` is based on the original Upskirt parser by Natacha Porté, with many additions -by Vicent Marti (@vmg) and contributions from the following authors: - - Ben Noordhuis, Bruno Michel, Joseph Koshy, Krzysztof Kowalczyk, Samuel Bronson, - Shuhei Tanuma - -Bindings --------- - -`Sundown` is available from other programming languages thanks to these bindings developed -by our awesome contributors. - -- [Redcarpet](https://github.com/vmg/redcarpet) (Ruby) -- [RobotSkirt](https://github.com/benmills/robotskirt) (Node.js) -- [Misaka](https://github.com/FSX/misaka) (Python) -- [ffi-sundown](https://github.com/postmodern/ffi-sundown) (Ruby FFI) -- [Sundown HS](https://github.com/bitonic/sundown) (Haskell) -- [Goskirt](https://github.com/madari/goskirt) (Go) -- [Upskirt.go](https://github.com/buu700/upskirt.go) (Go) -- [MoonShine](https://github.com/brandonc/moonshine) (.NET) -- [PHP-Sundown](https://github.com/chobie/php-sundown) (PHP) -- [Sundown.net](https://github.com/txdv/sundown.net) (.NET) - -Help us -------- - -`Sundown` is all about security. If you find a (potential) security vulnerability in the -library, or a way to make it crash through malicious input, please report it to us, -either directly via email or by opening an Issue on GitHub, and help make the web safer -for everybody. - -Unicode character handling --------------------------- - -Given that the Markdown spec makes no provision for Unicode character handling, `Sundown` -takes a conservative approach towards deciding which extended characters trigger Markdown -features: - -* Punctuation characters outside of the U+007F codepoint are not handled as punctuation. - They are considered as normal, in-word characters for word-boundary checks. - -* Whitespace characters outside of the U+007F codepoint are not considered as - whitespace. They are considered as normal, in-word characters for word-boundary checks. - -Install -------- - -There is nothing to install. `Sundown` is composed of 3 `.c` files (`markdown.c`, -`buffer.c` and `array.c`), so just throw them in your project. Zero-dependency means -zero-dependency. You might want to include `render/html.c` if you want to use the -included XHTML renderer, or write your own renderer. Either way, it's all fun and joy. - -If you are hardcore, you can use the included `Makefile` to build `Sundown` into a dynamic -library, or to build the sample `sundown` executable, which is just a commandline -Markdown to XHTML parser. (If gcc gives you grief about `-fPIC`, e.g. with MinGW, try -`make MFLAGS=` instead of just `make`.) - -License -------- - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - - - diff --git a/src/rt/sundown/examples/smartypants.c b/src/rt/sundown/examples/smartypants.c deleted file mode 100644 index 4840703bb12..00000000000 --- a/src/rt/sundown/examples/smartypants.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2011, Vicent Marti - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "markdown.h" -#include "html.h" -#include "buffer.h" - -#include -#include -#include -#include -#include - -#define READ_UNIT 1024 -#define OUTPUT_UNIT 64 - -int -main(int argc, char **argv) -{ - struct buf *ib, *ob; - size_t ret; - FILE *in = stdin; - - /* opening the file if given from the command line */ - if (argc > 1) { - in = fopen(argv[1], "r"); - if (!in) { - fprintf(stderr, "Unable to open input file \"%s\": %s\n", argv[0], strerror(errno)); - return 1; - } - } - - /* reading everything */ - ib = bufnew(READ_UNIT); - bufgrow(ib, READ_UNIT); - while ((ret = fread(ib->data + ib->size, 1, ib->asize - ib->size, in)) > 0) { - ib->size += ret; - bufgrow(ib, ib->size + READ_UNIT); - } - - if (in != stdin) - fclose(in); - - /* performing markdown parsing */ - ob = bufnew(OUTPUT_UNIT); - - sdhtml_smartypants(ob, ib->data, ib->size); - - /* writing the result to stdout */ - (void)fwrite(ob->data, 1, ob->size, stdout); - - /* cleanup */ - bufrelease(ib); - bufrelease(ob); - - return 0; -} - -/* vim: set filetype=c: */ diff --git a/src/rt/sundown/examples/sundown.c b/src/rt/sundown/examples/sundown.c deleted file mode 100644 index 8a475dcaa3d..00000000000 --- a/src/rt/sundown/examples/sundown.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2011, Vicent Marti - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "markdown.h" -#include "html.h" -#include "buffer.h" - -#include -#include -#include -#include - -#define READ_UNIT 1024 -#define OUTPUT_UNIT 64 - -/* main • main function, interfacing STDIO with the parser */ -int -main(int argc, char **argv) -{ - struct buf *ib, *ob; - int ret; - FILE *in = stdin; - - struct sd_callbacks callbacks; - struct html_renderopt options; - struct sd_markdown *markdown; - - /* opening the file if given from the command line */ - if (argc > 1) { - in = fopen(argv[1], "r"); - if (!in) { - fprintf(stderr,"Unable to open input file \"%s\": %s\n", argv[1], strerror(errno)); - return 1; - } - } - - /* reading everything */ - ib = bufnew(READ_UNIT); - bufgrow(ib, READ_UNIT); - while ((ret = fread(ib->data + ib->size, 1, ib->asize - ib->size, in)) > 0) { - ib->size += ret; - bufgrow(ib, ib->size + READ_UNIT); - } - - if (in != stdin) - fclose(in); - - /* performing markdown parsing */ - ob = bufnew(OUTPUT_UNIT); - - sdhtml_renderer(&callbacks, &options, 0); - markdown = sd_markdown_new(0, 16, &callbacks, &options); - - sd_markdown_render(ob, ib->data, ib->size, markdown); - sd_markdown_free(markdown); - - /* writing the result to stdout */ - ret = fwrite(ob->data, 1, ob->size, stdout); - - /* cleanup */ - bufrelease(ib); - bufrelease(ob); - - return (ret < 0) ? -1 : 0; -} - -/* vim: set filetype=c: */ diff --git a/src/rt/sundown/html/houdini.h b/src/rt/sundown/html/houdini.h deleted file mode 100644 index b4954c02f67..00000000000 --- a/src/rt/sundown/html/houdini.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef HOUDINI_H__ -#define HOUDINI_H__ - -#include "buffer.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef HOUDINI_USE_LOCALE -# define _isxdigit(c) isxdigit(c) -# define _isdigit(c) isdigit(c) -#else -/* - * Helper _isdigit methods -- do not trust the current locale - * */ -# define _isxdigit(c) (strchr("0123456789ABCDEFabcdef", (c)) != NULL) -# define _isdigit(c) ((c) >= '0' && (c) <= '9') -#endif - -extern void houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size); -extern void houdini_escape_html0(struct buf *ob, const uint8_t *src, size_t size, int secure); -extern void houdini_unescape_html(struct buf *ob, const uint8_t *src, size_t size); -extern void houdini_escape_xml(struct buf *ob, const uint8_t *src, size_t size); -extern void houdini_escape_uri(struct buf *ob, const uint8_t *src, size_t size); -extern void houdini_escape_url(struct buf *ob, const uint8_t *src, size_t size); -extern void houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size); -extern void houdini_unescape_uri(struct buf *ob, const uint8_t *src, size_t size); -extern void houdini_unescape_url(struct buf *ob, const uint8_t *src, size_t size); -extern void houdini_escape_js(struct buf *ob, const uint8_t *src, size_t size); -extern void houdini_unescape_js(struct buf *ob, const uint8_t *src, size_t size); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/rt/sundown/html/houdini_href_e.c b/src/rt/sundown/html/houdini_href_e.c deleted file mode 100644 index 981b3b17e41..00000000000 --- a/src/rt/sundown/html/houdini_href_e.c +++ /dev/null @@ -1,108 +0,0 @@ -#include -#include -#include - -#include "houdini.h" - -#define ESCAPE_GROW_FACTOR(x) (((x) * 12) / 10) - -/* - * The following characters will not be escaped: - * - * -_.+!*'(),%#@?=;:/,+&$ alphanum - * - * Note that this character set is the addition of: - * - * - The characters which are safe to be in an URL - * - The characters which are *not* safe to be in - * an URL because they are RESERVED characters. - * - * We asume (lazily) that any RESERVED char that - * appears inside an URL is actually meant to - * have its native function (i.e. as an URL - * component/separator) and hence needs no escaping. - * - * There are two exceptions: the chacters & (amp) - * and ' (single quote) do not appear in the table. - * They are meant to appear in the URL as components, - * yet they require special HTML-entity escaping - * to generate valid HTML markup. - * - * All other characters will be escaped to %XX. - * - */ -static const char HREF_SAFE[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -void -houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size) -{ - static const char hex_chars[] = "0123456789ABCDEF"; - size_t i = 0, org; - char hex_str[3]; - - bufgrow(ob, ESCAPE_GROW_FACTOR(size)); - hex_str[0] = '%'; - - while (i < size) { - org = i; - while (i < size && HREF_SAFE[src[i]] != 0) - i++; - - if (i > org) - bufput(ob, src + org, i - org); - - /* escaping */ - if (i >= size) - break; - - switch (src[i]) { - /* amp appears all the time in URLs, but needs - * HTML-entity escaping to be inside an href */ - case '&': - BUFPUTSL(ob, "&"); - break; - - /* the single quote is a valid URL character - * according to the standard; it needs HTML - * entity escaping too */ - case '\'': - BUFPUTSL(ob, "'"); - break; - - /* the space can be escaped to %20 or a plus - * sign. we're going with the generic escape - * for now. the plus thing is more commonly seen - * when building GET strings */ -#if 0 - case ' ': - bufputc(ob, '+'); - break; -#endif - - /* every other character goes with a %XX escaping */ - default: - hex_str[1] = hex_chars[(src[i] >> 4) & 0xF]; - hex_str[2] = hex_chars[src[i] & 0xF]; - bufput(ob, hex_str, 3); - } - - i++; - } -} diff --git a/src/rt/sundown/html/houdini_html_e.c b/src/rt/sundown/html/houdini_html_e.c deleted file mode 100644 index d9bbf187d82..00000000000 --- a/src/rt/sundown/html/houdini_html_e.c +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include - -#include "houdini.h" - -#define ESCAPE_GROW_FACTOR(x) (((x) * 12) / 10) /* this is very scientific, yes */ - -/** - * According to the OWASP rules: - * - * & --> & - * < --> < - * > --> > - * " --> " - * ' --> ' ' is not recommended - * / --> / forward slash is included as it helps end an HTML entity - * - */ -static const char HTML_ESCAPE_TABLE[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -static const char *HTML_ESCAPES[] = { - "", - """, - "&", - "'", - "/", - "<", - ">" -}; - -void -houdini_escape_html0(struct buf *ob, const uint8_t *src, size_t size, int secure) -{ - size_t i = 0, org, esc = 0; - - bufgrow(ob, ESCAPE_GROW_FACTOR(size)); - - while (i < size) { - org = i; - while (i < size && (esc = HTML_ESCAPE_TABLE[src[i]]) == 0) - i++; - - if (i > org) - bufput(ob, src + org, i - org); - - /* escaping */ - if (i >= size) - break; - - /* The forward slash is only escaped in secure mode */ - if (src[i] == '/' && !secure) { - bufputc(ob, '/'); - } else { - bufputs(ob, HTML_ESCAPES[esc]); - } - - i++; - } -} - -void -houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size) -{ - houdini_escape_html0(ob, src, size, 1); -} - diff --git a/src/rt/sundown/html/html.c b/src/rt/sundown/html/html.c deleted file mode 100644 index 7f08ee8ef1b..00000000000 --- a/src/rt/sundown/html/html.c +++ /dev/null @@ -1,635 +0,0 @@ -/* - * Copyright (c) 2009, Natacha Porté - * Copyright (c) 2011, Vicent Marti - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "markdown.h" -#include "html.h" - -#include -#include -#include -#include - -#include "houdini.h" - -#define USE_XHTML(opt) (opt->flags & HTML_USE_XHTML) - -int -sdhtml_is_tag(const uint8_t *tag_data, size_t tag_size, const char *tagname) -{ - size_t i; - int closed = 0; - - if (tag_size < 3 || tag_data[0] != '<') - return HTML_TAG_NONE; - - i = 1; - - if (tag_data[i] == '/') { - closed = 1; - i++; - } - - for (; i < tag_size; ++i, ++tagname) { - if (*tagname == 0) - break; - - if (tag_data[i] != *tagname) - return HTML_TAG_NONE; - } - - if (i == tag_size) - return HTML_TAG_NONE; - - if (isspace(tag_data[i]) || tag_data[i] == '>') - return closed ? HTML_TAG_CLOSE : HTML_TAG_OPEN; - - return HTML_TAG_NONE; -} - -static inline void escape_html(struct buf *ob, const uint8_t *source, size_t length) -{ - houdini_escape_html0(ob, source, length, 0); -} - -static inline void escape_href(struct buf *ob, const uint8_t *source, size_t length) -{ - houdini_escape_href(ob, source, length); -} - -/******************** - * GENERIC RENDERER * - ********************/ -static int -rndr_autolink(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque) -{ - struct html_renderopt *options = opaque; - - if (!link || !link->size) - return 0; - - if ((options->flags & HTML_SAFELINK) != 0 && - !sd_autolink_issafe(link->data, link->size) && - type != MKDA_EMAIL) - return 0; - - BUFPUTSL(ob, "data, link->size); - - if (options->link_attributes) { - bufputc(ob, '\"'); - options->link_attributes(ob, link, opaque); - bufputc(ob, '>'); - } else { - BUFPUTSL(ob, "\">"); - } - - /* - * Pretty printing: if we get an email address as - * an actual URI, e.g. `mailto:foo@bar.com`, we don't - * want to print the `mailto:` prefix - */ - if (bufprefix(link, "mailto:") == 0) { - escape_html(ob, link->data + 7, link->size - 7); - } else { - escape_html(ob, link->data, link->size); - } - - BUFPUTSL(ob, ""); - - return 1; -} - -static void -rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque) -{ - if (ob->size) bufputc(ob, '\n'); - - if (lang && lang->size) { - size_t i, cls; - BUFPUTSL(ob, "
size; ++i, ++cls) {
-			while (i < lang->size && isspace(lang->data[i]))
-				i++;
-
-			if (i < lang->size) {
-				size_t org = i;
-				while (i < lang->size && !isspace(lang->data[i]))
-					i++;
-
-				if (lang->data[org] == '.')
-					org++;
-
-				if (cls) bufputc(ob, ' ');
-				escape_html(ob, lang->data + org, i - org);
-			}
-		}
-
-		BUFPUTSL(ob, "\">");
-	} else
-		BUFPUTSL(ob, "
");
-
-	if (text)
-		escape_html(ob, text->data, text->size);
-
-	BUFPUTSL(ob, "
\n"); -} - -static void -rndr_blockquote(struct buf *ob, const struct buf *text, void *opaque) -{ - if (ob->size) bufputc(ob, '\n'); - BUFPUTSL(ob, "
\n"); - if (text) bufput(ob, text->data, text->size); - BUFPUTSL(ob, "
\n"); -} - -static int -rndr_codespan(struct buf *ob, const struct buf *text, void *opaque) -{ - BUFPUTSL(ob, ""); - if (text) escape_html(ob, text->data, text->size); - BUFPUTSL(ob, ""); - return 1; -} - -static int -rndr_strikethrough(struct buf *ob, const struct buf *text, void *opaque) -{ - if (!text || !text->size) - return 0; - - BUFPUTSL(ob, ""); - bufput(ob, text->data, text->size); - BUFPUTSL(ob, ""); - return 1; -} - -static int -rndr_double_emphasis(struct buf *ob, const struct buf *text, void *opaque) -{ - if (!text || !text->size) - return 0; - - BUFPUTSL(ob, ""); - bufput(ob, text->data, text->size); - BUFPUTSL(ob, ""); - - return 1; -} - -static int -rndr_emphasis(struct buf *ob, const struct buf *text, void *opaque) -{ - if (!text || !text->size) return 0; - BUFPUTSL(ob, ""); - if (text) bufput(ob, text->data, text->size); - BUFPUTSL(ob, ""); - return 1; -} - -static int -rndr_linebreak(struct buf *ob, void *opaque) -{ - struct html_renderopt *options = opaque; - bufputs(ob, USE_XHTML(options) ? "
\n" : "
\n"); - return 1; -} - -static void -rndr_header(struct buf *ob, const struct buf *text, int level, void *opaque) -{ - struct html_renderopt *options = opaque; - - if (ob->size) - bufputc(ob, '\n'); - - if (options->flags & HTML_TOC) - bufprintf(ob, "", level, options->toc_data.header_count++); - else - bufprintf(ob, "", level); - - if (text) bufput(ob, text->data, text->size); - bufprintf(ob, "\n", level); -} - -static int -rndr_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque) -{ - struct html_renderopt *options = opaque; - - if (link != NULL && (options->flags & HTML_SAFELINK) != 0 && !sd_autolink_issafe(link->data, link->size)) - return 0; - - BUFPUTSL(ob, "size) - escape_href(ob, link->data, link->size); - - if (title && title->size) { - BUFPUTSL(ob, "\" title=\""); - escape_html(ob, title->data, title->size); - } - - if (options->link_attributes) { - bufputc(ob, '\"'); - options->link_attributes(ob, link, opaque); - bufputc(ob, '>'); - } else { - BUFPUTSL(ob, "\">"); - } - - if (content && content->size) bufput(ob, content->data, content->size); - BUFPUTSL(ob, ""); - return 1; -} - -static void -rndr_list(struct buf *ob, const struct buf *text, int flags, void *opaque) -{ - if (ob->size) bufputc(ob, '\n'); - bufput(ob, flags & MKD_LIST_ORDERED ? "
    \n" : "
      \n", 5); - if (text) bufput(ob, text->data, text->size); - bufput(ob, flags & MKD_LIST_ORDERED ? "
\n" : "\n", 6); -} - -static void -rndr_listitem(struct buf *ob, const struct buf *text, int flags, void *opaque) -{ - BUFPUTSL(ob, "
  • "); - if (text) { - size_t size = text->size; - while (size && text->data[size - 1] == '\n') - size--; - - bufput(ob, text->data, size); - } - BUFPUTSL(ob, "
  • \n"); -} - -static void -rndr_paragraph(struct buf *ob, const struct buf *text, void *opaque) -{ - struct html_renderopt *options = opaque; - size_t i = 0; - - if (ob->size) bufputc(ob, '\n'); - - if (!text || !text->size) - return; - - while (i < text->size && isspace(text->data[i])) i++; - - if (i == text->size) - return; - - BUFPUTSL(ob, "

    "); - if (options->flags & HTML_HARD_WRAP) { - size_t org; - while (i < text->size) { - org = i; - while (i < text->size && text->data[i] != '\n') - i++; - - if (i > org) - bufput(ob, text->data + org, i - org); - - /* - * do not insert a line break if this newline - * is the last character on the paragraph - */ - if (i >= text->size - 1) - break; - - rndr_linebreak(ob, opaque); - i++; - } - } else { - bufput(ob, &text->data[i], text->size - i); - } - BUFPUTSL(ob, "

    \n"); -} - -static void -rndr_raw_block(struct buf *ob, const struct buf *text, void *opaque) -{ - size_t org, sz; - if (!text) return; - sz = text->size; - while (sz > 0 && text->data[sz - 1] == '\n') sz--; - org = 0; - while (org < sz && text->data[org] == '\n') org++; - if (org >= sz) return; - if (ob->size) bufputc(ob, '\n'); - bufput(ob, text->data + org, sz - org); - bufputc(ob, '\n'); -} - -static int -rndr_triple_emphasis(struct buf *ob, const struct buf *text, void *opaque) -{ - if (!text || !text->size) return 0; - BUFPUTSL(ob, ""); - bufput(ob, text->data, text->size); - BUFPUTSL(ob, ""); - return 1; -} - -static void -rndr_hrule(struct buf *ob, void *opaque) -{ - struct html_renderopt *options = opaque; - if (ob->size) bufputc(ob, '\n'); - bufputs(ob, USE_XHTML(options) ? "
    \n" : "
    \n"); -} - -static int -rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque) -{ - struct html_renderopt *options = opaque; - if (!link || !link->size) return 0; - - BUFPUTSL(ob, "data, link->size); - BUFPUTSL(ob, "\" alt=\""); - - if (alt && alt->size) - escape_html(ob, alt->data, alt->size); - - if (title && title->size) { - BUFPUTSL(ob, "\" title=\""); - escape_html(ob, title->data, title->size); } - - bufputs(ob, USE_XHTML(options) ? "\"/>" : "\">"); - return 1; -} - -static int -rndr_raw_html(struct buf *ob, const struct buf *text, void *opaque) -{ - struct html_renderopt *options = opaque; - - /* HTML_ESCAPE overrides SKIP_HTML, SKIP_STYLE, SKIP_LINKS and SKIP_IMAGES - * It doens't see if there are any valid tags, just escape all of them. */ - if((options->flags & HTML_ESCAPE) != 0) { - escape_html(ob, text->data, text->size); - return 1; - } - - if ((options->flags & HTML_SKIP_HTML) != 0) - return 1; - - if ((options->flags & HTML_SKIP_STYLE) != 0 && - sdhtml_is_tag(text->data, text->size, "style")) - return 1; - - if ((options->flags & HTML_SKIP_LINKS) != 0 && - sdhtml_is_tag(text->data, text->size, "a")) - return 1; - - if ((options->flags & HTML_SKIP_IMAGES) != 0 && - sdhtml_is_tag(text->data, text->size, "img")) - return 1; - - bufput(ob, text->data, text->size); - return 1; -} - -static void -rndr_table(struct buf *ob, const struct buf *header, const struct buf *body, void *opaque) -{ - if (ob->size) bufputc(ob, '\n'); - BUFPUTSL(ob, "\n"); - if (header) - bufput(ob, header->data, header->size); - BUFPUTSL(ob, "\n"); - if (body) - bufput(ob, body->data, body->size); - BUFPUTSL(ob, "
    \n"); -} - -static void -rndr_tablerow(struct buf *ob, const struct buf *text, void *opaque) -{ - BUFPUTSL(ob, "\n"); - if (text) - bufput(ob, text->data, text->size); - BUFPUTSL(ob, "\n"); -} - -static void -rndr_tablecell(struct buf *ob, const struct buf *text, int flags, void *opaque) -{ - if (flags & MKD_TABLE_HEADER) { - BUFPUTSL(ob, ""); - break; - - case MKD_TABLE_ALIGN_L: - BUFPUTSL(ob, " align=\"left\">"); - break; - - case MKD_TABLE_ALIGN_R: - BUFPUTSL(ob, " align=\"right\">"); - break; - - default: - BUFPUTSL(ob, ">"); - } - - if (text) - bufput(ob, text->data, text->size); - - if (flags & MKD_TABLE_HEADER) { - BUFPUTSL(ob, "\n"); - } else { - BUFPUTSL(ob, "\n"); - } -} - -static int -rndr_superscript(struct buf *ob, const struct buf *text, void *opaque) -{ - if (!text || !text->size) return 0; - BUFPUTSL(ob, ""); - bufput(ob, text->data, text->size); - BUFPUTSL(ob, ""); - return 1; -} - -static void -rndr_normal_text(struct buf *ob, const struct buf *text, void *opaque) -{ - if (text) - escape_html(ob, text->data, text->size); -} - -static void -toc_header(struct buf *ob, const struct buf *text, int level, void *opaque) -{ - struct html_renderopt *options = opaque; - - /* set the level offset if this is the first header - * we're parsing for the document */ - if (options->toc_data.current_level == 0) { - options->toc_data.level_offset = level - 1; - } - level -= options->toc_data.level_offset; - - if (level > options->toc_data.current_level) { - while (level > options->toc_data.current_level) { - BUFPUTSL(ob, "
      \n
    • \n"); - options->toc_data.current_level++; - } - } else if (level < options->toc_data.current_level) { - BUFPUTSL(ob, "
    • \n"); - while (level < options->toc_data.current_level) { - BUFPUTSL(ob, "
    \n\n"); - options->toc_data.current_level--; - } - BUFPUTSL(ob,"
  • \n"); - } else { - BUFPUTSL(ob,"
  • \n
  • \n"); - } - - bufprintf(ob, "", options->toc_data.header_count++); - if (text) - escape_html(ob, text->data, text->size); - BUFPUTSL(ob, "\n"); -} - -static int -toc_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque) -{ - if (content && content->size) - bufput(ob, content->data, content->size); - return 1; -} - -static void -toc_finalize(struct buf *ob, void *opaque) -{ - struct html_renderopt *options = opaque; - - while (options->toc_data.current_level > 0) { - BUFPUTSL(ob, "
  • \n\n"); - options->toc_data.current_level--; - } -} - -void -sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options) -{ - static const struct sd_callbacks cb_default = { - NULL, - NULL, - NULL, - toc_header, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - - NULL, - rndr_codespan, - rndr_double_emphasis, - rndr_emphasis, - NULL, - NULL, - toc_link, - NULL, - rndr_triple_emphasis, - rndr_strikethrough, - rndr_superscript, - - NULL, - NULL, - - NULL, - toc_finalize, - }; - - memset(options, 0x0, sizeof(struct html_renderopt)); - options->flags = HTML_TOC; - - memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks)); -} - -void -sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options, unsigned int render_flags) -{ - static const struct sd_callbacks cb_default = { - rndr_blockcode, - rndr_blockquote, - rndr_raw_block, - rndr_header, - rndr_hrule, - rndr_list, - rndr_listitem, - rndr_paragraph, - rndr_table, - rndr_tablerow, - rndr_tablecell, - - rndr_autolink, - rndr_codespan, - rndr_double_emphasis, - rndr_emphasis, - rndr_image, - rndr_linebreak, - rndr_link, - rndr_raw_html, - rndr_triple_emphasis, - rndr_strikethrough, - rndr_superscript, - - NULL, - rndr_normal_text, - - NULL, - NULL, - }; - - /* Prepare the options pointer */ - memset(options, 0x0, sizeof(struct html_renderopt)); - options->flags = render_flags; - - /* Prepare the callbacks */ - memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks)); - - if (render_flags & HTML_SKIP_IMAGES) - callbacks->image = NULL; - - if (render_flags & HTML_SKIP_LINKS) { - callbacks->link = NULL; - callbacks->autolink = NULL; - } - - if (render_flags & HTML_SKIP_HTML || render_flags & HTML_ESCAPE) - callbacks->blockhtml = NULL; -} diff --git a/src/rt/sundown/html/html.h b/src/rt/sundown/html/html.h deleted file mode 100644 index 4c8810d471c..00000000000 --- a/src/rt/sundown/html/html.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2011, Vicent Marti - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef UPSKIRT_HTML_H -#define UPSKIRT_HTML_H - -#include "markdown.h" -#include "buffer.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct html_renderopt { - struct { - int header_count; - int current_level; - int level_offset; - } toc_data; - - unsigned int flags; - - /* extra callbacks */ - void (*link_attributes)(struct buf *ob, const struct buf *url, void *self); -}; - -typedef enum { - HTML_SKIP_HTML = (1 << 0), - HTML_SKIP_STYLE = (1 << 1), - HTML_SKIP_IMAGES = (1 << 2), - HTML_SKIP_LINKS = (1 << 3), - HTML_EXPAND_TABS = (1 << 4), - HTML_SAFELINK = (1 << 5), - HTML_TOC = (1 << 6), - HTML_HARD_WRAP = (1 << 7), - HTML_USE_XHTML = (1 << 8), - HTML_ESCAPE = (1 << 9), -} html_render_mode; - -typedef enum { - HTML_TAG_NONE = 0, - HTML_TAG_OPEN, - HTML_TAG_CLOSE, -} html_tag; - -int -sdhtml_is_tag(const uint8_t *tag_data, size_t tag_size, const char *tagname); - -extern void -sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, unsigned int render_flags); - -extern void -sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr); - -extern void -sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/src/rt/sundown/html/html_smartypants.c b/src/rt/sundown/html/html_smartypants.c deleted file mode 100644 index 367c26aeb9c..00000000000 --- a/src/rt/sundown/html/html_smartypants.c +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright (c) 2011, Vicent Marti - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "buffer.h" -#include "html.h" - -#include -#include -#include -#include - -#if defined(_WIN32) -#define snprintf _snprintf -#endif - -struct smartypants_data { - int in_squote; - int in_dquote; -}; - -static size_t smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); -static size_t smartypants_cb__dquote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); -static size_t smartypants_cb__amp(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); -static size_t smartypants_cb__period(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); -static size_t smartypants_cb__number(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); -static size_t smartypants_cb__dash(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); -static size_t smartypants_cb__parens(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); -static size_t smartypants_cb__squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); -static size_t smartypants_cb__backtick(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); -static size_t smartypants_cb__escape(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); - -static size_t (*smartypants_cb_ptrs[]) - (struct buf *, struct smartypants_data *, uint8_t, const uint8_t *, size_t) = -{ - NULL, /* 0 */ - smartypants_cb__dash, /* 1 */ - smartypants_cb__parens, /* 2 */ - smartypants_cb__squote, /* 3 */ - smartypants_cb__dquote, /* 4 */ - smartypants_cb__amp, /* 5 */ - smartypants_cb__period, /* 6 */ - smartypants_cb__number, /* 7 */ - smartypants_cb__ltag, /* 8 */ - smartypants_cb__backtick, /* 9 */ - smartypants_cb__escape, /* 10 */ -}; - -static const uint8_t smartypants_cb_chars[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 4, 0, 0, 0, 5, 3, 2, 0, 0, 0, 0, 1, 6, 0, - 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, - 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -static inline int -word_boundary(uint8_t c) -{ - return c == 0 || isspace(c) || ispunct(c); -} - -static int -smartypants_quotes(struct buf *ob, uint8_t previous_char, uint8_t next_char, uint8_t quote, int *is_open) -{ - char ent[8]; - - if (*is_open && !word_boundary(next_char)) - return 0; - - if (!(*is_open) && !word_boundary(previous_char)) - return 0; - - snprintf(ent, sizeof(ent), "&%c%cquo;", (*is_open) ? 'r' : 'l', quote); - *is_open = !(*is_open); - bufputs(ob, ent); - return 1; -} - -static size_t -smartypants_cb__squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) -{ - if (size >= 2) { - uint8_t t1 = tolower(text[1]); - - if (t1 == '\'') { - if (smartypants_quotes(ob, previous_char, size >= 3 ? text[2] : 0, 'd', &smrt->in_dquote)) - return 1; - } - - if ((t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && - (size == 3 || word_boundary(text[2]))) { - BUFPUTSL(ob, "’"); - return 0; - } - - if (size >= 3) { - uint8_t t2 = tolower(text[2]); - - if (((t1 == 'r' && t2 == 'e') || - (t1 == 'l' && t2 == 'l') || - (t1 == 'v' && t2 == 'e')) && - (size == 4 || word_boundary(text[3]))) { - BUFPUTSL(ob, "’"); - return 0; - } - } - } - - if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote)) - return 0; - - bufputc(ob, text[0]); - return 0; -} - -static size_t -smartypants_cb__parens(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) -{ - if (size >= 3) { - uint8_t t1 = tolower(text[1]); - uint8_t t2 = tolower(text[2]); - - if (t1 == 'c' && t2 == ')') { - BUFPUTSL(ob, "©"); - return 2; - } - - if (t1 == 'r' && t2 == ')') { - BUFPUTSL(ob, "®"); - return 2; - } - - if (size >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')') { - BUFPUTSL(ob, "™"); - return 3; - } - } - - bufputc(ob, text[0]); - return 0; -} - -static size_t -smartypants_cb__dash(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) -{ - if (size >= 3 && text[1] == '-' && text[2] == '-') { - BUFPUTSL(ob, "—"); - return 2; - } - - if (size >= 2 && text[1] == '-') { - BUFPUTSL(ob, "–"); - return 1; - } - - bufputc(ob, text[0]); - return 0; -} - -static size_t -smartypants_cb__amp(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) -{ - if (size >= 6 && memcmp(text, """, 6) == 0) { - if (smartypants_quotes(ob, previous_char, size >= 7 ? text[6] : 0, 'd', &smrt->in_dquote)) - return 5; - } - - if (size >= 4 && memcmp(text, "�", 4) == 0) - return 3; - - bufputc(ob, '&'); - return 0; -} - -static size_t -smartypants_cb__period(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) -{ - if (size >= 3 && text[1] == '.' && text[2] == '.') { - BUFPUTSL(ob, "…"); - return 2; - } - - if (size >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.') { - BUFPUTSL(ob, "…"); - return 4; - } - - bufputc(ob, text[0]); - return 0; -} - -static size_t -smartypants_cb__backtick(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) -{ - if (size >= 2 && text[1] == '`') { - if (smartypants_quotes(ob, previous_char, size >= 3 ? text[2] : 0, 'd', &smrt->in_dquote)) - return 1; - } - - return 0; -} - -static size_t -smartypants_cb__number(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) -{ - if (word_boundary(previous_char) && size >= 3) { - if (text[0] == '1' && text[1] == '/' && text[2] == '2') { - if (size == 3 || word_boundary(text[3])) { - BUFPUTSL(ob, "½"); - return 2; - } - } - - if (text[0] == '1' && text[1] == '/' && text[2] == '4') { - if (size == 3 || word_boundary(text[3]) || - (size >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h')) { - BUFPUTSL(ob, "¼"); - return 2; - } - } - - if (text[0] == '3' && text[1] == '/' && text[2] == '4') { - if (size == 3 || word_boundary(text[3]) || - (size >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's')) { - BUFPUTSL(ob, "¾"); - return 2; - } - } - } - - bufputc(ob, text[0]); - return 0; -} - -static size_t -smartypants_cb__dquote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) -{ - if (!smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 'd', &smrt->in_dquote)) - BUFPUTSL(ob, """); - - return 0; -} - -static size_t -smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) -{ - static const char *skip_tags[] = { - "pre", "code", "var", "samp", "kbd", "math", "script", "style" - }; - static const size_t skip_tags_count = 8; - - size_t tag, i = 0; - - while (i < size && text[i] != '>') - i++; - - for (tag = 0; tag < skip_tags_count; ++tag) { - if (sdhtml_is_tag(text, size, skip_tags[tag]) == HTML_TAG_OPEN) - break; - } - - if (tag < skip_tags_count) { - for (;;) { - while (i < size && text[i] != '<') - i++; - - if (i == size) - break; - - if (sdhtml_is_tag(text + i, size - i, skip_tags[tag]) == HTML_TAG_CLOSE) - break; - - i++; - } - - while (i < size && text[i] != '>') - i++; - } - - bufput(ob, text, i + 1); - return i; -} - -static size_t -smartypants_cb__escape(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) -{ - if (size < 2) - return 0; - - switch (text[1]) { - case '\\': - case '"': - case '\'': - case '.': - case '-': - case '`': - bufputc(ob, text[1]); - return 1; - - default: - bufputc(ob, '\\'); - return 0; - } -} - -#if 0 -static struct { - uint8_t c0; - const uint8_t *pattern; - const uint8_t *entity; - int skip; -} smartypants_subs[] = { - { '\'', "'s>", "’", 0 }, - { '\'', "'t>", "’", 0 }, - { '\'', "'re>", "’", 0 }, - { '\'', "'ll>", "’", 0 }, - { '\'', "'ve>", "’", 0 }, - { '\'', "'m>", "’", 0 }, - { '\'', "'d>", "’", 0 }, - { '-', "--", "—", 1 }, - { '-', "<->", "–", 0 }, - { '.', "...", "…", 2 }, - { '.', ". . .", "…", 4 }, - { '(', "(c)", "©", 2 }, - { '(', "(r)", "®", 2 }, - { '(', "(tm)", "™", 3 }, - { '3', "<3/4>", "¾", 2 }, - { '3', "<3/4ths>", "¾", 2 }, - { '1', "<1/2>", "½", 2 }, - { '1', "<1/4>", "¼", 2 }, - { '1', "<1/4th>", "¼", 2 }, - { '&', "�", 0, 3 }, -}; -#endif - -void -sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size) -{ - size_t i; - struct smartypants_data smrt = {0, 0}; - - if (!text) - return; - - bufgrow(ob, size); - - for (i = 0; i < size; ++i) { - size_t org; - uint8_t action = 0; - - org = i; - while (i < size && (action = smartypants_cb_chars[text[i]]) == 0) - i++; - - if (i > org) - bufput(ob, text + org, i - org); - - if (i < size) { - i += smartypants_cb_ptrs[(int)action] - (ob, &smrt, i ? text[i - 1] : 0, text + i, size - i); - } - } -} - - diff --git a/src/rt/sundown/html_block_names.txt b/src/rt/sundown/html_block_names.txt deleted file mode 100644 index a41d7d1b335..00000000000 --- a/src/rt/sundown/html_block_names.txt +++ /dev/null @@ -1,25 +0,0 @@ -## -p -dl -h1 -h2 -h3 -h4 -h5 -h6 -ol -ul -del -div -ins -pre -form -math -table -figure -iframe -script -style -fieldset -noscript -blockquote diff --git a/src/rt/sundown/src/autolink.c b/src/rt/sundown/src/autolink.c deleted file mode 100644 index 6f8d6ab9902..00000000000 --- a/src/rt/sundown/src/autolink.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (c) 2011, Vicent Marti - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "buffer.h" -#include "autolink.h" - -#include -#include -#include -#include - -#if defined(_WIN32) -#define strncasecmp _strnicmp -#endif - -int -sd_autolink_issafe(const uint8_t *link, size_t link_len) -{ - static const size_t valid_uris_count = 5; - static const char *valid_uris[] = { - "/", "http://", "https://", "ftp://", "mailto:" - }; - - size_t i; - - for (i = 0; i < valid_uris_count; ++i) { - size_t len = strlen(valid_uris[i]); - - if (link_len > len && - strncasecmp((char *)link, valid_uris[i], len) == 0 && - isalnum(link[len])) - return 1; - } - - return 0; -} - -static size_t -autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size) -{ - uint8_t cclose, copen = 0; - size_t i; - - for (i = 0; i < link_end; ++i) - if (data[i] == '<') { - link_end = i; - break; - } - - while (link_end > 0) { - if (strchr("?!.,", data[link_end - 1]) != NULL) - link_end--; - - else if (data[link_end - 1] == ';') { - size_t new_end = link_end - 2; - - while (new_end > 0 && isalpha(data[new_end])) - new_end--; - - if (new_end < link_end - 2 && data[new_end] == '&') - link_end = new_end; - else - link_end--; - } - else break; - } - - if (link_end == 0) - return 0; - - cclose = data[link_end - 1]; - - switch (cclose) { - case '"': copen = '"'; break; - case '\'': copen = '\''; break; - case ')': copen = '('; break; - case ']': copen = '['; break; - case '}': copen = '{'; break; - } - - if (copen != 0) { - size_t closing = 0; - size_t opening = 0; - size_t i = 0; - - /* Try to close the final punctuation sign in this same line; - * if we managed to close it outside of the URL, that means that it's - * not part of the URL. If it closes inside the URL, that means it - * is part of the URL. - * - * Examples: - * - * foo http://www.pokemon.com/Pikachu_(Electric) bar - * => http://www.pokemon.com/Pikachu_(Electric) - * - * foo (http://www.pokemon.com/Pikachu_(Electric)) bar - * => http://www.pokemon.com/Pikachu_(Electric) - * - * foo http://www.pokemon.com/Pikachu_(Electric)) bar - * => http://www.pokemon.com/Pikachu_(Electric)) - * - * (foo http://www.pokemon.com/Pikachu_(Electric)) bar - * => foo http://www.pokemon.com/Pikachu_(Electric) - */ - - while (i < link_end) { - if (data[i] == copen) - opening++; - else if (data[i] == cclose) - closing++; - - i++; - } - - if (closing != opening) - link_end--; - } - - return link_end; -} - -static size_t -check_domain(uint8_t *data, size_t size, int allow_short) -{ - size_t i, np = 0; - - if (!isalnum(data[0])) - return 0; - - for (i = 1; i < size - 1; ++i) { - if (data[i] == '.') np++; - else if (!isalnum(data[i]) && data[i] != '-') break; - } - - if (allow_short) { - /* We don't need a valid domain in the strict sense (with - * least one dot; so just make sure it's composed of valid - * domain characters and return the length of the the valid - * sequence. */ - return i; - } else { - /* a valid domain needs to have at least a dot. - * that's as far as we get */ - return np ? i : 0; - } -} - -size_t -sd_autolink__www( - size_t *rewind_p, - struct buf *link, - uint8_t *data, - size_t max_rewind, - size_t size, - unsigned int flags) -{ - size_t link_end; - - if (max_rewind > 0 && !ispunct(data[-1]) && !isspace(data[-1])) - return 0; - - if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0) - return 0; - - link_end = check_domain(data, size, 0); - - if (link_end == 0) - return 0; - - while (link_end < size && !isspace(data[link_end])) - link_end++; - - link_end = autolink_delim(data, link_end, max_rewind, size); - - if (link_end == 0) - return 0; - - bufput(link, data, link_end); - *rewind_p = 0; - - return (int)link_end; -} - -size_t -sd_autolink__email( - size_t *rewind_p, - struct buf *link, - uint8_t *data, - size_t max_rewind, - size_t size, - unsigned int flags) -{ - size_t link_end, rewind; - int nb = 0, np = 0; - - for (rewind = 0; rewind < max_rewind; ++rewind) { - uint8_t c = data[-rewind - 1]; - - if (isalnum(c)) - continue; - - if (strchr(".+-_", c) != NULL) - continue; - - break; - } - - if (rewind == 0) - return 0; - - for (link_end = 0; link_end < size; ++link_end) { - uint8_t c = data[link_end]; - - if (isalnum(c)) - continue; - - if (c == '@') - nb++; - else if (c == '.' && link_end < size - 1) - np++; - else if (c != '-' && c != '_') - break; - } - - if (link_end < 2 || nb != 1 || np == 0 || - !isalpha(data[link_end - 1])) - return 0; - - link_end = autolink_delim(data, link_end, max_rewind, size); - - if (link_end == 0) - return 0; - - bufput(link, data - rewind, link_end + rewind); - *rewind_p = rewind; - - return link_end; -} - -size_t -sd_autolink__url( - size_t *rewind_p, - struct buf *link, - uint8_t *data, - size_t max_rewind, - size_t size, - unsigned int flags) -{ - size_t link_end, rewind = 0, domain_len; - - if (size < 4 || data[1] != '/' || data[2] != '/') - return 0; - - while (rewind < max_rewind && isalpha(data[-rewind - 1])) - rewind++; - - if (!sd_autolink_issafe(data - rewind, size + rewind)) - return 0; - - link_end = strlen("://"); - - domain_len = check_domain( - data + link_end, - size - link_end, - flags & SD_AUTOLINK_SHORT_DOMAINS); - - if (domain_len == 0) - return 0; - - link_end += domain_len; - while (link_end < size && !isspace(data[link_end])) - link_end++; - - link_end = autolink_delim(data, link_end, max_rewind, size); - - if (link_end == 0) - return 0; - - bufput(link, data - rewind, link_end + rewind); - *rewind_p = rewind; - - return link_end; -} - diff --git a/src/rt/sundown/src/autolink.h b/src/rt/sundown/src/autolink.h deleted file mode 100644 index 65e0fe6f144..00000000000 --- a/src/rt/sundown/src/autolink.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2011, Vicent Marti - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef UPSKIRT_AUTOLINK_H -#define UPSKIRT_AUTOLINK_H - -#include "buffer.h" - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - SD_AUTOLINK_SHORT_DOMAINS = (1 << 0), -}; - -int -sd_autolink_issafe(const uint8_t *link, size_t link_len); - -size_t -sd_autolink__www(size_t *rewind_p, struct buf *link, - uint8_t *data, size_t offset, size_t size, unsigned int flags); - -size_t -sd_autolink__email(size_t *rewind_p, struct buf *link, - uint8_t *data, size_t offset, size_t size, unsigned int flags); - -size_t -sd_autolink__url(size_t *rewind_p, struct buf *link, - uint8_t *data, size_t offset, size_t size, unsigned int flags); - -#ifdef __cplusplus -} -#endif - -#endif - -/* vim: set filetype=c: */ diff --git a/src/rt/sundown/src/buffer.c b/src/rt/sundown/src/buffer.c deleted file mode 100644 index 47b40ce2f75..00000000000 --- a/src/rt/sundown/src/buffer.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2008, Natacha Porté - * Copyright (c) 2011, Vicent Martí - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#define BUFFER_MAX_ALLOC_SIZE (1024 * 1024 * 16) //16mb - -#include "buffer.h" - -#include -#include -#include -#include - -/* MSVC compat */ -#if defined(_MSC_VER) -# define _buf_vsnprintf _vsnprintf -#else -# define _buf_vsnprintf vsnprintf -#endif - -int -bufprefix(const struct buf *buf, const char *prefix) -{ - size_t i; - assert(buf && buf->unit); - - for (i = 0; i < buf->size; ++i) { - if (prefix[i] == 0) - return 0; - - if (buf->data[i] != prefix[i]) - return buf->data[i] - prefix[i]; - } - - return 0; -} - -/* bufgrow: increasing the allocated size to the given value */ -int -bufgrow(struct buf *buf, size_t neosz) -{ - size_t neoasz; - void *neodata; - - assert(buf && buf->unit); - - if (neosz > BUFFER_MAX_ALLOC_SIZE) - return BUF_ENOMEM; - - if (buf->asize >= neosz) - return BUF_OK; - - neoasz = buf->asize + buf->unit; - while (neoasz < neosz) - neoasz += buf->unit; - - neodata = realloc(buf->data, neoasz); - if (!neodata) - return BUF_ENOMEM; - - buf->data = neodata; - buf->asize = neoasz; - return BUF_OK; -} - - -/* bufnew: allocation of a new buffer */ -struct buf * -bufnew(size_t unit) -{ - struct buf *ret; - ret = malloc(sizeof (struct buf)); - - if (ret) { - ret->data = 0; - ret->size = ret->asize = 0; - ret->unit = unit; - } - return ret; -} - -/* bufnullterm: NULL-termination of the string array */ -const char * -bufcstr(struct buf *buf) -{ - assert(buf && buf->unit); - - if (buf->size < buf->asize && buf->data[buf->size] == 0) - return (char *)buf->data; - - if (buf->size + 1 <= buf->asize || bufgrow(buf, buf->size + 1) == 0) { - buf->data[buf->size] = 0; - return (char *)buf->data; - } - - return NULL; -} - -/* bufprintf: formatted printing to a buffer */ -void -bufprintf(struct buf *buf, const char *fmt, ...) -{ - va_list ap; - int n; - - assert(buf && buf->unit); - - if (buf->size >= buf->asize && bufgrow(buf, buf->size + 1) < 0) - return; - - va_start(ap, fmt); - n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap); - va_end(ap); - - if (n < 0) { -#ifdef _MSC_VER - va_start(ap, fmt); - n = _vscprintf(fmt, ap); - va_end(ap); -#else - return; -#endif - } - - if ((size_t)n >= buf->asize - buf->size) { - if (bufgrow(buf, buf->size + n + 1) < 0) - return; - - va_start(ap, fmt); - n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap); - va_end(ap); - } - - if (n < 0) - return; - - buf->size += n; -} - -/* bufput: appends raw data to a buffer */ -void -bufput(struct buf *buf, const void *data, size_t len) -{ - assert(buf && buf->unit); - - if (buf->size + len > buf->asize && bufgrow(buf, buf->size + len) < 0) - return; - - memcpy(buf->data + buf->size, data, len); - buf->size += len; -} - -/* bufputs: appends a NUL-terminated string to a buffer */ -void -bufputs(struct buf *buf, const char *str) -{ - bufput(buf, str, strlen(str)); -} - - -/* bufputc: appends a single uint8_t to a buffer */ -void -bufputc(struct buf *buf, int c) -{ - assert(buf && buf->unit); - - if (buf->size + 1 > buf->asize && bufgrow(buf, buf->size + 1) < 0) - return; - - buf->data[buf->size] = c; - buf->size += 1; -} - -/* bufrelease: decrease the reference count and free the buffer if needed */ -void -bufrelease(struct buf *buf) -{ - if (!buf) - return; - - free(buf->data); - free(buf); -} - - -/* bufreset: frees internal data of the buffer */ -void -bufreset(struct buf *buf) -{ - if (!buf) - return; - - free(buf->data); - buf->data = NULL; - buf->size = buf->asize = 0; -} - -/* bufslurp: removes a given number of bytes from the head of the array */ -void -bufslurp(struct buf *buf, size_t len) -{ - assert(buf && buf->unit); - - if (len >= buf->size) { - buf->size = 0; - return; - } - - buf->size -= len; - memmove(buf->data, buf->data + len, buf->size); -} - diff --git a/src/rt/sundown/src/buffer.h b/src/rt/sundown/src/buffer.h deleted file mode 100644 index 221d142eda3..00000000000 --- a/src/rt/sundown/src/buffer.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2008, Natacha Porté - * Copyright (c) 2011, Vicent Martí - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef BUFFER_H__ -#define BUFFER_H__ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(_MSC_VER) -#define __attribute__(x) -#define inline -#endif - -typedef enum { - BUF_OK = 0, - BUF_ENOMEM = -1, -} buferror_t; - -/* struct buf: character array buffer */ -struct buf { - uint8_t *data; /* actual character data */ - size_t size; /* size of the string */ - size_t asize; /* allocated size (0 = volatile buffer) */ - size_t unit; /* reallocation unit size (0 = read-only buffer) */ -}; - -/* CONST_BUF: global buffer from a string litteral */ -#define BUF_STATIC(string) \ - { (uint8_t *)string, sizeof string -1, sizeof string, 0, 0 } - -/* VOLATILE_BUF: macro for creating a volatile buffer on the stack */ -#define BUF_VOLATILE(strname) \ - { (uint8_t *)strname, strlen(strname), 0, 0, 0 } - -/* BUFPUTSL: optimized bufputs of a string litteral */ -#define BUFPUTSL(output, literal) \ - bufput(output, literal, sizeof literal - 1) - -/* bufgrow: increasing the allocated size to the given value */ -int bufgrow(struct buf *, size_t); - -/* bufnew: allocation of a new buffer */ -struct buf *bufnew(size_t) __attribute__ ((malloc)); - -/* bufnullterm: NUL-termination of the string array (making a C-string) */ -const char *bufcstr(struct buf *); - -/* bufprefix: compare the beginning of a buffer with a string */ -int bufprefix(const struct buf *buf, const char *prefix); - -/* bufput: appends raw data to a buffer */ -void bufput(struct buf *, const void *, size_t); - -/* bufputs: appends a NUL-terminated string to a buffer */ -void bufputs(struct buf *, const char *); - -/* bufputc: appends a single char to a buffer */ -void bufputc(struct buf *, int); - -/* bufrelease: decrease the reference count and free the buffer if needed */ -void bufrelease(struct buf *); - -/* bufreset: frees internal data of the buffer */ -void bufreset(struct buf *); - -/* bufslurp: removes a given number of bytes from the head of the array */ -void bufslurp(struct buf *, size_t); - -/* bufprintf: formatted printing to a buffer */ -void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf, 2, 3))); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/rt/sundown/src/html_blocks.h b/src/rt/sundown/src/html_blocks.h deleted file mode 100644 index 09a758fe275..00000000000 --- a/src/rt/sundown/src/html_blocks.h +++ /dev/null @@ -1,206 +0,0 @@ -/* C code produced by gperf version 3.0.3 */ -/* Command-line: gperf -N find_block_tag -H hash_block_tag -C -c -E --ignore-case html_block_names.txt */ -/* Computed positions: -k'1-2' */ - -#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ - && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ - && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ - && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ - && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ - && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ - && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ - && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ - && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ - && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ - && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ - && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ - && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ - && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ - && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ - && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ - && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ - && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ - && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ - && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ - && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ - && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ - && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) -/* The character set is not based on ISO-646. */ -error "gperf generated tables don't work with this execution character set. Please report a bug to ." -#endif - -/* maximum key range = 37, duplicates = 0 */ - -#ifndef GPERF_DOWNCASE -#define GPERF_DOWNCASE 1 -static unsigned char gperf_downcase[256] = - { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, - 255 - }; -#endif - -#ifndef GPERF_CASE_STRNCMP -#define GPERF_CASE_STRNCMP 1 -static int -gperf_case_strncmp (s1, s2, n) - register const char *s1; - register const char *s2; - register unsigned int n; -{ - for (; n > 0;) - { - unsigned char c1 = gperf_downcase[(unsigned char)*s1++]; - unsigned char c2 = gperf_downcase[(unsigned char)*s2++]; - if (c1 != 0 && c1 == c2) - { - n--; - continue; - } - return (int)c1 - (int)c2; - } - return 0; -} -#endif - -#ifdef __GNUC__ -__inline -#else -#ifdef __cplusplus -inline -#endif -#endif -static unsigned int -hash_block_tag (str, len) - register const char *str; - register unsigned int len; -{ - static const unsigned char asso_values[] = - { - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 8, 30, 25, 20, 15, 10, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 0, 38, 0, 38, - 5, 5, 5, 15, 0, 38, 38, 0, 15, 10, - 0, 38, 38, 15, 0, 5, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 0, 38, - 0, 38, 5, 5, 5, 15, 0, 38, 38, 0, - 15, 10, 0, 38, 38, 15, 0, 5, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38 - }; - register int hval = len; - - switch (hval) - { - default: - hval += asso_values[(unsigned char)str[1]+1]; - /*FALLTHROUGH*/ - case 1: - hval += asso_values[(unsigned char)str[0]]; - break; - } - return hval; -} - -#ifdef __GNUC__ -__inline -#ifdef __GNUC_STDC_INLINE__ -__attribute__ ((__gnu_inline__)) -#endif -#endif -const char * -find_block_tag (str, len) - register const char *str; - register unsigned int len; -{ - enum - { - TOTAL_KEYWORDS = 24, - MIN_WORD_LENGTH = 1, - MAX_WORD_LENGTH = 10, - MIN_HASH_VALUE = 1, - MAX_HASH_VALUE = 37 - }; - - static const char * const wordlist[] = - { - "", - "p", - "dl", - "div", - "math", - "table", - "", - "ul", - "del", - "form", - "blockquote", - "figure", - "ol", - "fieldset", - "", - "h1", - "", - "h6", - "pre", - "", "", - "script", - "h5", - "noscript", - "", - "style", - "iframe", - "h4", - "ins", - "", "", "", - "h3", - "", "", "", "", - "h2" - }; - - if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) - { - register int key = hash_block_tag (str, len); - - if (key <= MAX_HASH_VALUE && key >= 0) - { - register const char *s = wordlist[key]; - - if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0') - return s; - } - } - return 0; -} diff --git a/src/rt/sundown/src/markdown.c b/src/rt/sundown/src/markdown.c deleted file mode 100644 index ea3cf23253a..00000000000 --- a/src/rt/sundown/src/markdown.c +++ /dev/null @@ -1,2556 +0,0 @@ -/* markdown.c - generic markdown parser */ - -/* - * Copyright (c) 2009, Natacha Porté - * Copyright (c) 2011, Vicent Marti - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "markdown.h" -#include "stack.h" - -#include -#include -#include -#include - -#if defined(_WIN32) -#define strncasecmp _strnicmp -#endif - -#define REF_TABLE_SIZE 8 - -#define BUFFER_BLOCK 0 -#define BUFFER_SPAN 1 - -#define MKD_LI_END 8 /* internal list flag */ - -#define gperf_case_strncmp(s1, s2, n) strncasecmp(s1, s2, n) -#define GPERF_DOWNCASE 1 -#define GPERF_CASE_STRNCMP 1 -#include "html_blocks.h" - -/*************** - * LOCAL TYPES * - ***************/ - -/* link_ref: reference to a link */ -struct link_ref { - unsigned int id; - - struct buf *link; - struct buf *title; - - struct link_ref *next; -}; - -/* char_trigger: function pointer to render active chars */ -/* returns the number of chars taken care of */ -/* data is the pointer of the beginning of the span */ -/* offset is the number of valid chars before data */ -struct sd_markdown; -typedef size_t -(*char_trigger)(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); - -static size_t char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); -static size_t char_linebreak(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); -static size_t char_codespan(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); -static size_t char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); -static size_t char_entity(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); -static size_t char_langle_tag(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); -static size_t char_autolink_url(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); -static size_t char_autolink_email(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); -static size_t char_autolink_www(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); -static size_t char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); -static size_t char_superscript(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); - -enum markdown_char_t { - MD_CHAR_NONE = 0, - MD_CHAR_EMPHASIS, - MD_CHAR_CODESPAN, - MD_CHAR_LINEBREAK, - MD_CHAR_LINK, - MD_CHAR_LANGLE, - MD_CHAR_ESCAPE, - MD_CHAR_ENTITITY, - MD_CHAR_AUTOLINK_URL, - MD_CHAR_AUTOLINK_EMAIL, - MD_CHAR_AUTOLINK_WWW, - MD_CHAR_SUPERSCRIPT, -}; - -static char_trigger markdown_char_ptrs[] = { - NULL, - &char_emphasis, - &char_codespan, - &char_linebreak, - &char_link, - &char_langle_tag, - &char_escape, - &char_entity, - &char_autolink_url, - &char_autolink_email, - &char_autolink_www, - &char_superscript, -}; - -/* render • structure containing one particular render */ -struct sd_markdown { - struct sd_callbacks cb; - void *opaque; - - struct link_ref *refs[REF_TABLE_SIZE]; - uint8_t active_char[256]; - struct stack work_bufs[2]; - unsigned int ext_flags; - size_t max_nesting; - int in_link_body; -}; - -/*************************** - * HELPER FUNCTIONS * - ***************************/ - -static inline struct buf * -rndr_newbuf(struct sd_markdown *rndr, int type) -{ - static const size_t buf_size[2] = {256, 64}; - struct buf *work = NULL; - struct stack *pool = &rndr->work_bufs[type]; - - if (pool->size < pool->asize && - pool->item[pool->size] != NULL) { - work = pool->item[pool->size++]; - work->size = 0; - } else { - work = bufnew(buf_size[type]); - stack_push(pool, work); - } - - return work; -} - -static inline void -rndr_popbuf(struct sd_markdown *rndr, int type) -{ - rndr->work_bufs[type].size--; -} - -static void -unscape_text(struct buf *ob, struct buf *src) -{ - size_t i = 0, org; - while (i < src->size) { - org = i; - while (i < src->size && src->data[i] != '\\') - i++; - - if (i > org) - bufput(ob, src->data + org, i - org); - - if (i + 1 >= src->size) - break; - - bufputc(ob, src->data[i + 1]); - i += 2; - } -} - -static unsigned int -hash_link_ref(const uint8_t *link_ref, size_t length) -{ - size_t i; - unsigned int hash = 0; - - for (i = 0; i < length; ++i) - hash = tolower(link_ref[i]) + (hash << 6) + (hash << 16) - hash; - - return hash; -} - -static struct link_ref * -add_link_ref( - struct link_ref **references, - const uint8_t *name, size_t name_size) -{ - struct link_ref *ref = calloc(1, sizeof(struct link_ref)); - - if (!ref) - return NULL; - - ref->id = hash_link_ref(name, name_size); - ref->next = references[ref->id % REF_TABLE_SIZE]; - - references[ref->id % REF_TABLE_SIZE] = ref; - return ref; -} - -static struct link_ref * -find_link_ref(struct link_ref **references, uint8_t *name, size_t length) -{ - unsigned int hash = hash_link_ref(name, length); - struct link_ref *ref = NULL; - - ref = references[hash % REF_TABLE_SIZE]; - - while (ref != NULL) { - if (ref->id == hash) - return ref; - - ref = ref->next; - } - - return NULL; -} - -static void -free_link_refs(struct link_ref **references) -{ - size_t i; - - for (i = 0; i < REF_TABLE_SIZE; ++i) { - struct link_ref *r = references[i]; - struct link_ref *next; - - while (r) { - next = r->next; - bufrelease(r->link); - bufrelease(r->title); - free(r); - r = next; - } - } -} - -/* - * Check whether a char is a Markdown space. - - * Right now we only consider spaces the actual - * space and a newline: tabs and carriage returns - * are filtered out during the preprocessing phase. - * - * If we wanted to actually be UTF-8 compliant, we - * should instead extract an Unicode codepoint from - * this character and check for space properties. - */ -static inline int -_isspace(int c) -{ - return c == ' ' || c == '\n'; -} - -/**************************** - * INLINE PARSING FUNCTIONS * - ****************************/ - -/* is_mail_autolink • looks for the address part of a mail autolink and '>' */ -/* this is less strict than the original markdown e-mail address matching */ -static size_t -is_mail_autolink(uint8_t *data, size_t size) -{ - size_t i = 0, nb = 0; - - /* address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' */ - for (i = 0; i < size; ++i) { - if (isalnum(data[i])) - continue; - - switch (data[i]) { - case '@': - nb++; - - case '-': - case '.': - case '_': - break; - - case '>': - return (nb == 1) ? i + 1 : 0; - - default: - return 0; - } - } - - return 0; -} - -/* tag_length • returns the length of the given tag, or 0 is it's not valid */ -static size_t -tag_length(uint8_t *data, size_t size, enum mkd_autolink *autolink) -{ - size_t i, j; - - /* a valid tag can't be shorter than 3 chars */ - if (size < 3) return 0; - - /* begins with a '<' optionally followed by '/', followed by letter or number */ - if (data[0] != '<') return 0; - i = (data[1] == '/') ? 2 : 1; - - if (!isalnum(data[i])) - return 0; - - /* scheme test */ - *autolink = MKDA_NOT_AUTOLINK; - - /* try to find the beginning of an URI */ - while (i < size && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-')) - i++; - - if (i > 1 && data[i] == '@') { - if ((j = is_mail_autolink(data + i, size - i)) != 0) { - *autolink = MKDA_EMAIL; - return i + j; - } - } - - if (i > 2 && data[i] == ':') { - *autolink = MKDA_NORMAL; - i++; - } - - /* completing autolink test: no whitespace or ' or " */ - if (i >= size) - *autolink = MKDA_NOT_AUTOLINK; - - else if (*autolink) { - j = i; - - while (i < size) { - if (data[i] == '\\') i += 2; - else if (data[i] == '>' || data[i] == '\'' || - data[i] == '"' || data[i] == ' ' || data[i] == '\n') - break; - else i++; - } - - if (i >= size) return 0; - if (i > j && data[i] == '>') return i + 1; - /* one of the forbidden chars has been found */ - *autolink = MKDA_NOT_AUTOLINK; - } - - /* looking for sometinhg looking like a tag end */ - while (i < size && data[i] != '>') i++; - if (i >= size) return 0; - return i + 1; -} - -/* parse_inline • parses inline markdown elements */ -static void -parse_inline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) -{ - size_t i = 0, end = 0; - uint8_t action = 0; - struct buf work = { 0, 0, 0, 0 }; - - if (rndr->work_bufs[BUFFER_SPAN].size + - rndr->work_bufs[BUFFER_BLOCK].size > rndr->max_nesting) - return; - - while (i < size) { - /* copying inactive chars into the output */ - while (end < size && (action = rndr->active_char[data[end]]) == 0) { - end++; - } - - if (rndr->cb.normal_text) { - work.data = data + i; - work.size = end - i; - rndr->cb.normal_text(ob, &work, rndr->opaque); - } - else - bufput(ob, data + i, end - i); - - if (end >= size) break; - i = end; - - end = markdown_char_ptrs[(int)action](ob, rndr, data + i, i, size - i); - if (!end) /* no action from the callback */ - end = i + 1; - else { - i += end; - end = i; - } - } -} - -/* find_emph_char • looks for the next emph uint8_t, skipping other constructs */ -static size_t -find_emph_char(uint8_t *data, size_t size, uint8_t c) -{ - size_t i = 1; - - while (i < size) { - while (i < size && data[i] != c && data[i] != '`' && data[i] != '[') - i++; - - if (i == size) - return 0; - - if (data[i] == c) - return i; - - /* not counting escaped chars */ - if (i && data[i - 1] == '\\') { - i++; continue; - } - - if (data[i] == '`') { - size_t span_nb = 0, bt; - size_t tmp_i = 0; - - /* counting the number of opening backticks */ - while (i < size && data[i] == '`') { - i++; span_nb++; - } - - if (i >= size) return 0; - - /* finding the matching closing sequence */ - bt = 0; - while (i < size && bt < span_nb) { - if (!tmp_i && data[i] == c) tmp_i = i; - if (data[i] == '`') bt++; - else bt = 0; - i++; - } - - if (i >= size) return tmp_i; - } - /* skipping a link */ - else if (data[i] == '[') { - size_t tmp_i = 0; - uint8_t cc; - - i++; - while (i < size && data[i] != ']') { - if (!tmp_i && data[i] == c) tmp_i = i; - i++; - } - - i++; - while (i < size && (data[i] == ' ' || data[i] == '\n')) - i++; - - if (i >= size) - return tmp_i; - - switch (data[i]) { - case '[': - cc = ']'; break; - - case '(': - cc = ')'; break; - - default: - if (tmp_i) - return tmp_i; - else - continue; - } - - i++; - while (i < size && data[i] != cc) { - if (!tmp_i && data[i] == c) tmp_i = i; - i++; - } - - if (i >= size) - return tmp_i; - - i++; - } - } - - return 0; -} - -/* parse_emph1 • parsing single emphase */ -/* closed by a symbol not preceded by whitespace and not followed by symbol */ -static size_t -parse_emph1(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, uint8_t c) -{ - size_t i = 0, len; - struct buf *work = 0; - int r; - - if (!rndr->cb.emphasis) return 0; - - /* skipping one symbol if coming from emph3 */ - if (size > 1 && data[0] == c && data[1] == c) i = 1; - - while (i < size) { - len = find_emph_char(data + i, size - i, c); - if (!len) return 0; - i += len; - if (i >= size) return 0; - - if (data[i] == c && !_isspace(data[i - 1])) { - - if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) { - if (i + 1 < size && isalnum(data[i + 1])) - continue; - } - - work = rndr_newbuf(rndr, BUFFER_SPAN); - parse_inline(work, rndr, data, i); - r = rndr->cb.emphasis(ob, work, rndr->opaque); - rndr_popbuf(rndr, BUFFER_SPAN); - return r ? i + 1 : 0; - } - } - - return 0; -} - -/* parse_emph2 • parsing single emphase */ -static size_t -parse_emph2(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, uint8_t c) -{ - int (*render_method)(struct buf *ob, const struct buf *text, void *opaque); - size_t i = 0, len; - struct buf *work = 0; - int r; - - render_method = (c == '~') ? rndr->cb.strikethrough : rndr->cb.double_emphasis; - - if (!render_method) - return 0; - - while (i < size) { - len = find_emph_char(data + i, size - i, c); - if (!len) return 0; - i += len; - - if (i + 1 < size && data[i] == c && data[i + 1] == c && i && !_isspace(data[i - 1])) { - work = rndr_newbuf(rndr, BUFFER_SPAN); - parse_inline(work, rndr, data, i); - r = render_method(ob, work, rndr->opaque); - rndr_popbuf(rndr, BUFFER_SPAN); - return r ? i + 2 : 0; - } - i++; - } - return 0; -} - -/* parse_emph3 • parsing single emphase */ -/* finds the first closing tag, and delegates to the other emph */ -static size_t -parse_emph3(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, uint8_t c) -{ - size_t i = 0, len; - int r; - - while (i < size) { - len = find_emph_char(data + i, size - i, c); - if (!len) return 0; - i += len; - - /* skip whitespace preceded symbols */ - if (data[i] != c || _isspace(data[i - 1])) - continue; - - if (i + 2 < size && data[i + 1] == c && data[i + 2] == c && rndr->cb.triple_emphasis) { - /* triple symbol found */ - struct buf *work = rndr_newbuf(rndr, BUFFER_SPAN); - - parse_inline(work, rndr, data, i); - r = rndr->cb.triple_emphasis(ob, work, rndr->opaque); - rndr_popbuf(rndr, BUFFER_SPAN); - return r ? i + 3 : 0; - - } else if (i + 1 < size && data[i + 1] == c) { - /* double symbol found, handing over to emph1 */ - len = parse_emph1(ob, rndr, data - 2, size + 2, c); - if (!len) return 0; - else return len - 2; - - } else { - /* single symbol found, handing over to emph2 */ - len = parse_emph2(ob, rndr, data - 1, size + 1, c); - if (!len) return 0; - else return len - 1; - } - } - return 0; -} - -/* char_emphasis • single and double emphasis parsing */ -static size_t -char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) -{ - uint8_t c = data[0]; - size_t ret; - - if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) { - if (offset > 0 && !_isspace(data[-1]) && data[-1] != '>') - return 0; - } - - if (size > 2 && data[1] != c) { - /* whitespace cannot follow an opening emphasis; - * strikethrough only takes two characters '~~' */ - if (c == '~' || _isspace(data[1]) || (ret = parse_emph1(ob, rndr, data + 1, size - 1, c)) == 0) - return 0; - - return ret + 1; - } - - if (size > 3 && data[1] == c && data[2] != c) { - if (_isspace(data[2]) || (ret = parse_emph2(ob, rndr, data + 2, size - 2, c)) == 0) - return 0; - - return ret + 2; - } - - if (size > 4 && data[1] == c && data[2] == c && data[3] != c) { - if (c == '~' || _isspace(data[3]) || (ret = parse_emph3(ob, rndr, data + 3, size - 3, c)) == 0) - return 0; - - return ret + 3; - } - - return 0; -} - - -/* char_linebreak • '\n' preceded by two spaces (assuming linebreak != 0) */ -static size_t -char_linebreak(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) -{ - if (offset < 2 || data[-1] != ' ' || data[-2] != ' ') - return 0; - - /* removing the last space from ob and rendering */ - while (ob->size && ob->data[ob->size - 1] == ' ') - ob->size--; - - return rndr->cb.linebreak(ob, rndr->opaque) ? 1 : 0; -} - - -/* char_codespan • '`' parsing a code span (assuming codespan != 0) */ -static size_t -char_codespan(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) -{ - size_t end, nb = 0, i, f_begin, f_end; - - /* counting the number of backticks in the delimiter */ - while (nb < size && data[nb] == '`') - nb++; - - /* finding the next delimiter */ - i = 0; - for (end = nb; end < size && i < nb; end++) { - if (data[end] == '`') i++; - else i = 0; - } - - if (i < nb && end >= size) - return 0; /* no matching delimiter */ - - /* trimming outside whitespaces */ - f_begin = nb; - while (f_begin < end && data[f_begin] == ' ') - f_begin++; - - f_end = end - nb; - while (f_end > nb && data[f_end-1] == ' ') - f_end--; - - /* real code span */ - if (f_begin < f_end) { - struct buf work = { data + f_begin, f_end - f_begin, 0, 0 }; - if (!rndr->cb.codespan(ob, &work, rndr->opaque)) - end = 0; - } else { - if (!rndr->cb.codespan(ob, 0, rndr->opaque)) - end = 0; - } - - return end; -} - - -/* char_escape • '\\' backslash escape */ -static size_t -char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) -{ - static const char *escape_chars = "\\`*_{}[]()#+-.!:|&<>^~"; - struct buf work = { 0, 0, 0, 0 }; - - if (size > 1) { - if (strchr(escape_chars, data[1]) == NULL) - return 0; - - if (rndr->cb.normal_text) { - work.data = data + 1; - work.size = 1; - rndr->cb.normal_text(ob, &work, rndr->opaque); - } - else bufputc(ob, data[1]); - } else if (size == 1) { - bufputc(ob, data[0]); - } - - return 2; -} - -/* char_entity • '&' escaped when it doesn't belong to an entity */ -/* valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; */ -static size_t -char_entity(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) -{ - size_t end = 1; - struct buf work = { 0, 0, 0, 0 }; - - if (end < size && data[end] == '#') - end++; - - while (end < size && isalnum(data[end])) - end++; - - if (end < size && data[end] == ';') - end++; /* real entity */ - else - return 0; /* lone '&' */ - - if (rndr->cb.entity) { - work.data = data; - work.size = end; - rndr->cb.entity(ob, &work, rndr->opaque); - } - else bufput(ob, data, end); - - return end; -} - -/* char_langle_tag • '<' when tags or autolinks are allowed */ -static size_t -char_langle_tag(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) -{ - enum mkd_autolink altype = MKDA_NOT_AUTOLINK; - size_t end = tag_length(data, size, &altype); - struct buf work = { data, end, 0, 0 }; - int ret = 0; - - if (end > 2) { - if (rndr->cb.autolink && altype != MKDA_NOT_AUTOLINK) { - struct buf *u_link = rndr_newbuf(rndr, BUFFER_SPAN); - work.data = data + 1; - work.size = end - 2; - unscape_text(u_link, &work); - ret = rndr->cb.autolink(ob, u_link, altype, rndr->opaque); - rndr_popbuf(rndr, BUFFER_SPAN); - } - else if (rndr->cb.raw_html_tag) - ret = rndr->cb.raw_html_tag(ob, &work, rndr->opaque); - } - - if (!ret) return 0; - else return end; -} - -static size_t -char_autolink_www(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) -{ - struct buf *link, *link_url, *link_text; - size_t link_len, rewind; - - if (!rndr->cb.link || rndr->in_link_body) - return 0; - - link = rndr_newbuf(rndr, BUFFER_SPAN); - - if ((link_len = sd_autolink__www(&rewind, link, data, offset, size, 0)) > 0) { - link_url = rndr_newbuf(rndr, BUFFER_SPAN); - BUFPUTSL(link_url, "http://"); - bufput(link_url, link->data, link->size); - - ob->size -= rewind; - if (rndr->cb.normal_text) { - link_text = rndr_newbuf(rndr, BUFFER_SPAN); - rndr->cb.normal_text(link_text, link, rndr->opaque); - rndr->cb.link(ob, link_url, NULL, link_text, rndr->opaque); - rndr_popbuf(rndr, BUFFER_SPAN); - } else { - rndr->cb.link(ob, link_url, NULL, link, rndr->opaque); - } - rndr_popbuf(rndr, BUFFER_SPAN); - } - - rndr_popbuf(rndr, BUFFER_SPAN); - return link_len; -} - -static size_t -char_autolink_email(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) -{ - struct buf *link; - size_t link_len, rewind; - - if (!rndr->cb.autolink || rndr->in_link_body) - return 0; - - link = rndr_newbuf(rndr, BUFFER_SPAN); - - if ((link_len = sd_autolink__email(&rewind, link, data, offset, size, 0)) > 0) { - ob->size -= rewind; - rndr->cb.autolink(ob, link, MKDA_EMAIL, rndr->opaque); - } - - rndr_popbuf(rndr, BUFFER_SPAN); - return link_len; -} - -static size_t -char_autolink_url(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) -{ - struct buf *link; - size_t link_len, rewind; - - if (!rndr->cb.autolink || rndr->in_link_body) - return 0; - - link = rndr_newbuf(rndr, BUFFER_SPAN); - - if ((link_len = sd_autolink__url(&rewind, link, data, offset, size, 0)) > 0) { - ob->size -= rewind; - rndr->cb.autolink(ob, link, MKDA_NORMAL, rndr->opaque); - } - - rndr_popbuf(rndr, BUFFER_SPAN); - return link_len; -} - -/* char_link • '[': parsing a link or an image */ -static size_t -char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) -{ - int is_img = (offset && data[-1] == '!'), level; - size_t i = 1, txt_e, link_b = 0, link_e = 0, title_b = 0, title_e = 0; - struct buf *content = 0; - struct buf *link = 0; - struct buf *title = 0; - struct buf *u_link = 0; - size_t org_work_size = rndr->work_bufs[BUFFER_SPAN].size; - int text_has_nl = 0, ret = 0; - int in_title = 0, qtype = 0; - - /* checking whether the correct renderer exists */ - if ((is_img && !rndr->cb.image) || (!is_img && !rndr->cb.link)) - goto cleanup; - - /* looking for the matching closing bracket */ - for (level = 1; i < size; i++) { - if (data[i] == '\n') - text_has_nl = 1; - - else if (data[i - 1] == '\\') - continue; - - else if (data[i] == '[') - level++; - - else if (data[i] == ']') { - level--; - if (level <= 0) - break; - } - } - - if (i >= size) - goto cleanup; - - txt_e = i; - i++; - - /* skip any amount of whitespace or newline */ - /* (this is much more laxist than original markdown syntax) */ - while (i < size && _isspace(data[i])) - i++; - - /* inline style link */ - if (i < size && data[i] == '(') { - /* skipping initial whitespace */ - i++; - - while (i < size && _isspace(data[i])) - i++; - - link_b = i; - - /* looking for link end: ' " ) */ - while (i < size) { - if (data[i] == '\\') i += 2; - else if (data[i] == ')') break; - else if (i >= 1 && _isspace(data[i-1]) && (data[i] == '\'' || data[i] == '"')) break; - else i++; - } - - if (i >= size) goto cleanup; - link_e = i; - - /* looking for title end if present */ - if (data[i] == '\'' || data[i] == '"') { - qtype = data[i]; - in_title = 1; - i++; - title_b = i; - - while (i < size) { - if (data[i] == '\\') i += 2; - else if (data[i] == qtype) {in_title = 0; i++;} - else if ((data[i] == ')') && !in_title) break; - else i++; - } - - if (i >= size) goto cleanup; - - /* skipping whitespaces after title */ - title_e = i - 1; - while (title_e > title_b && _isspace(data[title_e])) - title_e--; - - /* checking for closing quote presence */ - if (data[title_e] != '\'' && data[title_e] != '"') { - title_b = title_e = 0; - link_e = i; - } - } - - /* remove whitespace at the end of the link */ - while (link_e > link_b && _isspace(data[link_e - 1])) - link_e--; - - /* remove optional angle brackets around the link */ - if (data[link_b] == '<') link_b++; - if (data[link_e - 1] == '>') link_e--; - - /* building escaped link and title */ - if (link_e > link_b) { - link = rndr_newbuf(rndr, BUFFER_SPAN); - bufput(link, data + link_b, link_e - link_b); - } - - if (title_e > title_b) { - title = rndr_newbuf(rndr, BUFFER_SPAN); - bufput(title, data + title_b, title_e - title_b); - } - - i++; - } - - /* reference style link */ - else if (i < size && data[i] == '[') { - struct buf id = { 0, 0, 0, 0 }; - struct link_ref *lr; - - /* looking for the id */ - i++; - link_b = i; - while (i < size && data[i] != ']') i++; - if (i >= size) goto cleanup; - link_e = i; - - /* finding the link_ref */ - if (link_b == link_e) { - if (text_has_nl) { - struct buf *b = rndr_newbuf(rndr, BUFFER_SPAN); - size_t j; - - for (j = 1; j < txt_e; j++) { - if (data[j] != '\n') - bufputc(b, data[j]); - else if (data[j - 1] != ' ') - bufputc(b, ' '); - } - - id.data = b->data; - id.size = b->size; - } else { - id.data = data + 1; - id.size = txt_e - 1; - } - } else { - id.data = data + link_b; - id.size = link_e - link_b; - } - - lr = find_link_ref(rndr->refs, id.data, id.size); - if (!lr) - goto cleanup; - - /* keeping link and title from link_ref */ - link = lr->link; - title = lr->title; - i++; - } - - /* shortcut reference style link */ - else { - struct buf id = { 0, 0, 0, 0 }; - struct link_ref *lr; - - /* crafting the id */ - if (text_has_nl) { - struct buf *b = rndr_newbuf(rndr, BUFFER_SPAN); - size_t j; - - for (j = 1; j < txt_e; j++) { - if (data[j] != '\n') - bufputc(b, data[j]); - else if (data[j - 1] != ' ') - bufputc(b, ' '); - } - - id.data = b->data; - id.size = b->size; - } else { - id.data = data + 1; - id.size = txt_e - 1; - } - - /* finding the link_ref */ - lr = find_link_ref(rndr->refs, id.data, id.size); - if (!lr) - goto cleanup; - - /* keeping link and title from link_ref */ - link = lr->link; - title = lr->title; - - /* rewinding the whitespace */ - i = txt_e + 1; - } - - /* building content: img alt is escaped, link content is parsed */ - if (txt_e > 1) { - content = rndr_newbuf(rndr, BUFFER_SPAN); - if (is_img) { - bufput(content, data + 1, txt_e - 1); - } else { - /* disable autolinking when parsing inline the - * content of a link */ - rndr->in_link_body = 1; - parse_inline(content, rndr, data + 1, txt_e - 1); - rndr->in_link_body = 0; - } - } - - if (link) { - u_link = rndr_newbuf(rndr, BUFFER_SPAN); - unscape_text(u_link, link); - } - - /* calling the relevant rendering function */ - if (is_img) { - if (ob->size && ob->data[ob->size - 1] == '!') - ob->size -= 1; - - ret = rndr->cb.image(ob, u_link, title, content, rndr->opaque); - } else { - ret = rndr->cb.link(ob, u_link, title, content, rndr->opaque); - } - - /* cleanup */ -cleanup: - rndr->work_bufs[BUFFER_SPAN].size = (int)org_work_size; - return ret ? i : 0; -} - -static size_t -char_superscript(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) -{ - size_t sup_start, sup_len; - struct buf *sup; - - if (!rndr->cb.superscript) - return 0; - - if (size < 2) - return 0; - - if (data[1] == '(') { - sup_start = sup_len = 2; - - while (sup_len < size && data[sup_len] != ')' && data[sup_len - 1] != '\\') - sup_len++; - - if (sup_len == size) - return 0; - } else { - sup_start = sup_len = 1; - - while (sup_len < size && !_isspace(data[sup_len])) - sup_len++; - } - - if (sup_len - sup_start == 0) - return (sup_start == 2) ? 3 : 0; - - sup = rndr_newbuf(rndr, BUFFER_SPAN); - parse_inline(sup, rndr, data + sup_start, sup_len - sup_start); - rndr->cb.superscript(ob, sup, rndr->opaque); - rndr_popbuf(rndr, BUFFER_SPAN); - - return (sup_start == 2) ? sup_len + 1 : sup_len; -} - -/********************************* - * BLOCK-LEVEL PARSING FUNCTIONS * - *********************************/ - -/* is_empty • returns the line length when it is empty, 0 otherwise */ -static size_t -is_empty(uint8_t *data, size_t size) -{ - size_t i; - - for (i = 0; i < size && data[i] != '\n'; i++) - if (data[i] != ' ') - return 0; - - return i + 1; -} - -/* is_hrule • returns whether a line is a horizontal rule */ -static int -is_hrule(uint8_t *data, size_t size) -{ - size_t i = 0, n = 0; - uint8_t c; - - /* skipping initial spaces */ - if (size < 3) return 0; - if (data[0] == ' ') { i++; - if (data[1] == ' ') { i++; - if (data[2] == ' ') { i++; } } } - - /* looking at the hrule uint8_t */ - if (i + 2 >= size - || (data[i] != '*' && data[i] != '-' && data[i] != '_')) - return 0; - c = data[i]; - - /* the whole line must be the char or whitespace */ - while (i < size && data[i] != '\n') { - if (data[i] == c) n++; - else if (data[i] != ' ') - return 0; - - i++; - } - - return n >= 3; -} - -/* check if a line begins with a code fence; return the - * width of the code fence */ -static size_t -prefix_codefence(uint8_t *data, size_t size) -{ - size_t i = 0, n = 0; - uint8_t c; - - /* skipping initial spaces */ - if (size < 3) return 0; - if (data[0] == ' ') { i++; - if (data[1] == ' ') { i++; - if (data[2] == ' ') { i++; } } } - - /* looking at the hrule uint8_t */ - if (i + 2 >= size || !(data[i] == '~' || data[i] == '`')) - return 0; - - c = data[i]; - - /* the whole line must be the uint8_t or whitespace */ - while (i < size && data[i] == c) { - n++; i++; - } - - if (n < 3) - return 0; - - return i; -} - -/* check if a line is a code fence; return its size if it is */ -static size_t -is_codefence(uint8_t *data, size_t size, struct buf *syntax) -{ - size_t i = 0, syn_len = 0; - uint8_t *syn_start; - - i = prefix_codefence(data, size); - if (i == 0) - return 0; - - while (i < size && data[i] == ' ') - i++; - - syn_start = data + i; - - if (i < size && data[i] == '{') { - i++; syn_start++; - - while (i < size && data[i] != '}' && data[i] != '\n') { - syn_len++; i++; - } - - if (i == size || data[i] != '}') - return 0; - - /* strip all whitespace at the beginning and the end - * of the {} block */ - while (syn_len > 0 && _isspace(syn_start[0])) { - syn_start++; syn_len--; - } - - while (syn_len > 0 && _isspace(syn_start[syn_len - 1])) - syn_len--; - - i++; - } else { - while (i < size && !_isspace(data[i])) { - syn_len++; i++; - } - } - - if (syntax) { - syntax->data = syn_start; - syntax->size = syn_len; - } - - while (i < size && data[i] != '\n') { - if (!_isspace(data[i])) - return 0; - - i++; - } - - return i + 1; -} - -/* is_atxheader • returns whether the line is a hash-prefixed header */ -static int -is_atxheader(struct sd_markdown *rndr, uint8_t *data, size_t size) -{ - if (data[0] != '#') - return 0; - - if (rndr->ext_flags & MKDEXT_SPACE_HEADERS) { - size_t level = 0; - - while (level < size && level < 6 && data[level] == '#') - level++; - - if (level < size && data[level] != ' ') - return 0; - } - - return 1; -} - -/* is_headerline • returns whether the line is a setext-style hdr underline */ -static int -is_headerline(uint8_t *data, size_t size) -{ - size_t i = 0; - - /* test of level 1 header */ - if (data[i] == '=') { - for (i = 1; i < size && data[i] == '='; i++); - while (i < size && data[i] == ' ') i++; - return (i >= size || data[i] == '\n') ? 1 : 0; } - - /* test of level 2 header */ - if (data[i] == '-') { - for (i = 1; i < size && data[i] == '-'; i++); - while (i < size && data[i] == ' ') i++; - return (i >= size || data[i] == '\n') ? 2 : 0; } - - return 0; -} - -static int -is_next_headerline(uint8_t *data, size_t size) -{ - size_t i = 0; - - while (i < size && data[i] != '\n') - i++; - - if (++i >= size) - return 0; - - return is_headerline(data + i, size - i); -} - -/* prefix_quote • returns blockquote prefix length */ -static size_t -prefix_quote(uint8_t *data, size_t size) -{ - size_t i = 0; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - - if (i < size && data[i] == '>') { - if (i + 1 < size && data[i + 1] == ' ') - return i + 2; - - return i + 1; - } - - return 0; -} - -/* prefix_code • returns prefix length for block code*/ -static size_t -prefix_code(uint8_t *data, size_t size) -{ - if (size > 3 && data[0] == ' ' && data[1] == ' ' - && data[2] == ' ' && data[3] == ' ') return 4; - - return 0; -} - -/* prefix_oli • returns ordered list item prefix */ -static size_t -prefix_oli(uint8_t *data, size_t size) -{ - size_t i = 0; - - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - - if (i >= size || data[i] < '0' || data[i] > '9') - return 0; - - while (i < size && data[i] >= '0' && data[i] <= '9') - i++; - - if (i + 1 >= size || data[i] != '.' || data[i + 1] != ' ') - return 0; - - if (is_next_headerline(data + i, size - i)) - return 0; - - return i + 2; -} - -/* prefix_uli • returns ordered list item prefix */ -static size_t -prefix_uli(uint8_t *data, size_t size) -{ - size_t i = 0; - - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - - if (i + 1 >= size || - (data[i] != '*' && data[i] != '+' && data[i] != '-') || - data[i + 1] != ' ') - return 0; - - if (is_next_headerline(data + i, size - i)) - return 0; - - return i + 2; -} - - -/* parse_block • parsing of one block, returning next uint8_t to parse */ -static void parse_block(struct buf *ob, struct sd_markdown *rndr, - uint8_t *data, size_t size); - - -/* parse_blockquote • handles parsing of a blockquote fragment */ -static size_t -parse_blockquote(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) -{ - size_t beg, end = 0, pre, work_size = 0; - uint8_t *work_data = 0; - struct buf *out = 0; - - out = rndr_newbuf(rndr, BUFFER_BLOCK); - beg = 0; - while (beg < size) { - for (end = beg + 1; end < size && data[end - 1] != '\n'; end++); - - pre = prefix_quote(data + beg, end - beg); - - if (pre) - beg += pre; /* skipping prefix */ - - /* empty line followed by non-quote line */ - else if (is_empty(data + beg, end - beg) && - (end >= size || (prefix_quote(data + end, size - end) == 0 && - !is_empty(data + end, size - end)))) - break; - - if (beg < end) { /* copy into the in-place working buffer */ - /* bufput(work, data + beg, end - beg); */ - if (!work_data) - work_data = data + beg; - else if (data + beg != work_data + work_size) - memmove(work_data + work_size, data + beg, end - beg); - work_size += end - beg; - } - beg = end; - } - - parse_block(out, rndr, work_data, work_size); - if (rndr->cb.blockquote) - rndr->cb.blockquote(ob, out, rndr->opaque); - rndr_popbuf(rndr, BUFFER_BLOCK); - return end; -} - -static size_t -parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int do_render); - -/* parse_blockquote • handles parsing of a regular paragraph */ -static size_t -parse_paragraph(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) -{ - size_t i = 0, end = 0; - int level = 0; - struct buf work = { data, 0, 0, 0 }; - - while (i < size) { - for (end = i + 1; end < size && data[end - 1] != '\n'; end++) /* empty */; - - if (is_empty(data + i, size - i)) - break; - - if ((level = is_headerline(data + i, size - i)) != 0) - break; - - if (is_atxheader(rndr, data + i, size - i) || - is_hrule(data + i, size - i) || - prefix_quote(data + i, size - i)) { - end = i; - break; - } - - /* - * Early termination of a paragraph with the same logic - * as Markdown 1.0.0. If this logic is applied, the - * Markdown 1.0.3 test suite won't pass cleanly - * - * :: If the first character in a new line is not a letter, - * let's check to see if there's some kind of block starting - * here - */ - if ((rndr->ext_flags & MKDEXT_LAX_SPACING) && !isalnum(data[i])) { - if (prefix_oli(data + i, size - i) || - prefix_uli(data + i, size - i)) { - end = i; - break; - } - - /* see if an html block starts here */ - if (data[i] == '<' && rndr->cb.blockhtml && - parse_htmlblock(ob, rndr, data + i, size - i, 0)) { - end = i; - break; - } - - /* see if a code fence starts here */ - if ((rndr->ext_flags & MKDEXT_FENCED_CODE) != 0 && - is_codefence(data + i, size - i, NULL) != 0) { - end = i; - break; - } - } - - i = end; - } - - work.size = i; - while (work.size && data[work.size - 1] == '\n') - work.size--; - - if (!level) { - struct buf *tmp = rndr_newbuf(rndr, BUFFER_BLOCK); - parse_inline(tmp, rndr, work.data, work.size); - if (rndr->cb.paragraph) - rndr->cb.paragraph(ob, tmp, rndr->opaque); - rndr_popbuf(rndr, BUFFER_BLOCK); - } else { - struct buf *header_work; - - if (work.size) { - size_t beg; - i = work.size; - work.size -= 1; - - while (work.size && data[work.size] != '\n') - work.size -= 1; - - beg = work.size + 1; - while (work.size && data[work.size - 1] == '\n') - work.size -= 1; - - if (work.size > 0) { - struct buf *tmp = rndr_newbuf(rndr, BUFFER_BLOCK); - parse_inline(tmp, rndr, work.data, work.size); - - if (rndr->cb.paragraph) - rndr->cb.paragraph(ob, tmp, rndr->opaque); - - rndr_popbuf(rndr, BUFFER_BLOCK); - work.data += beg; - work.size = i - beg; - } - else work.size = i; - } - - header_work = rndr_newbuf(rndr, BUFFER_SPAN); - parse_inline(header_work, rndr, work.data, work.size); - - if (rndr->cb.header) - rndr->cb.header(ob, header_work, (int)level, rndr->opaque); - - rndr_popbuf(rndr, BUFFER_SPAN); - } - - return end; -} - -/* parse_fencedcode • handles parsing of a block-level code fragment */ -static size_t -parse_fencedcode(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) -{ - size_t beg, end; - struct buf *work = 0; - struct buf lang = { 0, 0, 0, 0 }; - - beg = is_codefence(data, size, &lang); - if (beg == 0) return 0; - - work = rndr_newbuf(rndr, BUFFER_BLOCK); - - while (beg < size) { - size_t fence_end; - struct buf fence_trail = { 0, 0, 0, 0 }; - - fence_end = is_codefence(data + beg, size - beg, &fence_trail); - if (fence_end != 0 && fence_trail.size == 0) { - beg += fence_end; - break; - } - - for (end = beg + 1; end < size && data[end - 1] != '\n'; end++); - - if (beg < end) { - /* verbatim copy to the working buffer, - escaping entities */ - if (is_empty(data + beg, end - beg)) - bufputc(work, '\n'); - else bufput(work, data + beg, end - beg); - } - beg = end; - } - - if (work->size && work->data[work->size - 1] != '\n') - bufputc(work, '\n'); - - if (rndr->cb.blockcode) - rndr->cb.blockcode(ob, work, lang.size ? &lang : NULL, rndr->opaque); - - rndr_popbuf(rndr, BUFFER_BLOCK); - return beg; -} - -static size_t -parse_blockcode(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) -{ - size_t beg, end, pre; - struct buf *work = 0; - - work = rndr_newbuf(rndr, BUFFER_BLOCK); - - beg = 0; - while (beg < size) { - for (end = beg + 1; end < size && data[end - 1] != '\n'; end++) {}; - pre = prefix_code(data + beg, end - beg); - - if (pre) - beg += pre; /* skipping prefix */ - else if (!is_empty(data + beg, end - beg)) - /* non-empty non-prefixed line breaks the pre */ - break; - - if (beg < end) { - /* verbatim copy to the working buffer, - escaping entities */ - if (is_empty(data + beg, end - beg)) - bufputc(work, '\n'); - else bufput(work, data + beg, end - beg); - } - beg = end; - } - - while (work->size && work->data[work->size - 1] == '\n') - work->size -= 1; - - bufputc(work, '\n'); - - if (rndr->cb.blockcode) - rndr->cb.blockcode(ob, work, NULL, rndr->opaque); - - rndr_popbuf(rndr, BUFFER_BLOCK); - return beg; -} - -/* parse_listitem • parsing of a single list item */ -/* assuming initial prefix is already removed */ -static size_t -parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int *flags) -{ - struct buf *work = 0, *inter = 0; - size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i; - int in_empty = 0, has_inside_empty = 0, in_fence = 0; - - /* keeping track of the first indentation prefix */ - while (orgpre < 3 && orgpre < size && data[orgpre] == ' ') - orgpre++; - - beg = prefix_uli(data, size); - if (!beg) - beg = prefix_oli(data, size); - - if (!beg) - return 0; - - /* skipping to the beginning of the following line */ - end = beg; - while (end < size && data[end - 1] != '\n') - end++; - - /* getting working buffers */ - work = rndr_newbuf(rndr, BUFFER_SPAN); - inter = rndr_newbuf(rndr, BUFFER_SPAN); - - /* putting the first line into the working buffer */ - bufput(work, data + beg, end - beg); - beg = end; - - /* process the following lines */ - while (beg < size) { - size_t has_next_uli = 0, has_next_oli = 0; - - end++; - - while (end < size && data[end - 1] != '\n') - end++; - - /* process an empty line */ - if (is_empty(data + beg, end - beg)) { - in_empty = 1; - beg = end; - continue; - } - - /* calculating the indentation */ - i = 0; - while (i < 4 && beg + i < end && data[beg + i] == ' ') - i++; - - pre = i; - - if (rndr->ext_flags & MKDEXT_FENCED_CODE) { - if (is_codefence(data + beg + i, end - beg - i, NULL) != 0) - in_fence = !in_fence; - } - - /* Only check for new list items if we are **not** inside - * a fenced code block */ - if (!in_fence) { - has_next_uli = prefix_uli(data + beg + i, end - beg - i); - has_next_oli = prefix_oli(data + beg + i, end - beg - i); - } - - /* checking for ul/ol switch */ - if (in_empty && ( - ((*flags & MKD_LIST_ORDERED) && has_next_uli) || - (!(*flags & MKD_LIST_ORDERED) && has_next_oli))){ - *flags |= MKD_LI_END; - break; /* the following item must have same list type */ - } - - /* checking for a new item */ - if ((has_next_uli && !is_hrule(data + beg + i, end - beg - i)) || has_next_oli) { - if (in_empty) - has_inside_empty = 1; - - if (pre == orgpre) /* the following item must have */ - break; /* the same indentation */ - - if (!sublist) - sublist = work->size; - } - /* joining only indented stuff after empty lines; - * note that now we only require 1 space of indentation - * to continue a list */ - else if (in_empty && pre == 0) { - *flags |= MKD_LI_END; - break; - } - else if (in_empty) { - bufputc(work, '\n'); - has_inside_empty = 1; - } - - in_empty = 0; - - /* adding the line without prefix into the working buffer */ - bufput(work, data + beg + i, end - beg - i); - beg = end; - } - - /* render of li contents */ - if (has_inside_empty) - *flags |= MKD_LI_BLOCK; - - if (*flags & MKD_LI_BLOCK) { - /* intermediate render of block li */ - if (sublist && sublist < work->size) { - parse_block(inter, rndr, work->data, sublist); - parse_block(inter, rndr, work->data + sublist, work->size - sublist); - } - else - parse_block(inter, rndr, work->data, work->size); - } else { - /* intermediate render of inline li */ - if (sublist && sublist < work->size) { - parse_inline(inter, rndr, work->data, sublist); - parse_block(inter, rndr, work->data + sublist, work->size - sublist); - } - else - parse_inline(inter, rndr, work->data, work->size); - } - - /* render of li itself */ - if (rndr->cb.listitem) - rndr->cb.listitem(ob, inter, *flags, rndr->opaque); - - rndr_popbuf(rndr, BUFFER_SPAN); - rndr_popbuf(rndr, BUFFER_SPAN); - return beg; -} - - -/* parse_list • parsing ordered or unordered list block */ -static size_t -parse_list(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int flags) -{ - struct buf *work = 0; - size_t i = 0, j; - - work = rndr_newbuf(rndr, BUFFER_BLOCK); - - while (i < size) { - j = parse_listitem(work, rndr, data + i, size - i, &flags); - i += j; - - if (!j || (flags & MKD_LI_END)) - break; - } - - if (rndr->cb.list) - rndr->cb.list(ob, work, flags, rndr->opaque); - rndr_popbuf(rndr, BUFFER_BLOCK); - return i; -} - -/* parse_atxheader • parsing of atx-style headers */ -static size_t -parse_atxheader(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) -{ - size_t level = 0; - size_t i, end, skip; - - while (level < size && level < 6 && data[level] == '#') - level++; - - for (i = level; i < size && data[i] == ' '; i++); - - for (end = i; end < size && data[end] != '\n'; end++); - skip = end; - - while (end && data[end - 1] == '#') - end--; - - while (end && data[end - 1] == ' ') - end--; - - if (end > i) { - struct buf *work = rndr_newbuf(rndr, BUFFER_SPAN); - - parse_inline(work, rndr, data + i, end - i); - - if (rndr->cb.header) - rndr->cb.header(ob, work, (int)level, rndr->opaque); - - rndr_popbuf(rndr, BUFFER_SPAN); - } - - return skip; -} - - -/* htmlblock_end • checking end of HTML block : [ \t]*\n[ \t*]\n */ -/* returns the length on match, 0 otherwise */ -static size_t -htmlblock_end_tag( - const char *tag, - size_t tag_len, - struct sd_markdown *rndr, - uint8_t *data, - size_t size) -{ - size_t i, w; - - /* checking if tag is a match */ - if (tag_len + 3 >= size || - strncasecmp((char *)data + 2, tag, tag_len) != 0 || - data[tag_len + 2] != '>') - return 0; - - /* checking white lines */ - i = tag_len + 3; - w = 0; - if (i < size && (w = is_empty(data + i, size - i)) == 0) - return 0; /* non-blank after tag */ - i += w; - w = 0; - - if (i < size) - w = is_empty(data + i, size - i); - - return i + w; -} - -static size_t -htmlblock_end(const char *curtag, - struct sd_markdown *rndr, - uint8_t *data, - size_t size, - int start_of_line) -{ - size_t tag_size = strlen(curtag); - size_t i = 1, end_tag; - int block_lines = 0; - - while (i < size) { - i++; - while (i < size && !(data[i - 1] == '<' && data[i] == '/')) { - if (data[i] == '\n') - block_lines++; - - i++; - } - - /* If we are only looking for unindented tags, skip the tag - * if it doesn't follow a newline. - * - * The only exception to this is if the tag is still on the - * initial line; in that case it still counts as a closing - * tag - */ - if (start_of_line && block_lines > 0 && data[i - 2] != '\n') - continue; - - if (i + 2 + tag_size >= size) - break; - - end_tag = htmlblock_end_tag(curtag, tag_size, rndr, data + i - 1, size - i + 1); - if (end_tag) - return i + end_tag - 1; - } - - return 0; -} - - -/* parse_htmlblock • parsing of inline HTML block */ -static size_t -parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int do_render) -{ - size_t i, j = 0, tag_end; - const char *curtag = NULL; - struct buf work = { data, 0, 0, 0 }; - - /* identification of the opening tag */ - if (size < 2 || data[0] != '<') - return 0; - - i = 1; - while (i < size && data[i] != '>' && data[i] != ' ') - i++; - - if (i < size) - curtag = find_block_tag((char *)data + 1, (int)i - 1); - - /* handling of special cases */ - if (!curtag) { - - /* HTML comment, laxist form */ - if (size > 5 && data[1] == '!' && data[2] == '-' && data[3] == '-') { - i = 5; - - while (i < size && !(data[i - 2] == '-' && data[i - 1] == '-' && data[i] == '>')) - i++; - - i++; - - if (i < size) - j = is_empty(data + i, size - i); - - if (j) { - work.size = i + j; - if (do_render && rndr->cb.blockhtml) - rndr->cb.blockhtml(ob, &work, rndr->opaque); - return work.size; - } - } - - /* HR, which is the only self-closing block tag considered */ - if (size > 4 && (data[1] == 'h' || data[1] == 'H') && (data[2] == 'r' || data[2] == 'R')) { - i = 3; - while (i < size && data[i] != '>') - i++; - - if (i + 1 < size) { - i++; - j = is_empty(data + i, size - i); - if (j) { - work.size = i + j; - if (do_render && rndr->cb.blockhtml) - rndr->cb.blockhtml(ob, &work, rndr->opaque); - return work.size; - } - } - } - - /* no special case recognised */ - return 0; - } - - /* looking for an unindented matching closing tag */ - /* followed by a blank line */ - tag_end = htmlblock_end(curtag, rndr, data, size, 1); - - /* if not found, trying a second pass looking for indented match */ - /* but not if tag is "ins" or "del" (following original Markdown.pl) */ - if (!tag_end && strcmp(curtag, "ins") != 0 && strcmp(curtag, "del") != 0) { - tag_end = htmlblock_end(curtag, rndr, data, size, 0); - } - - if (!tag_end) - return 0; - - /* the end of the block has been found */ - work.size = tag_end; - if (do_render && rndr->cb.blockhtml) - rndr->cb.blockhtml(ob, &work, rndr->opaque); - - return tag_end; -} - -static void -parse_table_row( - struct buf *ob, - struct sd_markdown *rndr, - uint8_t *data, - size_t size, - size_t columns, - int *col_data, - int header_flag) -{ - size_t i = 0, col; - struct buf *row_work = 0; - - if (!rndr->cb.table_cell || !rndr->cb.table_row) - return; - - row_work = rndr_newbuf(rndr, BUFFER_SPAN); - - if (i < size && data[i] == '|') - i++; - - for (col = 0; col < columns && i < size; ++col) { - size_t cell_start, cell_end; - struct buf *cell_work; - - cell_work = rndr_newbuf(rndr, BUFFER_SPAN); - - while (i < size && _isspace(data[i])) - i++; - - cell_start = i; - - while (i < size && data[i] != '|') - i++; - - cell_end = i - 1; - - while (cell_end > cell_start && _isspace(data[cell_end])) - cell_end--; - - parse_inline(cell_work, rndr, data + cell_start, 1 + cell_end - cell_start); - rndr->cb.table_cell(row_work, cell_work, col_data[col] | header_flag, rndr->opaque); - - rndr_popbuf(rndr, BUFFER_SPAN); - i++; - } - - for (; col < columns; ++col) { - struct buf empty_cell = { 0, 0, 0, 0 }; - rndr->cb.table_cell(row_work, &empty_cell, col_data[col] | header_flag, rndr->opaque); - } - - rndr->cb.table_row(ob, row_work, rndr->opaque); - - rndr_popbuf(rndr, BUFFER_SPAN); -} - -static size_t -parse_table_header( - struct buf *ob, - struct sd_markdown *rndr, - uint8_t *data, - size_t size, - size_t *columns, - int **column_data) -{ - int pipes; - size_t i = 0, col, header_end, under_end; - - pipes = 0; - while (i < size && data[i] != '\n') - if (data[i++] == '|') - pipes++; - - if (i == size || pipes == 0) - return 0; - - header_end = i; - - while (header_end > 0 && _isspace(data[header_end - 1])) - header_end--; - - if (data[0] == '|') - pipes--; - - if (header_end && data[header_end - 1] == '|') - pipes--; - - *columns = pipes + 1; - *column_data = calloc(*columns, sizeof(int)); - - /* Parse the header underline */ - i++; - if (i < size && data[i] == '|') - i++; - - under_end = i; - while (under_end < size && data[under_end] != '\n') - under_end++; - - for (col = 0; col < *columns && i < under_end; ++col) { - size_t dashes = 0; - - while (i < under_end && data[i] == ' ') - i++; - - if (data[i] == ':') { - i++; (*column_data)[col] |= MKD_TABLE_ALIGN_L; - dashes++; - } - - while (i < under_end && data[i] == '-') { - i++; dashes++; - } - - if (i < under_end && data[i] == ':') { - i++; (*column_data)[col] |= MKD_TABLE_ALIGN_R; - dashes++; - } - - while (i < under_end && data[i] == ' ') - i++; - - if (i < under_end && data[i] != '|') - break; - - if (dashes < 3) - break; - - i++; - } - - if (col < *columns) - return 0; - - parse_table_row( - ob, rndr, data, - header_end, - *columns, - *column_data, - MKD_TABLE_HEADER - ); - - return under_end + 1; -} - -static size_t -parse_table( - struct buf *ob, - struct sd_markdown *rndr, - uint8_t *data, - size_t size) -{ - size_t i; - - struct buf *header_work = 0; - struct buf *body_work = 0; - - size_t columns; - int *col_data = NULL; - - header_work = rndr_newbuf(rndr, BUFFER_SPAN); - body_work = rndr_newbuf(rndr, BUFFER_BLOCK); - - i = parse_table_header(header_work, rndr, data, size, &columns, &col_data); - if (i > 0) { - - while (i < size) { - size_t row_start; - int pipes = 0; - - row_start = i; - - while (i < size && data[i] != '\n') - if (data[i++] == '|') - pipes++; - - if (pipes == 0 || i == size) { - i = row_start; - break; - } - - parse_table_row( - body_work, - rndr, - data + row_start, - i - row_start, - columns, - col_data, 0 - ); - - i++; - } - - if (rndr->cb.table) - rndr->cb.table(ob, header_work, body_work, rndr->opaque); - } - - free(col_data); - rndr_popbuf(rndr, BUFFER_SPAN); - rndr_popbuf(rndr, BUFFER_BLOCK); - return i; -} - -/* parse_block • parsing of one block, returning next uint8_t to parse */ -static void -parse_block(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) -{ - size_t beg, end, i; - uint8_t *txt_data; - beg = 0; - - if (rndr->work_bufs[BUFFER_SPAN].size + - rndr->work_bufs[BUFFER_BLOCK].size > rndr->max_nesting) - return; - - while (beg < size) { - txt_data = data + beg; - end = size - beg; - - if (is_atxheader(rndr, txt_data, end)) - beg += parse_atxheader(ob, rndr, txt_data, end); - - else if (data[beg] == '<' && rndr->cb.blockhtml && - (i = parse_htmlblock(ob, rndr, txt_data, end, 1)) != 0) - beg += i; - - else if ((i = is_empty(txt_data, end)) != 0) - beg += i; - - else if (is_hrule(txt_data, end)) { - if (rndr->cb.hrule) - rndr->cb.hrule(ob, rndr->opaque); - - while (beg < size && data[beg] != '\n') - beg++; - - beg++; - } - - else if ((rndr->ext_flags & MKDEXT_FENCED_CODE) != 0 && - (i = parse_fencedcode(ob, rndr, txt_data, end)) != 0) - beg += i; - - else if ((rndr->ext_flags & MKDEXT_TABLES) != 0 && - (i = parse_table(ob, rndr, txt_data, end)) != 0) - beg += i; - - else if (prefix_quote(txt_data, end)) - beg += parse_blockquote(ob, rndr, txt_data, end); - - else if (prefix_code(txt_data, end)) - beg += parse_blockcode(ob, rndr, txt_data, end); - - else if (prefix_uli(txt_data, end)) - beg += parse_list(ob, rndr, txt_data, end, 0); - - else if (prefix_oli(txt_data, end)) - beg += parse_list(ob, rndr, txt_data, end, MKD_LIST_ORDERED); - - else - beg += parse_paragraph(ob, rndr, txt_data, end); - } -} - - - -/********************* - * REFERENCE PARSING * - *********************/ - -/* is_ref • returns whether a line is a reference or not */ -static int -is_ref(const uint8_t *data, size_t beg, size_t end, size_t *last, struct link_ref **refs) -{ -/* int n; */ - size_t i = 0; - size_t id_offset, id_end; - size_t link_offset, link_end; - size_t title_offset, title_end; - size_t line_end; - - /* up to 3 optional leading spaces */ - if (beg + 3 >= end) return 0; - if (data[beg] == ' ') { i = 1; - if (data[beg + 1] == ' ') { i = 2; - if (data[beg + 2] == ' ') { i = 3; - if (data[beg + 3] == ' ') return 0; } } } - i += beg; - - /* id part: anything but a newline between brackets */ - if (data[i] != '[') return 0; - i++; - id_offset = i; - while (i < end && data[i] != '\n' && data[i] != '\r' && data[i] != ']') - i++; - if (i >= end || data[i] != ']') return 0; - id_end = i; - - /* spacer: colon (space | tab)* newline? (space | tab)* */ - i++; - if (i >= end || data[i] != ':') return 0; - i++; - while (i < end && data[i] == ' ') i++; - if (i < end && (data[i] == '\n' || data[i] == '\r')) { - i++; - if (i < end && data[i] == '\r' && data[i - 1] == '\n') i++; } - while (i < end && data[i] == ' ') i++; - if (i >= end) return 0; - - /* link: whitespace-free sequence, optionally between angle brackets */ - if (data[i] == '<') - i++; - - link_offset = i; - - while (i < end && data[i] != ' ' && data[i] != '\n' && data[i] != '\r') - i++; - - if (data[i - 1] == '>') link_end = i - 1; - else link_end = i; - - /* optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) */ - while (i < end && data[i] == ' ') i++; - if (i < end && data[i] != '\n' && data[i] != '\r' - && data[i] != '\'' && data[i] != '"' && data[i] != '(') - return 0; - line_end = 0; - /* computing end-of-line */ - if (i >= end || data[i] == '\r' || data[i] == '\n') line_end = i; - if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') - line_end = i + 1; - - /* optional (space|tab)* spacer after a newline */ - if (line_end) { - i = line_end + 1; - while (i < end && data[i] == ' ') i++; } - - /* optional title: any non-newline sequence enclosed in '"() - alone on its line */ - title_offset = title_end = 0; - if (i + 1 < end - && (data[i] == '\'' || data[i] == '"' || data[i] == '(')) { - i++; - title_offset = i; - /* looking for EOL */ - while (i < end && data[i] != '\n' && data[i] != '\r') i++; - if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') - title_end = i + 1; - else title_end = i; - /* stepping back */ - i -= 1; - while (i > title_offset && data[i] == ' ') - i -= 1; - if (i > title_offset - && (data[i] == '\'' || data[i] == '"' || data[i] == ')')) { - line_end = title_end; - title_end = i; } } - - if (!line_end || link_end == link_offset) - return 0; /* garbage after the link empty link */ - - /* a valid ref has been found, filling-in return structures */ - if (last) - *last = line_end; - - if (refs) { - struct link_ref *ref; - - ref = add_link_ref(refs, data + id_offset, id_end - id_offset); - if (!ref) - return 0; - - ref->link = bufnew(link_end - link_offset); - bufput(ref->link, data + link_offset, link_end - link_offset); - - if (title_end > title_offset) { - ref->title = bufnew(title_end - title_offset); - bufput(ref->title, data + title_offset, title_end - title_offset); - } - } - - return 1; -} - -static void expand_tabs(struct buf *ob, const uint8_t *line, size_t size) -{ - size_t i = 0, tab = 0; - - while (i < size) { - size_t org = i; - - while (i < size && line[i] != '\t') { - i++; tab++; - } - - if (i > org) - bufput(ob, line + org, i - org); - - if (i >= size) - break; - - do { - bufputc(ob, ' '); tab++; - } while (tab % 4); - - i++; - } -} - -/********************** - * EXPORTED FUNCTIONS * - **********************/ - -struct sd_markdown * -sd_markdown_new( - unsigned int extensions, - size_t max_nesting, - const struct sd_callbacks *callbacks, - void *opaque) -{ - struct sd_markdown *md = NULL; - - assert(max_nesting > 0 && callbacks); - - md = malloc(sizeof(struct sd_markdown)); - if (!md) - return NULL; - - memcpy(&md->cb, callbacks, sizeof(struct sd_callbacks)); - - stack_init(&md->work_bufs[BUFFER_BLOCK], 4); - stack_init(&md->work_bufs[BUFFER_SPAN], 8); - - memset(md->active_char, 0x0, 256); - - if (md->cb.emphasis || md->cb.double_emphasis || md->cb.triple_emphasis) { - md->active_char['*'] = MD_CHAR_EMPHASIS; - md->active_char['_'] = MD_CHAR_EMPHASIS; - if (extensions & MKDEXT_STRIKETHROUGH) - md->active_char['~'] = MD_CHAR_EMPHASIS; - } - - if (md->cb.codespan) - md->active_char['`'] = MD_CHAR_CODESPAN; - - if (md->cb.linebreak) - md->active_char['\n'] = MD_CHAR_LINEBREAK; - - if (md->cb.image || md->cb.link) - md->active_char['['] = MD_CHAR_LINK; - - md->active_char['<'] = MD_CHAR_LANGLE; - md->active_char['\\'] = MD_CHAR_ESCAPE; - md->active_char['&'] = MD_CHAR_ENTITITY; - - if (extensions & MKDEXT_AUTOLINK) { - md->active_char[':'] = MD_CHAR_AUTOLINK_URL; - md->active_char['@'] = MD_CHAR_AUTOLINK_EMAIL; - md->active_char['w'] = MD_CHAR_AUTOLINK_WWW; - } - - if (extensions & MKDEXT_SUPERSCRIPT) - md->active_char['^'] = MD_CHAR_SUPERSCRIPT; - - /* Extension data */ - md->ext_flags = extensions; - md->opaque = opaque; - md->max_nesting = max_nesting; - md->in_link_body = 0; - - return md; -} - -void -sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, struct sd_markdown *md) -{ -#define MARKDOWN_GROW(x) ((x) + ((x) >> 1)) - static const char UTF8_BOM[] = {0xEF, 0xBB, 0xBF}; - - struct buf *text; - size_t beg, end; - - text = bufnew(64); - if (!text) - return; - - /* Preallocate enough space for our buffer to avoid expanding while copying */ - bufgrow(text, doc_size); - - /* reset the references table */ - memset(&md->refs, 0x0, REF_TABLE_SIZE * sizeof(void *)); - - /* first pass: looking for references, copying everything else */ - beg = 0; - - /* Skip a possible UTF-8 BOM, even though the Unicode standard - * discourages having these in UTF-8 documents */ - if (doc_size >= 3 && memcmp(document, UTF8_BOM, 3) == 0) - beg += 3; - - while (beg < doc_size) /* iterating over lines */ - if (is_ref(document, beg, doc_size, &end, md->refs)) - beg = end; - else { /* skipping to the next line */ - end = beg; - while (end < doc_size && document[end] != '\n' && document[end] != '\r') - end++; - - /* adding the line body if present */ - if (end > beg) - expand_tabs(text, document + beg, end - beg); - - while (end < doc_size && (document[end] == '\n' || document[end] == '\r')) { - /* add one \n per newline */ - if (document[end] == '\n' || (end + 1 < doc_size && document[end + 1] != '\n')) - bufputc(text, '\n'); - end++; - } - - beg = end; - } - - /* pre-grow the output buffer to minimize allocations */ - bufgrow(ob, MARKDOWN_GROW(text->size)); - - /* second pass: actual rendering */ - if (md->cb.doc_header) - md->cb.doc_header(ob, md->opaque); - - if (text->size) { - /* adding a final newline if not already present */ - if (text->data[text->size - 1] != '\n' && text->data[text->size - 1] != '\r') - bufputc(text, '\n'); - - parse_block(ob, md, text->data, text->size); - } - - if (md->cb.doc_footer) - md->cb.doc_footer(ob, md->opaque); - - /* clean-up */ - bufrelease(text); - free_link_refs(md->refs); - - assert(md->work_bufs[BUFFER_SPAN].size == 0); - assert(md->work_bufs[BUFFER_BLOCK].size == 0); -} - -void -sd_markdown_free(struct sd_markdown *md) -{ - size_t i; - - for (i = 0; i < (size_t)md->work_bufs[BUFFER_SPAN].asize; ++i) - bufrelease(md->work_bufs[BUFFER_SPAN].item[i]); - - for (i = 0; i < (size_t)md->work_bufs[BUFFER_BLOCK].asize; ++i) - bufrelease(md->work_bufs[BUFFER_BLOCK].item[i]); - - stack_free(&md->work_bufs[BUFFER_SPAN]); - stack_free(&md->work_bufs[BUFFER_BLOCK]); - - free(md); -} - -void -sd_version(int *ver_major, int *ver_minor, int *ver_revision) -{ - *ver_major = SUNDOWN_VER_MAJOR; - *ver_minor = SUNDOWN_VER_MINOR; - *ver_revision = SUNDOWN_VER_REVISION; -} - -/* vim: set filetype=c: */ diff --git a/src/rt/sundown/src/markdown.h b/src/rt/sundown/src/markdown.h deleted file mode 100644 index 6f6553ec87d..00000000000 --- a/src/rt/sundown/src/markdown.h +++ /dev/null @@ -1,138 +0,0 @@ -/* markdown.h - generic markdown parser */ - -/* - * Copyright (c) 2009, Natacha Porté - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef UPSKIRT_MARKDOWN_H -#define UPSKIRT_MARKDOWN_H - -#include "buffer.h" -#include "autolink.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define SUNDOWN_VERSION "1.16.0" -#define SUNDOWN_VER_MAJOR 1 -#define SUNDOWN_VER_MINOR 16 -#define SUNDOWN_VER_REVISION 0 - -/******************** - * TYPE DEFINITIONS * - ********************/ - -/* mkd_autolink - type of autolink */ -enum mkd_autolink { - MKDA_NOT_AUTOLINK, /* used internally when it is not an autolink*/ - MKDA_NORMAL, /* normal http/http/ftp/mailto/etc link */ - MKDA_EMAIL, /* e-mail link without explit mailto: */ -}; - -enum mkd_tableflags { - MKD_TABLE_ALIGN_L = 1, - MKD_TABLE_ALIGN_R = 2, - MKD_TABLE_ALIGN_CENTER = 3, - MKD_TABLE_ALIGNMASK = 3, - MKD_TABLE_HEADER = 4 -}; - -enum mkd_extensions { - MKDEXT_NO_INTRA_EMPHASIS = (1 << 0), - MKDEXT_TABLES = (1 << 1), - MKDEXT_FENCED_CODE = (1 << 2), - MKDEXT_AUTOLINK = (1 << 3), - MKDEXT_STRIKETHROUGH = (1 << 4), - MKDEXT_SPACE_HEADERS = (1 << 6), - MKDEXT_SUPERSCRIPT = (1 << 7), - MKDEXT_LAX_SPACING = (1 << 8), -}; - -/* sd_callbacks - functions for rendering parsed data */ -struct sd_callbacks { - /* block level callbacks - NULL skips the block */ - void (*blockcode)(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque); - void (*blockquote)(struct buf *ob, const struct buf *text, void *opaque); - void (*blockhtml)(struct buf *ob,const struct buf *text, void *opaque); - void (*header)(struct buf *ob, const struct buf *text, int level, void *opaque); - void (*hrule)(struct buf *ob, void *opaque); - void (*list)(struct buf *ob, const struct buf *text, int flags, void *opaque); - void (*listitem)(struct buf *ob, const struct buf *text, int flags, void *opaque); - void (*paragraph)(struct buf *ob, const struct buf *text, void *opaque); - void (*table)(struct buf *ob, const struct buf *header, const struct buf *body, void *opaque); - void (*table_row)(struct buf *ob, const struct buf *text, void *opaque); - void (*table_cell)(struct buf *ob, const struct buf *text, int flags, void *opaque); - - - /* span level callbacks - NULL or return 0 prints the span verbatim */ - int (*autolink)(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque); - int (*codespan)(struct buf *ob, const struct buf *text, void *opaque); - int (*double_emphasis)(struct buf *ob, const struct buf *text, void *opaque); - int (*emphasis)(struct buf *ob, const struct buf *text, void *opaque); - int (*image)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque); - int (*linebreak)(struct buf *ob, void *opaque); - int (*link)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque); - int (*raw_html_tag)(struct buf *ob, const struct buf *tag, void *opaque); - int (*triple_emphasis)(struct buf *ob, const struct buf *text, void *opaque); - int (*strikethrough)(struct buf *ob, const struct buf *text, void *opaque); - int (*superscript)(struct buf *ob, const struct buf *text, void *opaque); - - /* low level callbacks - NULL copies input directly into the output */ - void (*entity)(struct buf *ob, const struct buf *entity, void *opaque); - void (*normal_text)(struct buf *ob, const struct buf *text, void *opaque); - - /* header and footer */ - void (*doc_header)(struct buf *ob, void *opaque); - void (*doc_footer)(struct buf *ob, void *opaque); -}; - -struct sd_markdown; - -/********* - * FLAGS * - *********/ - -/* list/listitem flags */ -#define MKD_LIST_ORDERED 1 -#define MKD_LI_BLOCK 2 /*
  • containing block data */ - -/********************** - * EXPORTED FUNCTIONS * - **********************/ - -extern struct sd_markdown * -sd_markdown_new( - unsigned int extensions, - size_t max_nesting, - const struct sd_callbacks *callbacks, - void *opaque); - -extern void -sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, struct sd_markdown *md); - -extern void -sd_markdown_free(struct sd_markdown *md); - -extern void -sd_version(int *major, int *minor, int *revision); - -#ifdef __cplusplus -} -#endif - -#endif - -/* vim: set filetype=c: */ diff --git a/src/rt/sundown/src/stack.c b/src/rt/sundown/src/stack.c deleted file mode 100644 index ce069ff3b9d..00000000000 --- a/src/rt/sundown/src/stack.c +++ /dev/null @@ -1,81 +0,0 @@ -#include "stack.h" -#include - -int -stack_grow(struct stack *st, size_t new_size) -{ - void **new_st; - - if (st->asize >= new_size) - return 0; - - new_st = realloc(st->item, new_size * sizeof(void *)); - if (new_st == NULL) - return -1; - - memset(new_st + st->asize, 0x0, - (new_size - st->asize) * sizeof(void *)); - - st->item = new_st; - st->asize = new_size; - - if (st->size > new_size) - st->size = new_size; - - return 0; -} - -void -stack_free(struct stack *st) -{ - if (!st) - return; - - free(st->item); - - st->item = NULL; - st->size = 0; - st->asize = 0; -} - -int -stack_init(struct stack *st, size_t initial_size) -{ - st->item = NULL; - st->size = 0; - st->asize = 0; - - if (!initial_size) - initial_size = 8; - - return stack_grow(st, initial_size); -} - -void * -stack_pop(struct stack *st) -{ - if (!st->size) - return NULL; - - return st->item[--st->size]; -} - -int -stack_push(struct stack *st, void *item) -{ - if (stack_grow(st, st->size * 2) < 0) - return -1; - - st->item[st->size++] = item; - return 0; -} - -void * -stack_top(struct stack *st) -{ - if (!st->size) - return NULL; - - return st->item[st->size - 1]; -} - diff --git a/src/rt/sundown/src/stack.h b/src/rt/sundown/src/stack.h deleted file mode 100644 index 08ff030a33b..00000000000 --- a/src/rt/sundown/src/stack.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef STACK_H__ -#define STACK_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct stack { - void **item; - size_t size; - size_t asize; -}; - -void stack_free(struct stack *); -int stack_grow(struct stack *, size_t); -int stack_init(struct stack *, size_t); - -int stack_push(struct stack *, void *); - -void *stack_pop(struct stack *); -void *stack_top(struct stack *); - -#ifdef __cplusplus -} -#endif - -#endif From 15856139e4e1ebbbf0a2a2d90996dff7d837cdd7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 2 May 2014 19:56:19 -0700 Subject: [PATCH 10/12] rustdoc: Enable the footnote markdown extension This enables hoedown's footnote extension, and fixes all footnotes in the reference manual to use the new syntax. --- mk/tests.mk | 9 +++-- src/doc/rust.md | 69 +++++++++++++++++++++------------ src/librustdoc/html/markdown.rs | 18 +++++---- 3 files changed, 59 insertions(+), 37 deletions(-) diff --git a/mk/tests.mk b/mk/tests.mk index d97a3799bd0..4ddb607c8bc 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -220,8 +220,8 @@ ALL_CS := $(wildcard $(S)src/rt/*.cpp \ $(S)src/rt/*/*/*.cpp \ $(S)src/rustllvm/*.cpp) ALL_CS := $(filter-out $(S)src/rt/miniz.cpp \ - $(wildcard $(S)src/rt/sundown/src/*.c) \ - $(wildcard $(S)src/rt/sundown/html/*.c) \ + $(wildcard $(S)src/rt/hoedown/src/*.c) \ + $(wildcard $(S)src/rt/hoedown/bin/*.c) \ ,$(ALL_CS)) ALL_HS := $(wildcard $(S)src/rt/*.h \ $(S)src/rt/*/*.h \ @@ -232,8 +232,8 @@ ALL_HS := $(filter-out $(S)src/rt/vg/valgrind.h \ $(S)src/rt/msvc/typeof.h \ $(S)src/rt/msvc/stdint.h \ $(S)src/rt/msvc/inttypes.h \ - $(wildcard $(S)src/rt/sundown/src/*.h) \ - $(wildcard $(S)src/rt/sundown/html/*.h) \ + $(wildcard $(S)src/rt/hoedown/src/*.h) \ + $(wildcard $(S)src/rt/hoedown/bin/*.h) \ ,$(ALL_HS)) # Run the tidy script in multiple parts to avoid huge 'echo' commands @@ -266,6 +266,7 @@ tidy: -and -not -name '*.sh' \ | grep '^$(S)src/llvm' -v \ | grep '^$(S)src/libuv' -v \ + | grep '^$(S)src/rt/hoedown' -v \ | grep '^$(S)src/gyp' -v \ | grep '^$(S)src/etc' -v \ | grep '^$(S)src/doc' -v \ diff --git a/src/doc/rust.md b/src/doc/rust.md index 99b3d516af5..11875560080 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -116,8 +116,12 @@ production. See [tokens](#tokens) for more information. Rust input is interpreted as a sequence of Unicode codepoints encoded in UTF-8, normalized to Unicode normalization form NFKC. Most Rust grammar rules are defined in terms of printable ASCII-range codepoints, -but a small number are defined in terms of Unicode properties or explicit codepoint lists. -^[Substitute definitions for the special Unicode productions are provided to the grammar verifier, restricted to ASCII range, when verifying the grammar in this document.] +but a small number are defined in terms of Unicode properties or explicit +codepoint lists. [^inputformat] + +[^inputformat]: Substitute definitions for the special Unicode productions are + provided to the grammar verifier, restricted to ASCII range, when verifying + the grammar in this document. ## Special Unicode Productions @@ -631,10 +635,13 @@ Semantic rules called "dynamic semantics" govern the behavior of programs at run A program that fails to compile due to violation of a compile-time rule has no defined dynamic semantics; the compiler should halt with an error report, and produce no executable artifact. The compilation model centres on artifacts called _crates_. -Each compilation processes a single crate in source form, and if successful, produces a single crate in binary form: either an executable or a library.^[A crate is somewhat -analogous to an *assembly* in the ECMA-335 CLI model, a *library* in the -SML/NJ Compilation Manager, a *unit* in the Owens and Flatt module system, -or a *configuration* in Mesa.] +Each compilation processes a single crate in source form, and if successful, +produces a single crate in binary form: either an executable or a +library.[^cratesourcefile] + +[^cratesourcefile]: A crate is somewhat analogous to an *assembly* in the + ECMA-335 CLI model, a *library* in the SML/NJ Compilation Manager, a *unit* + in the Owens and Flatt module system, or a *configuration* in Mesa. A _crate_ is a unit of compilation and linking, as well as versioning, distribution and runtime loading. A crate contains a _tree_ of nested [module](#modules) scopes. @@ -3246,12 +3253,17 @@ types. User-defined types have limited capabilities. The primitive types are the following: -* The "unit" type `()`, having the single "unit" value `()` (occasionally called "nil"). - ^[The "unit" value `()` is *not* a sentinel "null pointer" value for reference slots; the "unit" type is the implicit return type from functions otherwise lacking a return type, and can be used in other contexts (such as message-sending or type-parametric code) as a zero-size type.] +* The "unit" type `()`, having the single "unit" value `()` (occasionally called + "nil"). [^unittype] * The boolean type `bool` with values `true` and `false`. * The machine types. * The machine-dependent integer and floating-point types. +[^unittype]: The "unit" value `()` is *not* a sentinel "null pointer" value for + reference slots; the "unit" type is the implicit return type from functions + otherwise lacking a return type, and can be used in other contexts (such as + message-sending or type-parametric code) as a zero-size type.] + #### Machine types The machine types are the following: @@ -3270,16 +3282,19 @@ The machine types are the following: #### Machine-dependent integer types -The Rust type `uint`^[A Rust `uint` is analogous to a C99 `uintptr_t`.] is an +The Rust type `uint` [^rustuint] is an unsigned integer type with target-machine-dependent size. Its size, in bits, is equal to the number of bits required to hold any memory address on the target machine. -The Rust type `int`^[A Rust `int` is analogous to a C99 `intptr_t`.] is a +The Rust type `int` [^rustint] is a two's complement signed integer type with target-machine-dependent size. Its size, in bits, is equal to the size of the rust type `uint` on the same target machine. +[^rustuint]: A Rust `uint` is analogous to a C99 `uintptr_t`. +[^rustint]: A Rust `int` is analogous to a C99 `intptr_t`. + ### Textual types The types `char` and `str` hold textual data. @@ -3352,10 +3367,12 @@ and access to a vector is always bounds-checked. ### Structure types -A `struct` *type* is a heterogeneous product of other types, called the *fields* of the type. -^[`struct` types are analogous `struct` types in C, -the *record* types of the ML family, -or the *structure* types of the Lisp family.] +A `struct` *type* is a heterogeneous product of other types, called the *fields* +of the type.[^structtype] + +[^structtype]: `struct` types are analogous `struct` types in C, + the *record* types of the ML family, + or the *structure* types of the Lisp family. New instances of a `struct` can be constructed with a [struct expression](#structure-expressions). @@ -3375,9 +3392,10 @@ is the only value that inhabits such a type. ### Enumerated types An *enumerated type* is a nominal, heterogeneous disjoint union type, -denoted by the name of an [`enum` item](#enumerations). -^[The `enum` type is analogous to a `data` constructor declaration in ML, -or a *pick ADT* in Limbo.] +denoted by the name of an [`enum` item](#enumerations). [^enumtype] + +[^enumtype]: The `enum` type is analogous to a `data` constructor declaration in + ML, or a *pick ADT* in Limbo. An [`enum` item](#enumerations) declares both the type and a number of *variant constructors*, each of which is independently named and takes an optional tuple of arguments. @@ -3804,14 +3822,15 @@ By default, the scheduler chooses the number of threads based on the number of concurrent physical CPUs detected at startup. It's also possible to override this choice at runtime. When the number of tasks exceeds the number of threads — which is likely — -the scheduler multiplexes the tasks onto threads.^[ -This is an M:N scheduler, -which is known to give suboptimal results for CPU-bound concurrency problems. -In such cases, running with the same number of threads and tasks can yield better results. -Rust has M:N scheduling in order to support very large numbers of tasks -in contexts where threads are too resource-intensive to use in large number. -The cost of threads varies substantially per operating system, and is sometimes quite low, -so this flexibility is not always worth exploiting.] +the scheduler multiplexes the tasks onto threads.[^mnscheduler] + +[^mnscheduler]: This is an M:N scheduler, which is known to give suboptimal + results for CPU-bound concurrency problems. In such cases, running with the + same number of threads and tasks can yield better results. Rust has M:N + scheduling in order to support very large numbers of tasks in contexts where + threads are too resource-intensive to use in large number. The cost of + threads varies substantially per operating system, and is sometimes quite + low, so this flexibility is not always worth exploiting. ### Communication between tasks diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 432f089cf42..9d6b0ec5517 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -51,6 +51,14 @@ static HOEDOWN_EXT_TABLES: libc::c_uint = 1 << 0; static HOEDOWN_EXT_FENCED_CODE: libc::c_uint = 1 << 1; static HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3; static HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4; +static HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8; +static HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2; + +static HOEDOWN_EXTENSIONS: libc::c_uint = + HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES | + HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK | + HOEDOWN_EXT_STRIKETHROUGH | HOEDOWN_EXT_SUPERSCRIPT | + HOEDOWN_EXT_FOOTNOTES; type hoedown_document = libc::c_void; // this is opaque to us @@ -236,9 +244,6 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result { unsafe { let ob = hoedown_buffer_new(DEF_OUNIT); - let extensions = HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES | - HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK | - HOEDOWN_EXT_STRIKETHROUGH; let renderer = hoedown_html_renderer_new(0, 0); let mut opaque = MyOpaque { dfltblk: (*renderer).blockcode.unwrap(), @@ -248,7 +253,7 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result { (*renderer).blockcode = Some(block); (*renderer).header = Some(header); - let document = hoedown_document_new(renderer, extensions, 16); + let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); hoedown_document_render(document, ob, s.as_ptr(), s.len() as libc::size_t); hoedown_document_free(document); @@ -319,15 +324,12 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { unsafe { let ob = hoedown_buffer_new(DEF_OUNIT); - let extensions = HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES | - HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK | - HOEDOWN_EXT_STRIKETHROUGH; let renderer = hoedown_html_renderer_new(0, 0); (*renderer).blockcode = Some(block); (*renderer).header = Some(header); (*(*renderer).opaque).opaque = tests as *mut _ as *mut libc::c_void; - let document = hoedown_document_new(renderer, extensions, 16); + let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); hoedown_document_render(document, ob, doc.as_ptr(), doc.len() as libc::size_t); hoedown_document_free(document); From 4d2877c189857501466fd2866608e73e7580a346 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 2 May 2014 20:07:00 -0700 Subject: [PATCH 11/12] doc: Remove latex math documentation This hasn't worked since pandoc stopped being used. We can get by well enough with the superscript extension for these equations. Closes #12989 --- src/doc/rust.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rust.md b/src/doc/rust.md index 11875560080..cc99b1a4ab5 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -3269,12 +3269,12 @@ The primitive types are the following: The machine types are the following: * The unsigned word types `u8`, `u16`, `u32` and `u64`, with values drawn from - the integer intervals $[0, 2^8 - 1]$, $[0, 2^{16} - 1]$, $[0, 2^{32} - 1]$ and - $[0, 2^{64} - 1]$ respectively. + the integer intervals [0, 2^8 - 1], [0, 2^16 - 1], [0, 2^32 - 1] and + [0, 2^64 - 1] respectively. * The signed two's complement word types `i8`, `i16`, `i32` and `i64`, with - values drawn from the integer intervals $[-(2^7), 2^7 - 1]$, - $[-(2^{15}), 2^{15} - 1]$, $[-(2^{31}), 2^{31} - 1]$, $[-(2^{63}), 2^{63} - 1]$ + values drawn from the integer intervals [-(2^(7)), 2^7 - 1], + [-(2^(15)), 2^15 - 1], $[-(2^(31)), 2^31 - 1], [-(2^(63)), 2^63 - 1] respectively. * The IEEE 754-2008 `binary32` and `binary64` floating-point types: `f32` and From d7891c7c0e964fc9f947e0aefc7494218d531af2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 2 May 2014 20:16:03 -0700 Subject: [PATCH 12/12] rustdoc: Turn the noise down on implemented traits This commit removes the inherited documentation from type pages. This generally just clutters up the page when you can click through to the trait itself to get all the meaty documentation. Closes #11991 --- src/librustdoc/html/render.rs | 44 ++++++----------------------------- 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 504be2cd8ae..a0d21bbf149 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1619,54 +1619,24 @@ fn render_impl(w: &mut Writer, i: &clean::Impl, None => {} } - fn docmeth(w: &mut Writer, item: &clean::Item) -> io::IoResult { + fn docmeth(w: &mut Writer, item: &clean::Item, + dox: bool) -> io::IoResult<()> { try!(write!(w, "

    ", *item.name.get_ref())); try!(render_method(w, item)); try!(write!(w, "

    \n")); match item.doc_value() { - Some(s) => { + Some(s) if dox => { try!(write!(w, "
    {}
    ", Markdown(s))); - Ok(true) + Ok(()) } - None => Ok(false) + Some(..) | None => Ok(()) } } try!(write!(w, "
    ")); for meth in i.methods.iter() { - if try!(docmeth(w, meth)) { - continue - } - - // No documentation? Attempt to slurp in the trait's documentation - let trait_id = match trait_id { - None => continue, - Some(id) => id, - }; - try!(local_data::get(cache_key, |cache| { - let cache = cache.unwrap(); - match cache.traits.find(&trait_id) { - Some(t) => { - let name = meth.name.clone(); - match t.methods.iter().find(|t| t.item().name == name) { - Some(method) => { - match method.item().doc_value() { - Some(s) => { - try!(write!(w, - "
    {}
    ", - Markdown(s))); - } - None => {} - } - } - None => {} - } - } - None => {} - } - Ok(()) - })) + try!(docmeth(w, meth, true)); } // If we've implemented a trait, then also emit documentation for all @@ -1685,7 +1655,7 @@ fn render_impl(w: &mut Writer, i: &clean::Impl, None => {} } - try!(docmeth(w, method.item())); + try!(docmeth(w, method.item(), false)); } } None => {}