auto merge of #9475 : alexcrichton/rust/rustdoc++, r=cmr
The commit messages are a good technical summary, a good visual summary (contrib is this version): Pub use statements now rendered. Notice how almost all components are also clickable! * http://static.rust-lang.org/doc/master/std/prelude/index.html * http://www.contrib.andrew.cmu.edu/~acrichto/doc/std/prelude/index.html Private things hidden by default (for at least some approximation of privacy). I hope to improve this once privacy is totally ironed out. * http://static.rust-lang.org/doc/master/std/hashmap/struct.HashMap.html * http://www.contrib.andrew.cmu.edu/~acrichto/doc/std/hashmap/struct.HashMap.html Unindentation now works properly: * http://static.rust-lang.org/doc/master/extra/getopts/index.html * http://www.contrib.andrew.cmu.edu/~acrichto/doc/extra/getopts/index.html Also sundown has massively reduced compilation time (of docs, not the of the crates)
This commit is contained in:
commit
41826c48ed
2
configure
vendored
2
configure
vendored
@ -684,7 +684,7 @@ do
|
||||
isaac linenoise sync test \
|
||||
arch/i386 arch/x86_64 arch/arm arch/mips \
|
||||
libuv libuv/src/ares libuv/src/eio libuv/src/ev \
|
||||
jemalloc
|
||||
jemalloc sundown/src sundown/html
|
||||
do
|
||||
make_dir $t/rt/stage$s/$i
|
||||
done
|
||||
|
13
mk/rt.mk
13
mk/rt.mk
@ -82,7 +82,16 @@ RUNTIME_CXXS_$(1)_$(2) := \
|
||||
rt/rust_android_dummy.cpp \
|
||||
rt/rust_test_helpers.cpp
|
||||
|
||||
RUNTIME_CS_$(1)_$(2) := rt/linenoise/linenoise.c rt/linenoise/utf8.c
|
||||
RUNTIME_CS_$(1)_$(2) := rt/linenoise/linenoise.c \
|
||||
rt/linenoise/utf8.c \
|
||||
rt/sundown/src/autolink.c \
|
||||
rt/sundown/src/buffer.c \
|
||||
rt/sundown/src/stack.c \
|
||||
rt/sundown/src/markdown.c \
|
||||
rt/sundown/html/houdini_href_e.c \
|
||||
rt/sundown/html/houdini_html_e.c \
|
||||
rt/sundown/html/html_smartypants.c \
|
||||
rt/sundown/html/html.c
|
||||
|
||||
RUNTIME_S_$(1)_$(2) := rt/arch/$$(HOST_$(1))/_context.S \
|
||||
rt/arch/$$(HOST_$(1))/ccall.S \
|
||||
@ -117,6 +126,8 @@ RUNTIME_DEF_$(1)_$(2) := $$(RT_OUTPUT_DIR_$(1))/rustrt$$(CFG_DEF_SUFFIX_$(1))
|
||||
RUNTIME_INCS_$(1)_$(2) := -I $$(S)src/rt -I $$(S)src/rt/isaac -I $$(S)src/rt/uthash \
|
||||
-I $$(S)src/rt/arch/$$(HOST_$(1)) \
|
||||
-I $$(S)src/rt/linenoise \
|
||||
-I $$(S)src/rt/sundown/src \
|
||||
-I $$(S)src/rt/sundown/html \
|
||||
-I $$(S)src/libuv/include
|
||||
RUNTIME_OBJS_$(1)_$(2) := $$(RUNTIME_CXXS_$(1)_$(2):rt/%.cpp=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) \
|
||||
$$(RUNTIME_CS_$(1)_$(2):rt/%.c=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) \
|
||||
|
@ -227,8 +227,9 @@ ALL_CS := $(wildcard $(S)src/rt/*.cpp \
|
||||
$(S)src/rt/*/*/*.cpp \
|
||||
$(S)src/rustllvm/*.cpp)
|
||||
ALL_CS := $(filter-out $(S)src/rt/miniz.cpp \
|
||||
$(S)src/rt/linenoise/linenoise.c \
|
||||
$(S)src/rt/linenoise/utf8.c \
|
||||
$(wildcard $(S)src/rt/linenoise/*.c) \
|
||||
$(wildcard $(S)src/rt/sundown/src/*.c) \
|
||||
$(wildcard $(S)src/rt/sundown/html/*.c) \
|
||||
,$(ALL_CS))
|
||||
ALL_HS := $(wildcard $(S)src/rt/*.h \
|
||||
$(S)src/rt/*/*.h \
|
||||
@ -241,6 +242,8 @@ ALL_HS := $(filter-out $(S)src/rt/vg/valgrind.h \
|
||||
$(S)src/rt/msvc/inttypes.h \
|
||||
$(S)src/rt/linenoise/linenoise.h \
|
||||
$(S)src/rt/linenoise/utf8.h \
|
||||
$(wildcard $(S)src/rt/sundown/src/*.h) \
|
||||
$(wildcard $(S)src/rt/sundown/html/*.h) \
|
||||
,$(ALL_HS))
|
||||
|
||||
# Run the tidy script in multiple parts to avoid huge 'echo' commands
|
||||
|
@ -17,7 +17,7 @@
|
||||
* In this example, a large vector of floats is shared between several tasks.
|
||||
* With simple pipes, without Arc, a copy would have to be made for each task.
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* extern mod std;
|
||||
* use extra::arc;
|
||||
* let numbers=vec::from_fn(100, |ind| (ind as float)*rand::random());
|
||||
@ -34,7 +34,7 @@
|
||||
* // Work with the local numbers
|
||||
* }
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
|
||||
#[allow(missing_doc)];
|
||||
@ -440,7 +440,7 @@ impl<T:Freeze + Send> RWArc<T> {
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* do arc.write_downgrade |mut write_token| {
|
||||
* do write_token.write_cond |state, condvar| {
|
||||
* ... exclusive access with mutable state ...
|
||||
@ -450,7 +450,7 @@ impl<T:Freeze + Send> RWArc<T> {
|
||||
* ... shared access with immutable state ...
|
||||
* }
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn write_downgrade<U>(&self, blk: &fn(v: RWWriteMode<T>) -> U) -> U {
|
||||
unsafe {
|
||||
|
@ -62,7 +62,7 @@ impl<'self> ToBase64 for &'self [u8] {
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* extern mod extra;
|
||||
* use extra::base64::{ToBase64, standard};
|
||||
*
|
||||
@ -70,7 +70,7 @@ impl<'self> ToBase64 for &'self [u8] {
|
||||
* let str = [52,32].to_base64(standard);
|
||||
* printfln!("%s", str);
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
fn to_base64(&self, config: Config) -> ~str {
|
||||
let bytes = match config.char_set {
|
||||
@ -170,7 +170,7 @@ impl<'self> FromBase64 for &'self str {
|
||||
*
|
||||
* This converts a string literal to base64 and back.
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* extern mod extra;
|
||||
* use extra::base64::{ToBase64, FromBase64, standard};
|
||||
* use std::str;
|
||||
@ -183,7 +183,7 @@ impl<'self> FromBase64 for &'self str {
|
||||
* let result_str = str::from_utf8(bytes);
|
||||
* printfln!("%s", result_str);
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
fn from_base64(&self) -> Result<~[u8], ~str> {
|
||||
let mut r = ~[];
|
||||
|
@ -26,8 +26,7 @@ Rust extras are part of the standard Rust distribution.
|
||||
url = "https://github.com/mozilla/rust/tree/master/src/libextra")];
|
||||
|
||||
#[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
passes = "strip-hidden")];
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico")];
|
||||
|
||||
#[comment = "Rust extras"];
|
||||
#[license = "MIT/ASL2"];
|
||||
|
@ -25,7 +25,7 @@ ports and channels.
|
||||
|
||||
This example sends boxed integers across tasks using serialization.
|
||||
|
||||
~~~ {.rust}
|
||||
```rust
|
||||
let (port, chan) = serial::pipe_stream();
|
||||
|
||||
do task::spawn || {
|
||||
@ -37,7 +37,7 @@ do task::spawn || {
|
||||
for i in range(0, 10) {
|
||||
assert @i == port.recv()
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
# Safety Note
|
||||
|
||||
|
@ -14,13 +14,13 @@
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* # fn fib(n: uint) -> uint {42};
|
||||
* # fn make_a_sandwich() {};
|
||||
* let mut delayed_fib = extra::future::spawn (|| fib(5000) );
|
||||
* make_a_sandwich();
|
||||
* printfln!("fib(5000) = %?", delayed_fib.get())
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
|
||||
#[allow(missing_doc)];
|
||||
|
@ -29,7 +29,7 @@
|
||||
//! that requires an input file to be specified, accepts an optional output
|
||||
//! file name following -o, and accepts both -h and --help as optional flags.
|
||||
//!
|
||||
//! ```
|
||||
//! ~~~{.rust}
|
||||
//! exter mod extra;
|
||||
//! use extra::getopts::*;
|
||||
//! use std::os;
|
||||
@ -75,7 +75,7 @@
|
||||
//! };
|
||||
//! do_work(input, output);
|
||||
//! }
|
||||
//! ```
|
||||
//! ~~~
|
||||
|
||||
use std::cmp::Eq;
|
||||
use std::result::{Err, Ok};
|
||||
|
@ -51,18 +51,18 @@ pub struct GlobIterator {
|
||||
* Consider a directory `/media/pictures` containing only the files `kittens.jpg`,
|
||||
* `puppies.jpg` and `hamsters.gif`:
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* for path in glob("/media/pictures/*.jpg") {
|
||||
* println(path.to_str());
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* The above code will print:
|
||||
*
|
||||
* ~~~
|
||||
* ```
|
||||
* /media/pictures/kittens.jpg
|
||||
* /media/pictures/puppies.jpg
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn glob(pattern: &str) -> GlobIterator {
|
||||
glob_with(pattern, MatchOptions::new())
|
||||
@ -270,11 +270,11 @@ impl Pattern {
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* assert!(Pattern::new("c?t").matches("cat"));
|
||||
* assert!(Pattern::new("k[!e]tteh").matches("kitteh"));
|
||||
* assert!(Pattern::new("d*g").matches("doog"));
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn matches(&self, str: &str) -> bool {
|
||||
self.matches_with(str, MatchOptions::new())
|
||||
@ -492,13 +492,13 @@ impl MatchOptions {
|
||||
*
|
||||
* This function always returns this value:
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* MatchOptions {
|
||||
* case_sensitive: true,
|
||||
* require_literal_separator: false.
|
||||
* require_literal_leading_dot: false
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn new() -> MatchOptions {
|
||||
MatchOptions {
|
||||
|
@ -27,7 +27,7 @@ impl<'self> ToHex for &'self [u8] {
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* extern mod extra;
|
||||
* use extra::hex::ToHex;
|
||||
*
|
||||
@ -35,7 +35,7 @@ impl<'self> ToHex for &'self [u8] {
|
||||
* let str = [52,32].to_hex();
|
||||
* printfln!("%s", str);
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
fn to_hex(&self) -> ~str {
|
||||
let mut v = vec::with_capacity(self.len() * 2);
|
||||
@ -70,7 +70,7 @@ impl<'self> FromHex for &'self str {
|
||||
*
|
||||
* This converts a string literal to hexadecimal and back.
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* extern mod extra;
|
||||
* use extra::hex::{FromHex, ToHex};
|
||||
* use std::str;
|
||||
@ -83,7 +83,7 @@ impl<'self> FromHex for &'self str {
|
||||
* let result_str = str::from_utf8(bytes);
|
||||
* printfln!("%s", result_str);
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
fn from_hex(&self) -> Result<~[u8], ~str> {
|
||||
// This may be an overestimate if there is any whitespace
|
||||
|
@ -578,7 +578,7 @@ impl RWLock {
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* do lock.write_downgrade |mut write_token| {
|
||||
* do write_token.write_cond |condvar| {
|
||||
* ... exclusive access ...
|
||||
@ -588,7 +588,7 @@ impl RWLock {
|
||||
* ... shared access ...
|
||||
* }
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn write_downgrade<U>(&self, blk: &fn(v: RWLockWriteMode) -> U) -> U {
|
||||
// Implementation slightly different from the slicker 'write's above.
|
||||
|
@ -28,7 +28,7 @@ unlikely.
|
||||
|
||||
To create a new random (V4) UUID and print it out in hexadecimal form:
|
||||
|
||||
~~~ {.rust}
|
||||
```rust
|
||||
extern mod extra;
|
||||
use extra::uuid::Uuid;
|
||||
|
||||
@ -36,7 +36,7 @@ fn main() {
|
||||
let uuid1 = Uuid::new_v4();
|
||||
println(uuid1.to_str());
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
# Strings
|
||||
|
||||
|
@ -2499,6 +2499,26 @@ impl Resolver {
|
||||
assert!(import_resolution.outstanding_references >= 1);
|
||||
import_resolution.outstanding_references -= 1;
|
||||
|
||||
// record what this import resolves to for later uses in documentation,
|
||||
// this may resolve to either a value or a type, but for documentation
|
||||
// purposes it's good enough to just favor one over the other.
|
||||
match i.value_target {
|
||||
Some(target) => {
|
||||
self.def_map.insert(i.value_id,
|
||||
target.bindings.value_def.get_ref().def);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
match i.type_target {
|
||||
Some(target) => {
|
||||
match target.bindings.type_def.get_ref().type_def {
|
||||
Some(def) => { self.def_map.insert(i.type_id, def); }
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
debug!("(resolving single import) successfully resolved import");
|
||||
return Success(());
|
||||
}
|
||||
@ -2626,6 +2646,14 @@ impl Resolver {
|
||||
merge_import_resolution(name, name_bindings);
|
||||
}
|
||||
|
||||
// Record the destination of this import
|
||||
match containing_module.def_id {
|
||||
Some(did) => {
|
||||
self.def_map.insert(id, DefMod(did));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
debug!("(resolving glob import) successfully resolved import");
|
||||
return Success(());
|
||||
}
|
||||
|
@ -240,4 +240,4 @@ We make use of a trait-like impementation strategy to consolidate
|
||||
duplicated code between subtypes, GLB, and LUB computations. See the
|
||||
section on "Type Combining" below for details.
|
||||
|
||||
*/
|
||||
*/
|
||||
|
@ -15,6 +15,7 @@ use its = syntax::parse::token::ident_to_str;
|
||||
|
||||
use syntax;
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
use syntax::attr::AttributeMethods;
|
||||
|
||||
use std;
|
||||
@ -283,7 +284,7 @@ impl Clean<Item> for ast::method {
|
||||
attrs: self.attrs.clean(),
|
||||
source: self.span.clean(),
|
||||
id: self.self_id.clone(),
|
||||
visibility: None,
|
||||
visibility: self.vis.clean(),
|
||||
inner: MethodItem(Method {
|
||||
generics: self.generics.clean(),
|
||||
self_: self.explicit_self.clean(),
|
||||
@ -345,6 +346,7 @@ impl Clean<SelfTy> for ast::explicit_self {
|
||||
pub struct Function {
|
||||
decl: FnDecl,
|
||||
generics: Generics,
|
||||
purity: ast::purity,
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Function {
|
||||
@ -358,6 +360,7 @@ impl Clean<Item> for doctree::Function {
|
||||
inner: FunctionItem(Function {
|
||||
decl: self.decl.clean(),
|
||||
generics: self.generics.clean(),
|
||||
purity: self.purity,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -468,8 +471,7 @@ impl Clean<Item> for doctree::Trait {
|
||||
|
||||
impl Clean<Type> for ast::trait_ref {
|
||||
fn clean(&self) -> Type {
|
||||
let t = Unresolved(self.path.clean(), None, self.ref_id);
|
||||
resolve_type(&t)
|
||||
resolve_type(self.path.clean(), None, self.ref_id)
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,9 +516,6 @@ impl Clean<TraitMethod> for ast::trait_method {
|
||||
/// it does not preserve mutability or boxes.
|
||||
#[deriving(Clone, Encodable, Decodable)]
|
||||
pub enum Type {
|
||||
/// Most types start out as "Unresolved". It serves as an intermediate stage between cleaning
|
||||
/// and type resolution.
|
||||
Unresolved(Path, Option<~[TyParamBound]>, ast::NodeId),
|
||||
/// structs/enums/traits (anything that'd be an ast::ty_path)
|
||||
ResolvedPath { path: Path, typarams: Option<~[TyParamBound]>, id: ast::NodeId },
|
||||
/// Reference to an item in an external crate (fully qualified path)
|
||||
@ -555,25 +554,25 @@ impl Clean<Type> for ast::Ty {
|
||||
debug!("cleaning type `%?`", self);
|
||||
let codemap = local_data::get(super::ctxtkey, |x| *x.unwrap()).sess.codemap;
|
||||
debug!("span corresponds to `%s`", codemap.span_to_str(self.span));
|
||||
let t = match self.node {
|
||||
match self.node {
|
||||
ty_nil => Unit,
|
||||
ty_ptr(ref m) => RawPointer(m.mutbl.clean(), ~resolve_type(&m.ty.clean())),
|
||||
ty_ptr(ref m) => RawPointer(m.mutbl.clean(), ~m.ty.clean()),
|
||||
ty_rptr(ref l, ref m) =>
|
||||
BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(),
|
||||
type_: ~resolve_type(&m.ty.clean())},
|
||||
ty_box(ref m) => Managed(m.mutbl.clean(), ~resolve_type(&m.ty.clean())),
|
||||
ty_uniq(ref m) => Unique(~resolve_type(&m.ty.clean())),
|
||||
ty_vec(ref m) => Vector(~resolve_type(&m.ty.clean())),
|
||||
ty_fixed_length_vec(ref m, ref e) => FixedVector(~resolve_type(&m.ty.clean()),
|
||||
type_: ~m.ty.clean()},
|
||||
ty_box(ref m) => Managed(m.mutbl.clean(), ~m.ty.clean()),
|
||||
ty_uniq(ref m) => Unique(~m.ty.clean()),
|
||||
ty_vec(ref m) => Vector(~m.ty.clean()),
|
||||
ty_fixed_length_vec(ref m, ref e) => FixedVector(~m.ty.clean(),
|
||||
e.span.to_src()),
|
||||
ty_tup(ref tys) => Tuple(tys.iter().map(|x| resolve_type(&x.clean())).collect()),
|
||||
ty_path(ref p, ref tpbs, id) => Unresolved(p.clean(), tpbs.clean(), id),
|
||||
ty_tup(ref tys) => Tuple(tys.iter().map(|x| x.clean()).collect()),
|
||||
ty_path(ref p, ref tpbs, id) =>
|
||||
resolve_type(p.clean(), tpbs.clean(), id),
|
||||
ty_closure(ref c) => Closure(~c.clean()),
|
||||
ty_bare_fn(ref barefn) => BareFunction(~barefn.clean()),
|
||||
ty_bot => Bottom,
|
||||
ref x => fail!("Unimplemented type %?", x),
|
||||
};
|
||||
resolve_type(&t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -927,26 +926,45 @@ impl Clean<ViewItemInner> for ast::view_item_ {
|
||||
|
||||
#[deriving(Clone, Encodable, Decodable)]
|
||||
pub enum ViewPath {
|
||||
SimpleImport(~str, Path, ast::NodeId),
|
||||
GlobImport(Path, ast::NodeId),
|
||||
ImportList(Path, ~[ViewListIdent], ast::NodeId)
|
||||
// use str = source;
|
||||
SimpleImport(~str, ImportSource),
|
||||
// use source::*;
|
||||
GlobImport(ImportSource),
|
||||
// use source::{a, b, c};
|
||||
ImportList(ImportSource, ~[ViewListIdent]),
|
||||
}
|
||||
|
||||
#[deriving(Clone, Encodable, Decodable)]
|
||||
pub struct ImportSource {
|
||||
path: Path,
|
||||
did: Option<ast::DefId>,
|
||||
}
|
||||
|
||||
impl Clean<ViewPath> for ast::view_path {
|
||||
fn clean(&self) -> ViewPath {
|
||||
match self.node {
|
||||
ast::view_path_simple(ref i, ref p, ref id) => SimpleImport(i.clean(), p.clean(), *id),
|
||||
ast::view_path_glob(ref p, ref id) => GlobImport(p.clean(), *id),
|
||||
ast::view_path_list(ref p, ref pl, ref id) => ImportList(p.clean(), pl.clean(), *id),
|
||||
ast::view_path_simple(ref i, ref p, id) =>
|
||||
SimpleImport(i.clean(), resolve_use_source(p.clean(), id)),
|
||||
ast::view_path_glob(ref p, id) =>
|
||||
GlobImport(resolve_use_source(p.clean(), id)),
|
||||
ast::view_path_list(ref p, ref pl, id) =>
|
||||
ImportList(resolve_use_source(p.clean(), id), pl.clean()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type ViewListIdent = ~str;
|
||||
#[deriving(Clone, Encodable, Decodable)]
|
||||
pub struct ViewListIdent {
|
||||
name: ~str,
|
||||
source: Option<ast::DefId>,
|
||||
}
|
||||
|
||||
impl Clean<ViewListIdent> for ast::path_list_ident {
|
||||
fn clean(&self) -> ViewListIdent {
|
||||
self.node.name.clean()
|
||||
ViewListIdent {
|
||||
name: self.node.name.clean(),
|
||||
source: resolve_def(self.node.id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1017,14 +1035,10 @@ fn remove_comment_tags(s: &str) -> ~str {
|
||||
}
|
||||
|
||||
/// Given a Type, resolve it using the def_map
|
||||
fn resolve_type(t: &Type) -> Type {
|
||||
fn resolve_type(path: Path, tpbs: Option<~[TyParamBound]>,
|
||||
id: ast::NodeId) -> Type {
|
||||
use syntax::ast::*;
|
||||
|
||||
let (path, tpbs, id) = match t {
|
||||
&Unresolved(ref path, ref tbps, id) => (path, tbps, id),
|
||||
_ => return (*t).clone(),
|
||||
};
|
||||
|
||||
let dm = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.def_map;
|
||||
debug!("searching for %? in defmap", id);
|
||||
let d = match dm.find(&id) {
|
||||
@ -1089,6 +1103,18 @@ fn resolve_type(t: &Type) -> Type {
|
||||
let cname = cratedata.name.to_owned();
|
||||
External(cname + "::" + path, ty)
|
||||
} else {
|
||||
ResolvedPath {path: path.clone(), typarams: tpbs.clone(), id: def_id.node}
|
||||
ResolvedPath {path: path.clone(), typarams: tpbs, id: def_id.node}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
|
||||
ImportSource {
|
||||
path: path,
|
||||
did: resolve_def(id),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
|
||||
let dm = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.def_map;
|
||||
dm.find(&id).map_move(|&d| ast_util::def_id_of_def(d))
|
||||
}
|
||||
|
@ -107,6 +107,7 @@ pub struct Function {
|
||||
id: NodeId,
|
||||
name: Ident,
|
||||
vis: ast::visibility,
|
||||
purity: ast::purity,
|
||||
where: Span,
|
||||
generics: ast::Generics,
|
||||
}
|
||||
|
@ -13,11 +13,13 @@ use std::local_data;
|
||||
use std::rt::io;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
|
||||
use clean;
|
||||
use html::render::{cache_key, current_location_key};
|
||||
|
||||
pub struct VisSpace(Option<ast::visibility>);
|
||||
pub struct PuritySpace(ast::purity);
|
||||
pub struct Method<'self>(&'self clean::SelfTy, &'self clean::FnDecl);
|
||||
|
||||
impl fmt::Default for clean::Generics {
|
||||
@ -95,7 +97,8 @@ impl fmt::Default for clean::Path {
|
||||
}
|
||||
}
|
||||
|
||||
fn resolved_path(w: &mut io::Writer, id: ast::NodeId, path: &clean::Path) {
|
||||
fn resolved_path(w: &mut io::Writer, id: ast::NodeId,
|
||||
path: &clean::Path, print_all: bool) {
|
||||
// The generics will get written to both the title and link
|
||||
let mut generics = ~"";
|
||||
let last = path.segments.last();
|
||||
@ -117,47 +120,73 @@ fn resolved_path(w: &mut io::Writer, id: ast::NodeId, path: &clean::Path) {
|
||||
// Did someone say rightward-drift?
|
||||
do local_data::get(current_location_key) |loc| {
|
||||
let loc = loc.unwrap();
|
||||
|
||||
if print_all {
|
||||
let mut root = match path.segments[0].name.as_slice() {
|
||||
"super" => ~"../",
|
||||
"self" => ~"",
|
||||
_ => "../".repeat(loc.len() - 1),
|
||||
};
|
||||
let amt = path.segments.len() - 1;
|
||||
for seg in path.segments.slice_to(amt).iter() {
|
||||
if "super" == seg.name || "self" == seg.name {
|
||||
write!(w, "{}::", seg.name);
|
||||
} else {
|
||||
root.push_str(seg.name);
|
||||
root.push_str("/");
|
||||
write!(w, "<a class='mod'
|
||||
href='{}index.html'>{}</a>::",
|
||||
root,
|
||||
seg.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do local_data::get(cache_key) |cache| {
|
||||
do cache.unwrap().read |cache| {
|
||||
match cache.paths.find(&id) {
|
||||
// This is a documented path, link to it!
|
||||
Some(&(ref fqp, shortty)) => {
|
||||
let fqn = fqp.connect("::");
|
||||
let mut same = 0;
|
||||
for (a, b) in loc.iter().zip(fqp.iter()) {
|
||||
if *a == *b {
|
||||
same += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let same = loc.iter().zip(fqp.iter())
|
||||
.take_while(|&(a, b)| *a == *b).len();
|
||||
|
||||
let mut url = ~"";
|
||||
for _ in range(same, loc.len()) {
|
||||
if "super" == path.segments[0].name {
|
||||
url.push_str("../");
|
||||
} else if "self" != path.segments[0].name {
|
||||
url.push_str("../".repeat(loc.len() - same));
|
||||
}
|
||||
if same == fqp.len() {
|
||||
url.push_str(shortty);
|
||||
url.push_str(".");
|
||||
url.push_str(*fqp.last());
|
||||
url.push_str(".html");
|
||||
} else {
|
||||
if same < fqp.len() {
|
||||
let remaining = fqp.slice_from(same);
|
||||
let to_link = remaining.slice_to(remaining.len() - 1);
|
||||
for component in to_link.iter() {
|
||||
url.push_str(*component);
|
||||
url.push_str("/");
|
||||
}
|
||||
url.push_str(shortty);
|
||||
url.push_str(".");
|
||||
url.push_str(*remaining.last());
|
||||
url.push_str(".html");
|
||||
}
|
||||
|
||||
match shortty {
|
||||
"mod" => {
|
||||
url.push_str(*fqp.last());
|
||||
url.push_str("/index.html");
|
||||
}
|
||||
_ => {
|
||||
url.push_str(shortty);
|
||||
url.push_str(".");
|
||||
url.push_str(*fqp.last());
|
||||
url.push_str(".html");
|
||||
}
|
||||
}
|
||||
write!(w, "<a class='{}' href='{}' title='{}'>{}</a>{}",
|
||||
shortty, url, fqn, last.name, generics);
|
||||
}
|
||||
None => {
|
||||
if print_all {
|
||||
let amt = path.segments.len() - 1;
|
||||
for seg in path.segments.iter().take(amt) {
|
||||
write!(w, "{}::", seg.name);
|
||||
}
|
||||
}
|
||||
write!(w, "{}{}", last.name, generics);
|
||||
}
|
||||
};
|
||||
@ -176,9 +205,8 @@ impl fmt::Default for clean::Type {
|
||||
}
|
||||
}
|
||||
}
|
||||
clean::Unresolved(*) => unreachable!(),
|
||||
clean::ResolvedPath{id, typarams: ref typarams, path: ref path} => {
|
||||
resolved_path(f.buf, id, path);
|
||||
resolved_path(f.buf, id, path, false);
|
||||
match *typarams {
|
||||
Some(ref params) => {
|
||||
f.buf.write("<".as_bytes());
|
||||
@ -228,11 +256,7 @@ impl fmt::Default for clean::Type {
|
||||
None => {}
|
||||
}
|
||||
write!(f.buf, "{}{}fn{}",
|
||||
match decl.purity {
|
||||
ast::unsafe_fn => "unsafe ",
|
||||
ast::extern_fn => "extern ",
|
||||
ast::impure_fn => ""
|
||||
},
|
||||
PuritySpace(decl.purity),
|
||||
match decl.onceness {
|
||||
ast::Once => "once ",
|
||||
ast::Many => "",
|
||||
@ -242,11 +266,7 @@ impl fmt::Default for clean::Type {
|
||||
}
|
||||
clean::BareFunction(ref decl) => {
|
||||
write!(f.buf, "{}{}fn{}{}",
|
||||
match decl.purity {
|
||||
ast::unsafe_fn => "unsafe ",
|
||||
ast::extern_fn => "extern ",
|
||||
ast::impure_fn => ""
|
||||
},
|
||||
PuritySpace(decl.purity),
|
||||
match decl.abi {
|
||||
~"" | ~"\"Rust\"" => ~"",
|
||||
ref s => " " + *s + " ",
|
||||
@ -362,3 +382,73 @@ impl fmt::Default for VisSpace {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Default for PuritySpace {
|
||||
fn fmt(p: &PuritySpace, f: &mut fmt::Formatter) {
|
||||
match **p {
|
||||
ast::unsafe_fn => write!(f.buf, "unsafe "),
|
||||
ast::extern_fn => write!(f.buf, "extern "),
|
||||
ast::impure_fn => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Default for clean::ViewPath {
|
||||
fn fmt(v: &clean::ViewPath, f: &mut fmt::Formatter) {
|
||||
match *v {
|
||||
clean::SimpleImport(ref name, ref src) => {
|
||||
if *name == src.path.segments.last().name {
|
||||
write!(f.buf, "use {};", *src);
|
||||
} else {
|
||||
write!(f.buf, "use {} = {};", *name, *src);
|
||||
}
|
||||
}
|
||||
clean::GlobImport(ref src) => {
|
||||
write!(f.buf, "use {}::*;", *src);
|
||||
}
|
||||
clean::ImportList(ref src, ref names) => {
|
||||
write!(f.buf, "use {}::\\{", *src);
|
||||
for (i, n) in names.iter().enumerate() {
|
||||
if i > 0 { write!(f.buf, ", "); }
|
||||
write!(f.buf, "{}", *n);
|
||||
}
|
||||
write!(f.buf, "\\};");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Default for clean::ImportSource {
|
||||
fn fmt(v: &clean::ImportSource, f: &mut fmt::Formatter) {
|
||||
match v.did {
|
||||
Some(did) if ast_util::is_local(did) => {
|
||||
resolved_path(f.buf, did.node, &v.path, true);
|
||||
}
|
||||
_ => {
|
||||
for (i, seg) in v.path.segments.iter().enumerate() {
|
||||
if i > 0 { write!(f.buf, "::") }
|
||||
write!(f.buf, "{}", seg.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Default for clean::ViewListIdent {
|
||||
fn fmt(v: &clean::ViewListIdent, f: &mut fmt::Formatter) {
|
||||
match v.source {
|
||||
Some(did) if ast_util::is_local(did) => {
|
||||
let path = clean::Path {
|
||||
global: false,
|
||||
segments: ~[clean::PathSegment {
|
||||
name: v.name.clone(),
|
||||
lifetime: None,
|
||||
types: ~[],
|
||||
}]
|
||||
};
|
||||
resolved_path(f.buf, did.node, &path, false);
|
||||
}
|
||||
_ => write!(f.buf, "{}", v.name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,47 +8,109 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[allow(cstack)]; // each rendering task runs on a fixed stack segment.
|
||||
|
||||
use std::fmt;
|
||||
use std::rt::io::Reader;
|
||||
use std::rt::io::pipe::PipeStream;
|
||||
use std::rt::io::process::{ProcessConfig, Process, CreatePipe};
|
||||
use std::libc;
|
||||
use std::rt::io;
|
||||
use std::vec;
|
||||
|
||||
pub struct Markdown<'self>(&'self str);
|
||||
|
||||
impl<'self> fmt::Default for Markdown<'self> {
|
||||
fn fmt(md: &Markdown<'self>, fmt: &mut fmt::Formatter) {
|
||||
if md.len() == 0 { return; }
|
||||
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 MKDEXT_SPACE_HEADERS: libc::c_uint = 1 << 6;
|
||||
static MKDEXT_SUPERSCRIPT: libc::c_uint = 1 << 7;
|
||||
static MKDEXT_LAX_SPACING: libc::c_uint = 1 << 8;
|
||||
|
||||
// Create the pandoc process
|
||||
do io::io_error::cond.trap(|err| {
|
||||
fail2!("Error executing `pandoc`: {}", err.desc);
|
||||
}).inside {
|
||||
let io = ~[CreatePipe(PipeStream::new().unwrap(), true, false),
|
||||
CreatePipe(PipeStream::new().unwrap(), false, true)];
|
||||
let args = ProcessConfig {
|
||||
program: "pandoc",
|
||||
args: [],
|
||||
env: None,
|
||||
cwd: None,
|
||||
io: io,
|
||||
};
|
||||
let mut p = Process::new(args).expect("couldn't fork for pandoc");
|
||||
type sd_markdown = libc::c_void; // this is opaque to us
|
||||
|
||||
// Write the markdown to stdin and close it.
|
||||
p.io[0].get_mut_ref().write(md.as_bytes());
|
||||
p.io[0] = None;
|
||||
// this is a large struct of callbacks we don't use
|
||||
type sd_callbacks = [libc::size_t, ..26];
|
||||
|
||||
// Ferry the output from pandoc over to the destination buffer.
|
||||
let mut buf = [0, ..1024];
|
||||
loop {
|
||||
match p.io[1].get_mut_ref().read(buf) {
|
||||
None | Some(0) => { break }
|
||||
Some(n) => {
|
||||
fmt.buf.write(buf.slice_to(n));
|
||||
}
|
||||
}
|
||||
}
|
||||
struct html_toc_data {
|
||||
header_count: libc::c_int,
|
||||
current_level: libc::c_int,
|
||||
level_offset: libc::c_int,
|
||||
}
|
||||
|
||||
struct html_renderopt {
|
||||
toc_data: html_toc_data,
|
||||
flags: libc::c_uint,
|
||||
link_attributes: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
|
||||
}
|
||||
|
||||
struct buf {
|
||||
data: *u8,
|
||||
size: libc::size_t,
|
||||
asize: libc::size_t,
|
||||
unit: libc::size_t,
|
||||
}
|
||||
|
||||
// sundown FFI
|
||||
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 bufnew(unit: libc::size_t) -> *buf;
|
||||
fn bufrelease(b: *buf);
|
||||
|
||||
}
|
||||
|
||||
fn render(w: &mut io::Writer, s: &str) {
|
||||
// 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 callbacks: sd_callbacks = [0, ..26];
|
||||
|
||||
sdhtml_renderer(&callbacks, &options, 0);
|
||||
let markdown = sd_markdown_new(extensions, 16, &callbacks,
|
||||
&options as *html_renderopt as *libc::c_void);
|
||||
|
||||
do s.as_imm_buf |data, len| {
|
||||
sd_markdown_render(ob, data, len as libc::size_t, markdown);
|
||||
}
|
||||
sd_markdown_free(markdown);
|
||||
|
||||
do vec::raw::buf_as_slice((*ob).data, (*ob).size as uint) |buf| {
|
||||
w.write(buf);
|
||||
}
|
||||
|
||||
bufrelease(ob);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'self> fmt::Default for Markdown<'self> {
|
||||
fn fmt(md: &Markdown<'self>, fmt: &mut fmt::Formatter) {
|
||||
// This is actually common enough to special-case
|
||||
if md.len() == 0 { return; }
|
||||
|
||||
render(fmt.buf, md.as_slice());
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ use syntax::ast;
|
||||
use clean;
|
||||
use doctree;
|
||||
use fold::DocFolder;
|
||||
use html::format::{VisSpace, Method};
|
||||
use html::format::{VisSpace, Method, PuritySpace};
|
||||
use html::layout;
|
||||
use html::markdown::Markdown;
|
||||
|
||||
@ -288,7 +288,9 @@ impl<'self> DocFolder for Cache {
|
||||
} else { false };
|
||||
match item.inner {
|
||||
clean::StructItem(*) | clean::EnumItem(*) |
|
||||
clean::TypedefItem(*) | clean::TraitItem(*) => {
|
||||
clean::TypedefItem(*) | clean::TraitItem(*) |
|
||||
clean::FunctionItem(*) | clean::ModuleItem(*) |
|
||||
clean::VariantItem(*) => {
|
||||
self.paths.insert(item.id, (self.stack.clone(), shortty(&item)));
|
||||
}
|
||||
_ => {}
|
||||
@ -401,8 +403,16 @@ impl Context {
|
||||
let mut task = task::task();
|
||||
task.unlinked(); // we kill things manually
|
||||
task.name(format!("worker{}", i));
|
||||
do task.spawn_with(cache.clone()) |cache| {
|
||||
task.spawn_with(cache.clone(),
|
||||
|cache| worker(cache, &port, &chan, &prog_chan));
|
||||
|
||||
fn worker(cache: RWArc<Cache>,
|
||||
port: &SharedPort<Work>,
|
||||
chan: &SharedChan<Work>,
|
||||
prog_chan: &SharedChan<Progress>) {
|
||||
#[fixed_stack_segment]; // we hit markdown FFI *a lot*
|
||||
local_data::set(cache_key, cache);
|
||||
|
||||
loop {
|
||||
match port.recv() {
|
||||
Process(cx, item) => {
|
||||
@ -425,28 +435,20 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
let watcher_chan = chan.clone();
|
||||
let (done_port, done_chan) = comm::stream();
|
||||
do task::spawn {
|
||||
let mut jobs = 0;
|
||||
loop {
|
||||
match prog_port.recv() {
|
||||
JobNew => jobs += 1,
|
||||
JobDone => jobs -= 1,
|
||||
}
|
||||
|
||||
if jobs == 0 { break }
|
||||
chan.send(Process(self, item));
|
||||
let mut jobs = 1;
|
||||
loop {
|
||||
match prog_port.recv() {
|
||||
JobNew => jobs += 1,
|
||||
JobDone => jobs -= 1,
|
||||
}
|
||||
|
||||
for _ in range(0, WORKERS) {
|
||||
watcher_chan.send(Die);
|
||||
}
|
||||
done_chan.send(());
|
||||
if jobs == 0 { break }
|
||||
}
|
||||
|
||||
prog_chan.send(JobNew);
|
||||
chan.send(Process(self, item));
|
||||
done_port.recv();
|
||||
for _ in range(0, WORKERS) {
|
||||
chan.send(Die);
|
||||
}
|
||||
}
|
||||
|
||||
fn item(&mut self, item: clean::Item, f: &fn(&mut Context, clean::Item)) {
|
||||
@ -479,6 +481,8 @@ impl Context {
|
||||
}
|
||||
|
||||
match item.inner {
|
||||
// modules are special because they add a namespace. We also need to
|
||||
// recurse into the items of the module as well.
|
||||
clean::ModuleItem(*) => {
|
||||
let name = item.name.get_ref().to_owned();
|
||||
let item = Cell::new(item);
|
||||
@ -498,11 +502,29 @@ impl Context {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Things which don't have names (like impls) don't get special
|
||||
// pages dedicated to them.
|
||||
_ if item.name.is_some() => {
|
||||
let dst = self.dst.push(item_path(&item));
|
||||
let writer = dst.open_writer(io::CreateOrTruncate);
|
||||
render(writer.unwrap(), self, &item, true);
|
||||
|
||||
// recurse if necessary
|
||||
let name = item.name.get_ref().clone();
|
||||
match item.inner {
|
||||
clean::EnumItem(e) => {
|
||||
let mut it = e.variants.move_iter();
|
||||
do self.recurse(name) |this| {
|
||||
for item in it {
|
||||
f(this, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -567,6 +589,7 @@ impl<'self> fmt::Default for Item<'self> {
|
||||
clean::StructItem(ref s) => item_struct(fmt.buf, it.item, s),
|
||||
clean::EnumItem(ref e) => item_enum(fmt.buf, it.item, e),
|
||||
clean::TypedefItem(ref t) => item_typedef(fmt.buf, it.item, t),
|
||||
clean::VariantItem(*) => item_variant(fmt.buf, it.cx, it.item),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -615,13 +638,21 @@ fn document(w: &mut io::Writer, item: &clean::Item) {
|
||||
fn item_module(w: &mut io::Writer, cx: &Context,
|
||||
item: &clean::Item, items: &[clean::Item]) {
|
||||
document(w, item);
|
||||
debug2!("{:?}", items);
|
||||
let mut indices = vec::from_fn(items.len(), |i| i);
|
||||
|
||||
fn lt(i1: &clean::Item, i2: &clean::Item) -> bool {
|
||||
fn lt(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> bool {
|
||||
if shortty(i1) == shortty(i2) {
|
||||
return i1.name < i2.name;
|
||||
}
|
||||
match (&i1.inner, &i2.inner) {
|
||||
(&clean::ViewItemItem(ref a), &clean::ViewItemItem(ref b)) => {
|
||||
match (&a.inner, &b.inner) {
|
||||
(&clean::ExternMod(*), _) => true,
|
||||
(_, &clean::ExternMod(*)) => false,
|
||||
_ => idx1 < idx2,
|
||||
}
|
||||
}
|
||||
(&clean::ViewItemItem(*), _) => true,
|
||||
(_, &clean::ViewItemItem(*)) => false,
|
||||
(&clean::ModuleItem(*), _) => true,
|
||||
@ -638,18 +669,19 @@ fn item_module(w: &mut io::Writer, cx: &Context,
|
||||
(_, &clean::FunctionItem(*)) => false,
|
||||
(&clean::TypedefItem(*), _) => true,
|
||||
(_, &clean::TypedefItem(*)) => false,
|
||||
_ => false,
|
||||
_ => idx1 < idx2,
|
||||
}
|
||||
}
|
||||
|
||||
debug2!("{:?}", indices);
|
||||
do sort::quick_sort(indices) |&i1, &i2| {
|
||||
lt(&items[i1], &items[i2])
|
||||
lt(&items[i1], &items[i2], i1, i2)
|
||||
}
|
||||
|
||||
debug2!("{:?}", indices);
|
||||
let mut curty = "";
|
||||
for &idx in indices.iter() {
|
||||
let myitem = &items[idx];
|
||||
if myitem.name.is_none() { loop }
|
||||
|
||||
let myty = shortty(myitem);
|
||||
if myty != curty {
|
||||
@ -687,17 +719,43 @@ fn item_module(w: &mut io::Writer, cx: &Context,
|
||||
|
||||
write!(w, "
|
||||
<tr>
|
||||
<td><code>{}: {} = </code>{}</td>
|
||||
<td><code>{}static {}: {} = </code>{}</td>
|
||||
<td class='docblock'>{} </td>
|
||||
</tr>
|
||||
",
|
||||
VisSpace(myitem.visibility),
|
||||
*myitem.name.get_ref(),
|
||||
s.type_,
|
||||
Initializer(s.expr),
|
||||
Markdown(blank(myitem.doc_value())));
|
||||
}
|
||||
|
||||
clean::ViewItemItem(ref item) => {
|
||||
match item.inner {
|
||||
clean::ExternMod(ref name, ref src, _, _) => {
|
||||
write!(w, "<tr><td><code>extern mod {}",
|
||||
name.as_slice());
|
||||
match *src {
|
||||
Some(ref src) => write!(w, " = \"{}\"",
|
||||
src.as_slice()),
|
||||
None => {}
|
||||
}
|
||||
write!(w, ";</code></td></tr>");
|
||||
}
|
||||
|
||||
clean::Import(ref imports) => {
|
||||
for import in imports.iter() {
|
||||
write!(w, "<tr><td><code>{}{}</code></td></tr>",
|
||||
VisSpace(myitem.visibility),
|
||||
*import);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_ => {
|
||||
if myitem.name.is_none() { loop }
|
||||
write!(w, "
|
||||
<tr>
|
||||
<td><a class='{class}' href='{href}'
|
||||
@ -717,8 +775,9 @@ fn item_module(w: &mut io::Writer, cx: &Context,
|
||||
}
|
||||
|
||||
fn item_function(w: &mut io::Writer, it: &clean::Item, f: &clean::Function) {
|
||||
write!(w, "<pre class='fn'>{vis}fn {name}{generics}{decl}</pre>",
|
||||
write!(w, "<pre class='fn'>{vis}{purity}fn {name}{generics}{decl}</pre>",
|
||||
vis = VisSpace(it.visibility),
|
||||
purity = PuritySpace(f.purity),
|
||||
name = it.name.get_ref().as_slice(),
|
||||
generics = f.generics,
|
||||
decl = f.decl);
|
||||
@ -830,8 +889,8 @@ fn render_method(w: &mut io::Writer, meth: &clean::Item, withlink: bool) {
|
||||
g: &clean::Generics, selfty: &clean::SelfTy, d: &clean::FnDecl,
|
||||
withlink: bool) {
|
||||
write!(w, "{}fn {withlink, select,
|
||||
true{<a href='\\#fn.{name}'>{name}</a>}
|
||||
other{{name}}
|
||||
true{<a href='\\#fn.{name}' class='fnname'>{name}</a>}
|
||||
other{<span class='fnname'>{name}</span>}
|
||||
}{generics}{decl}",
|
||||
match purity {
|
||||
ast::unsafe_fn => "unsafe ",
|
||||
@ -872,7 +931,8 @@ fn item_enum(w: &mut io::Writer, it: &clean::Item, e: &clean::Enum) {
|
||||
} else {
|
||||
write!(w, " \\{\n");
|
||||
for v in e.variants.iter() {
|
||||
let name = v.name.get_ref().as_slice();
|
||||
let name = format!("<a name='variant.{0}'>{0}</a>",
|
||||
v.name.get_ref().as_slice());
|
||||
match v.inner {
|
||||
clean::VariantItem(ref var) => {
|
||||
match var.kind {
|
||||
@ -1101,3 +1161,12 @@ fn build_sidebar(m: &clean::Module) -> HashMap<~str, ~[~str]> {
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
fn item_variant(w: &mut io::Writer, cx: &Context, it: &clean::Item) {
|
||||
write!(w, "<DOCTYPE html><html><head>\
|
||||
<meta http-equiv='refresh' content='0; \
|
||||
url=../enum.{}.html\\#variant.{}'>\
|
||||
</head><body></body></html>",
|
||||
*cx.current.last(),
|
||||
it.name.get_ref().as_slice());
|
||||
}
|
||||
|
@ -221,6 +221,7 @@ a {
|
||||
.content a.enum, .block a.current.enum { color: #5e9766; }
|
||||
.content a.struct, .block a.current.struct { color: #e53700; }
|
||||
.content a.fn, .block a.current.fn { color: #8c6067; }
|
||||
.content .fnname { color: #8c6067; }
|
||||
|
||||
.search-input {
|
||||
border: 2px solid #f2f2f2;
|
||||
|
@ -11,8 +11,9 @@
|
||||
use std::num;
|
||||
use std::uint;
|
||||
|
||||
use clean;
|
||||
use syntax::ast;
|
||||
|
||||
use clean;
|
||||
use clean::Item;
|
||||
use plugins;
|
||||
use fold;
|
||||
@ -47,6 +48,78 @@ pub fn strip_hidden(crate: clean::Crate) -> plugins::PluginResult {
|
||||
(crate, None)
|
||||
}
|
||||
|
||||
/// Strip private items from the point of view of a crate or externally from a
|
||||
/// crate, specified by the `xcrate` flag.
|
||||
pub fn strip_private(crate: clean::Crate) -> plugins::PluginResult {
|
||||
struct Stripper;
|
||||
impl fold::DocFolder for Stripper {
|
||||
fn fold_item(&mut self, i: Item) -> Option<Item> {
|
||||
match i.inner {
|
||||
// These items can all get re-exported
|
||||
clean::TypedefItem(*) | clean::StaticItem(*) |
|
||||
clean::StructItem(*) | clean::EnumItem(*) |
|
||||
clean::TraitItem(*) | clean::FunctionItem(*) |
|
||||
clean::ViewItemItem(*) | clean::MethodItem(*) => {
|
||||
// XXX: re-exported items should get surfaced in the docs as
|
||||
// well (using the output of resolve analysis)
|
||||
if i.visibility != Some(ast::public) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
// These are public-by-default (if the enum was public)
|
||||
clean::VariantItem(*) => {
|
||||
if i.visibility == Some(ast::private) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
// We show these regardless of whether they're public/private
|
||||
// because it's useful to see sometimes
|
||||
clean::StructFieldItem(*) => {}
|
||||
|
||||
// handled below
|
||||
clean::ModuleItem(*) => {}
|
||||
|
||||
// impls/tymethods have no control over privacy
|
||||
clean::ImplItem(*) | clean::TyMethodItem(*) => {}
|
||||
}
|
||||
|
||||
let fastreturn = match i.inner {
|
||||
// nothing left to do for traits (don't want to filter their
|
||||
// methods out, visibility controlled by the trait)
|
||||
clean::TraitItem(*) => true,
|
||||
|
||||
// implementations of traits are always public.
|
||||
clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
|
||||
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let i = if fastreturn {
|
||||
return Some(i);
|
||||
} else {
|
||||
self.fold_item_recur(i)
|
||||
};
|
||||
|
||||
match i {
|
||||
Some(i) => {
|
||||
match i.inner {
|
||||
// emptied modules/impls have no need to exist
|
||||
clean::ModuleItem(ref m) if m.items.len() == 0 => None,
|
||||
clean::ImplItem(ref i) if i.methods.len() == 0 => None,
|
||||
_ => Some(i),
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut stripper = Stripper;
|
||||
let crate = stripper.fold_crate(crate);
|
||||
(crate, None)
|
||||
}
|
||||
|
||||
pub fn unindent_comments(crate: clean::Crate) -> plugins::PluginResult {
|
||||
struct CommentCleaner;
|
||||
impl fold::DocFolder for CommentCleaner {
|
||||
@ -69,27 +142,6 @@ pub fn unindent_comments(crate: clean::Crate) -> plugins::PluginResult {
|
||||
(crate, None)
|
||||
}
|
||||
|
||||
pub fn collapse_privacy(crate: clean::Crate) -> plugins::PluginResult {
|
||||
struct PrivacyCollapser {
|
||||
stack: ~[clean::Visibility]
|
||||
}
|
||||
impl fold::DocFolder for PrivacyCollapser {
|
||||
fn fold_item(&mut self, mut i: Item) -> Option<Item> {
|
||||
if i.visibility.is_some() {
|
||||
if i.visibility == Some(ast::inherited) {
|
||||
i.visibility = Some(self.stack.last().clone());
|
||||
} else {
|
||||
self.stack.push(i.visibility.clone().unwrap());
|
||||
}
|
||||
}
|
||||
self.fold_item_recur(i)
|
||||
}
|
||||
}
|
||||
let mut privacy = PrivacyCollapser { stack: ~[] };
|
||||
let crate = privacy.fold_crate(crate);
|
||||
(crate, None)
|
||||
}
|
||||
|
||||
pub fn collapse_docs(crate: clean::Crate) -> plugins::PluginResult {
|
||||
struct Collapser;
|
||||
impl fold::DocFolder for Collapser {
|
||||
@ -110,7 +162,7 @@ pub fn collapse_docs(crate: clean::Crate) -> plugins::PluginResult {
|
||||
_ => true
|
||||
}).map(|x| x.clone()).collect();
|
||||
if "" != docstr {
|
||||
a.push(clean::NameValue(~"doc", docstr.trim().to_owned()));
|
||||
a.push(clean::NameValue(~"doc", docstr));
|
||||
}
|
||||
i.attrs = a;
|
||||
self.fold_item_recur(i)
|
||||
@ -121,7 +173,6 @@ pub fn collapse_docs(crate: clean::Crate) -> plugins::PluginResult {
|
||||
(crate, None)
|
||||
}
|
||||
|
||||
// n.b. this is copied from src/librustdoc/unindent_pass.rs
|
||||
pub fn unindent(s: &str) -> ~str {
|
||||
let lines = s.any_line_iter().collect::<~[&str]>();
|
||||
let mut saw_first_line = false;
|
||||
|
@ -45,6 +45,28 @@ pub mod visit_ast;
|
||||
|
||||
pub static SCHEMA_VERSION: &'static str = "0.8.0";
|
||||
|
||||
type Pass = (&'static str, // name
|
||||
extern fn(clean::Crate) -> plugins::PluginResult, // fn
|
||||
&'static str); // description
|
||||
|
||||
static PASSES: &'static [Pass] = &[
|
||||
("strip-hidden", passes::strip_hidden,
|
||||
"strips all doc(hidden) items from the output"),
|
||||
("unindent-comments", passes::unindent_comments,
|
||||
"removes excess indentation on comments in order for markdown to like it"),
|
||||
("collapse-docs", passes::collapse_docs,
|
||||
"concatenates all document attributes into one document attribute"),
|
||||
("strip-private", passes::strip_private,
|
||||
"strips all private items from a crate which cannot be seen externally"),
|
||||
];
|
||||
|
||||
static DEFAULT_PASSES: &'static [&'static str] = &[
|
||||
"strip-hidden",
|
||||
"strip-private",
|
||||
"collapse-docs",
|
||||
"unindent-comments",
|
||||
];
|
||||
|
||||
local_data_key!(pub ctxtkey: @core::DocContext)
|
||||
|
||||
enum OutputFormat {
|
||||
@ -61,7 +83,8 @@ pub fn opts() -> ~[groups::OptGroup] {
|
||||
optmulti("L", "library-path", "directory to add to crate search path",
|
||||
"DIR"),
|
||||
optmulti("", "plugin-path", "directory to load plugins from", "DIR"),
|
||||
optmulti("", "passes", "space separated list of passes to also run",
|
||||
optmulti("", "passes", "space separated list of passes to also run, a \
|
||||
value of `list` will print available passes",
|
||||
"PASSES"),
|
||||
optmulti("", "plugins", "space separated list of plugins to also load",
|
||||
"PLUGINS"),
|
||||
@ -86,6 +109,22 @@ pub fn main_args(args: &[~str]) -> int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let mut default_passes = !matches.opt_present("nodefaults");
|
||||
let mut passes = matches.opt_strs("passes");
|
||||
let mut plugins = matches.opt_strs("plugins");
|
||||
|
||||
if passes == ~[~"list"] {
|
||||
println("Available passes for running rustdoc:");
|
||||
for &(name, _, description) in PASSES.iter() {
|
||||
println!("{:>20s} - {}", name, description);
|
||||
}
|
||||
println("\nDefault passes for rustdoc:");
|
||||
for &name in DEFAULT_PASSES.iter() {
|
||||
println!("{:>20s}", name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
let (format, cratefile) = match matches.free.clone() {
|
||||
[~"json", crate] => (JSON, crate),
|
||||
[~"html", crate] => (HTML, crate),
|
||||
@ -118,9 +157,6 @@ pub fn main_args(args: &[~str]) -> int {
|
||||
|
||||
// Process all of the crate attributes, extracting plugin metadata along
|
||||
// with the passes which we are supposed to run.
|
||||
let mut default_passes = !matches.opt_present("nodefaults");
|
||||
let mut passes = matches.opt_strs("passes");
|
||||
let mut plugins = matches.opt_strs("plugins");
|
||||
match crate.module.get_ref().doc_list() {
|
||||
Some(nested) => {
|
||||
for inner in nested.iter() {
|
||||
@ -145,19 +181,20 @@ pub fn main_args(args: &[~str]) -> int {
|
||||
None => {}
|
||||
}
|
||||
if default_passes {
|
||||
passes.unshift(~"collapse-docs");
|
||||
passes.unshift(~"unindent-comments");
|
||||
for name in DEFAULT_PASSES.rev_iter() {
|
||||
passes.unshift(name.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
// Load all plugins/passes into a PluginManager
|
||||
let mut pm = plugins::PluginManager::new(Path("/tmp/rustdoc_ng/plugins"));
|
||||
for pass in passes.iter() {
|
||||
let plugin = match pass.as_slice() {
|
||||
"strip-hidden" => passes::strip_hidden,
|
||||
"unindent-comments" => passes::unindent_comments,
|
||||
"collapse-docs" => passes::collapse_docs,
|
||||
"collapse-privacy" => passes::collapse_privacy,
|
||||
s => { error!("unknown pass %s, skipping", s); loop },
|
||||
let plugin = match PASSES.iter().position(|&(p, _, _)| p == *pass) {
|
||||
Some(i) => PASSES[i].n1(),
|
||||
None => {
|
||||
error2!("unknown pass {}, skipping", *pass);
|
||||
loop
|
||||
},
|
||||
};
|
||||
pm.add_plugin(plugin);
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ impl RustdocVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_fn(item: &ast::item, fd: &ast::fn_decl, _purity: &ast::purity,
|
||||
fn visit_fn(item: &ast::item, fd: &ast::fn_decl, purity: &ast::purity,
|
||||
_abi: &AbiSet, gen: &ast::Generics) -> Function {
|
||||
debug!("Visiting fn");
|
||||
Function {
|
||||
@ -86,6 +86,7 @@ impl RustdocVisitor {
|
||||
name: item.ident,
|
||||
where: item.span,
|
||||
generics: gen.clone(),
|
||||
purity: *purity,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,4 +9,4 @@
|
||||
// except according to those terms.
|
||||
|
||||
pub fn do_nothing() {
|
||||
}
|
||||
}
|
||||
|
@ -14,4 +14,4 @@ fn g() {
|
||||
while(x < 1000) {
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,4 +9,4 @@
|
||||
// except according to those terms.
|
||||
|
||||
pub fn do_nothing() {
|
||||
}
|
||||
}
|
||||
|
@ -52,15 +52,15 @@ use to_str::ToStr;
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::not(true)
|
||||
* false
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::not(false)
|
||||
* true
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn not(v: bool) -> bool { !v }
|
||||
|
||||
@ -69,15 +69,15 @@ pub fn not(v: bool) -> bool { !v }
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::and(true, false)
|
||||
* false
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::and(true, true)
|
||||
* true
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn and(a: bool, b: bool) -> bool { a && b }
|
||||
|
||||
@ -86,15 +86,15 @@ pub fn and(a: bool, b: bool) -> bool { a && b }
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::or(true, false)
|
||||
* true
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::or(false, false)
|
||||
* false
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn or(a: bool, b: bool) -> bool { a || b }
|
||||
|
||||
@ -105,15 +105,15 @@ pub fn or(a: bool, b: bool) -> bool { a || b }
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::xor(true, false)
|
||||
* true
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::xor(true, true)
|
||||
* false
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) }
|
||||
|
||||
@ -126,15 +126,15 @@ pub fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) }
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::implies(true, true)
|
||||
* true
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::implies(true, false)
|
||||
* false
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn implies(a: bool, b: bool) -> bool { !a || b }
|
||||
|
||||
@ -143,15 +143,15 @@ pub fn implies(a: bool, b: bool) -> bool { !a || b }
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::is_true(true)
|
||||
* true
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::is_true(false)
|
||||
* false
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn is_true(v: bool) -> bool { v }
|
||||
|
||||
@ -160,15 +160,15 @@ pub fn is_true(v: bool) -> bool { v }
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::is_false(false)
|
||||
* true
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::is_false(true)
|
||||
* false
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn is_false(v: bool) -> bool { !v }
|
||||
|
||||
@ -179,20 +179,20 @@ pub fn is_false(v: bool) -> bool { !v }
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> FromStr::from_str::<bool>("true")
|
||||
* Some(true)
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> FromStr::from_str::<bool>("false")
|
||||
* Some(false)
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> FromStr::from_str::<bool>("not even a boolean")
|
||||
* None
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
impl FromStr for bool {
|
||||
fn from_str(s: &str) -> Option<bool> {
|
||||
@ -209,15 +209,15 @@ impl FromStr for bool {
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> true.to_str()
|
||||
* "true"
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> false.to_str()
|
||||
* "false"
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
impl ToStr for bool {
|
||||
#[inline]
|
||||
@ -232,11 +232,11 @@ impl ToStr for bool {
|
||||
* There are no guarantees about the order values will be given.
|
||||
*
|
||||
* # Examples
|
||||
* ~~~
|
||||
* ```
|
||||
* do std::bool::all_values |x: bool| {
|
||||
* println(x.to_str())
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn all_values(blk: &fn(v: bool)) {
|
||||
blk(true);
|
||||
@ -248,15 +248,15 @@ pub fn all_values(blk: &fn(v: bool)) {
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::to_bit(true)
|
||||
* 1
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> std::bool::to_bit(false)
|
||||
* 0
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
#[inline]
|
||||
pub fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }
|
||||
@ -269,12 +269,12 @@ pub fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }
|
||||
* ~~~rust
|
||||
* rusti> !true
|
||||
* false
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~rust
|
||||
* rusti> !false
|
||||
* true
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
#[cfg(not(test))]
|
||||
impl Not<bool> for bool {
|
||||
@ -299,25 +299,25 @@ impl TotalOrd for bool {
|
||||
*
|
||||
* Two booleans are equal if they have the same value.
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> false.eq(&true)
|
||||
* false
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> false == false
|
||||
* true
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> false != true
|
||||
* true
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* rusti> false.ne(&false)
|
||||
* false
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
#[cfg(not(test))]
|
||||
impl Eq for bool {
|
||||
|
@ -38,7 +38,7 @@ unnecessary amounts of allocations.
|
||||
|
||||
An example of creating and using a C string would be:
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
use std::libc;
|
||||
externfn!(fn puts(s: *libc::c_char))
|
||||
|
||||
@ -56,7 +56,7 @@ do my_c_string.with_ref |c_buffer| {
|
||||
do my_string.with_c_str |c_buffer| {
|
||||
unsafe { puts(c_buffer); }
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
*/
|
||||
|
||||
@ -204,9 +204,9 @@ pub trait ToCStr {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let s = "PATH".with_c_str(|path| libc::getenv(path))
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
|
@ -67,10 +67,10 @@ pub unsafe fn bump_box_refcount<T>(t: @T) { forget(t); }
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* let v: &[u8] = transmute("L");
|
||||
* assert!(v == [76u8]);
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
#[inline]
|
||||
pub unsafe fn transmute<L, G>(thing: L) -> G {
|
||||
|
@ -19,17 +19,17 @@ same manner.
|
||||
|
||||
A condition is declared through the `condition!` macro provided by the compiler:
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
condition! {
|
||||
pub my_error: int -> ~str;
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
This macro declares an inner module called `my_error` with one static variable,
|
||||
`cond` that is a static `Condition` instance. To help understand what the other
|
||||
parameters are used for, an example usage of this condition would be:
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
do my_error::cond.trap(|raised_int| {
|
||||
|
||||
// the condition `my_error` was raised on, and the value it raised is stored
|
||||
@ -51,7 +51,7 @@ do my_error::cond.trap(|raised_int| {
|
||||
println(my_error::cond.raise(4)); // prints "oh well"
|
||||
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
Condition handling is useful in cases where propagating errors is either to
|
||||
cumbersome or just not necessary in the first place. It should also be noted,
|
||||
@ -96,14 +96,14 @@ impl<T, U> Condition<T, U> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~{.rust}
|
||||
/// ```rust
|
||||
/// condition! { my_error: int -> int; }
|
||||
///
|
||||
/// let trap = my_error::cond.trap(|error| error + 3);
|
||||
///
|
||||
/// // use `trap`'s inside method to register the handler and then run a
|
||||
/// // block of code with the handler registered
|
||||
/// ~~~
|
||||
/// ```
|
||||
pub fn trap<'a>(&'a self, h: &'a fn(T) -> U) -> Trap<'a, T, U> {
|
||||
let h: Closure = unsafe { ::cast::transmute(h) };
|
||||
let prev = local_data::get(self.key, |k| k.map(|&x| *x));
|
||||
@ -173,14 +173,14 @@ impl<'self, T, U> Trap<'self, T, U> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~{.rust}
|
||||
/// ```rust
|
||||
/// condition! { my_error: int -> int; }
|
||||
///
|
||||
/// let result = do my_error::cond.trap(|error| error + 3).inside {
|
||||
/// my_error::cond.raise(4)
|
||||
/// };
|
||||
/// assert_eq!(result, 7);
|
||||
/// ~~~
|
||||
/// ```
|
||||
pub fn inside<V>(&self, inner: &'self fn() -> V) -> V {
|
||||
let _g = Guard { cond: self.cond };
|
||||
debug!("Trap: pushing handler to TLS");
|
||||
|
@ -33,14 +33,14 @@ arguments directly while performing minimal allocations.
|
||||
|
||||
Some examples of the `format!` extension are:
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
format!("Hello") // => ~"Hello"
|
||||
format!("Hello, {:s}!", "world") // => ~"Hello, world!"
|
||||
format!("The number is {:d}", 1) // => ~"The number is 1"
|
||||
format!("{:?}", ~[3, 4]) // => ~"~[3, 4]"
|
||||
format!("{value}", value=4) // => ~"4"
|
||||
format!("{} {}", 1, 2) // => ~"1 2"
|
||||
~~~
|
||||
```
|
||||
|
||||
From these, you can see that the first argument is a format string. It is
|
||||
required by the compiler for this to be a string literal; it cannot be a
|
||||
@ -67,9 +67,9 @@ function, but the `format!` macro is a syntax extension which allows it to
|
||||
leverage named parameters. Named parameters are listed at the end of the
|
||||
argument list and have the syntax:
|
||||
|
||||
~~~
|
||||
```
|
||||
identifier '=' expression
|
||||
~~~
|
||||
```
|
||||
|
||||
It is illegal to put positional parameters (those without names) after arguments
|
||||
which have names. Like positional parameters, it is illegal to provided named
|
||||
@ -84,9 +84,9 @@ and if all references to one argument do not provide a type, then the format `?`
|
||||
is used (the type's rust-representation is printed). For example, this is an
|
||||
invalid format string:
|
||||
|
||||
~~~
|
||||
```
|
||||
{0:d} {0:s}
|
||||
~~~
|
||||
```
|
||||
|
||||
Because the first argument is both referred to as an integer as well as a
|
||||
string.
|
||||
@ -100,9 +100,9 @@ must have the type `uint`. Although a `uint` can be printed with `{:u}`, it is
|
||||
illegal to reference an argument as such. For example, this is another invalid
|
||||
format string:
|
||||
|
||||
~~~
|
||||
```
|
||||
{:.*s} {0:u}
|
||||
~~~
|
||||
```
|
||||
|
||||
### Formatting traits
|
||||
|
||||
@ -134,9 +134,9 @@ is `?` which is defined for all types by default.
|
||||
When implementing a format trait for your own time, you will have to implement a
|
||||
method of the signature:
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
fn fmt(value: &T, f: &mut std::fmt::Formatter);
|
||||
~~~
|
||||
```
|
||||
|
||||
Your type will be passed by-reference in `value`, and then the function should
|
||||
emit output into the `f.buf` stream. It is up to each format trait
|
||||
@ -150,14 +150,14 @@ helper methods.
|
||||
There are a number of related macros in the `format!` family. The ones that are
|
||||
currently implemented are:
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
format! // described above
|
||||
write! // first argument is a &mut rt::io::Writer, the destination
|
||||
writeln! // same as write but appends a newline
|
||||
print! // the format string is printed to the standard output
|
||||
println! // same as print but appends a newline
|
||||
format_args! // described below.
|
||||
~~~
|
||||
```
|
||||
|
||||
|
||||
#### `write!`
|
||||
@ -167,12 +167,12 @@ specified stream. This is used to prevent intermediate allocations of format
|
||||
strings and instead directly write the output. Under the hood, this function is
|
||||
actually invoking the `write` function defined in this module. Example usage is:
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
use std::rt::io;
|
||||
|
||||
let mut w = io::mem::MemWriter::new();
|
||||
write!(&mut w as &mut io::Writer, "Hello {}!", "world");
|
||||
~~~
|
||||
```
|
||||
|
||||
#### `print!`
|
||||
|
||||
@ -180,10 +180,10 @@ This and `println` emit their output to stdout. Similarly to the `write!` macro,
|
||||
the goal of these macros is to avoid intermediate allocations when printing
|
||||
output. Example usage is:
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
print!("Hello {}!", "world");
|
||||
println!("I have a newline {}", "character at the end");
|
||||
~~~
|
||||
```
|
||||
|
||||
#### `format_args!`
|
||||
This is a curious macro which is used to safely pass around
|
||||
@ -193,13 +193,13 @@ references information on the stack. Under the hood, all of
|
||||
the related macros are implemented in terms of this. First
|
||||
off, some example usage is:
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
use std::fmt;
|
||||
|
||||
format_args!(fmt::format, "this returns {}", "~str");
|
||||
format_args!(|args| { fmt::write(my_writer, args) }, "some {}", "args");
|
||||
format_args!(my_fn, "format {}", "string");
|
||||
~~~
|
||||
```
|
||||
|
||||
The first argument of the `format_args!` macro is a function (or closure) which
|
||||
takes one argument of type `&fmt::Arguments`. This structure can then be
|
||||
@ -236,9 +236,9 @@ Furthermore, whenever a case is running, the special character `#` can be used
|
||||
to reference the string value of the argument which was selected upon. As an
|
||||
example:
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
format!("{0, select, other{#}}", "hello") // => ~"hello"
|
||||
~~~
|
||||
```
|
||||
|
||||
This example is the equivalent of `{0:s}` essentially.
|
||||
|
||||
@ -247,9 +247,9 @@ This example is the equivalent of `{0:s}` essentially.
|
||||
The select method is a switch over a `&str` parameter, and the parameter *must*
|
||||
be of the type `&str`. An example of the syntax is:
|
||||
|
||||
~~~
|
||||
```
|
||||
{0, select, male{...} female{...} other{...}}
|
||||
~~~
|
||||
```
|
||||
|
||||
Breaking this down, the `0`-th argument is selected upon with the `select`
|
||||
method, and then a number of cases follow. Each case is preceded by an
|
||||
@ -266,9 +266,9 @@ The plural method is a switch statement over a `uint` parameter, and the
|
||||
parameter *must* be a `uint`. A plural method in its full glory can be specified
|
||||
as:
|
||||
|
||||
~~~
|
||||
```
|
||||
{0, plural, offset=1 =1{...} two{...} many{...} other{...}}
|
||||
~~~
|
||||
```
|
||||
|
||||
To break this down, the first `0` indicates that this method is selecting over
|
||||
the value of the first positional parameter to the format string. Next, the
|
||||
@ -294,7 +294,7 @@ should not be too alien. Arguments are formatted with python-like syntax,
|
||||
meaning that arguments are surrounded by `{}` instead of the C-like `%`. The
|
||||
actual grammar for the formatting syntax is:
|
||||
|
||||
~~~
|
||||
```
|
||||
format_string := <text> [ format <text> ] *
|
||||
format := '{' [ argument ] [ ':' format_spec ] [ ',' function_spec ] '}'
|
||||
argument := integer | identifier
|
||||
@ -315,7 +315,7 @@ plural := 'plural' ',' [ 'offset:' integer ] ( selector arm ) *
|
||||
selector := '=' integer | keyword
|
||||
keyword := 'zero' | 'one' | 'two' | 'few' | 'many' | 'other'
|
||||
arm := '{' format_string '}'
|
||||
~~~
|
||||
```
|
||||
|
||||
## Formatting Parameters
|
||||
|
||||
@ -516,11 +516,11 @@ pub trait Float { fn fmt(&Self, &mut Formatter); }
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~{.rust}
|
||||
/// ```rust
|
||||
/// use std::fmt;
|
||||
/// let w: &mut io::Writer = ...;
|
||||
/// format_args!(|args| { fmt::write(w, args) }, "Hello, {}!", "world");
|
||||
/// ~~~
|
||||
/// ```
|
||||
pub fn write(output: &mut io::Writer, args: &Arguments) {
|
||||
unsafe { write_unsafe(output, args.fmt, args.args) }
|
||||
}
|
||||
@ -581,11 +581,11 @@ pub unsafe fn write_unsafe(output: &mut io::Writer,
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~{.rust}
|
||||
/// ```rust
|
||||
/// use std::fmt;
|
||||
/// let s = format_args!(fmt::format, "Hello, {}!", "world");
|
||||
/// assert_eq!(s, "Hello, world!");
|
||||
/// ~~~
|
||||
/// ```
|
||||
pub fn format(args: &Arguments) -> ~str {
|
||||
unsafe { format_unsafe(args.fmt, args.args) }
|
||||
}
|
||||
|
@ -1047,11 +1047,11 @@ pub fn FILE_reader(f: *libc::FILE, cleanup: bool) -> @Reader {
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* let stdin = std::io::stdin();
|
||||
* let line = stdin.read_line();
|
||||
* std::io::print(line);
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn stdin() -> @Reader {
|
||||
#[fixed_stack_segment]; #[inline(never)];
|
||||
@ -1650,10 +1650,10 @@ pub fn buffered_file_writer(path: &Path) -> Result<@Writer, ~str> {
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* let stdout = std::io::stdout();
|
||||
* stdout.write_str("hello\n");
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn stdout() -> @Writer { fd_writer(libc::STDOUT_FILENO as c_int, false) }
|
||||
|
||||
@ -1662,10 +1662,10 @@ pub fn stdout() -> @Writer { fd_writer(libc::STDOUT_FILENO as c_int, false) }
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* let stderr = std::io::stderr();
|
||||
* stderr.write_str("hello\n");
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn stderr() -> @Writer { fd_writer(libc::STDERR_FILENO as c_int, false) }
|
||||
|
||||
@ -1677,10 +1677,10 @@ pub fn stderr() -> @Writer { fd_writer(libc::STDERR_FILENO as c_int, false) }
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* // print is imported into the prelude, and so is always available.
|
||||
* print("hello");
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn print(s: &str) {
|
||||
stdout().write_str(s);
|
||||
@ -1693,10 +1693,10 @@ pub fn print(s: &str) {
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* // println is imported into the prelude, and so is always available.
|
||||
* println("hello");
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn println(s: &str) {
|
||||
stdout().write_line(s);
|
||||
|
@ -34,7 +34,7 @@ trait defined in this module. For loops can be viewed as a syntactical expansion
|
||||
into a `loop`, for example, the `for` loop in this example is essentially
|
||||
translated to the `loop` below.
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
let values = ~[1, 2, 3];
|
||||
|
||||
// "Syntactical sugar" taking advantage of an iterator
|
||||
@ -52,7 +52,7 @@ loop {
|
||||
None => { break }
|
||||
}
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
This `for` loop syntax can be applied to any iterator over any type.
|
||||
|
||||
@ -111,14 +111,14 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [0];
|
||||
/// let b = [1];
|
||||
/// let mut it = a.iter().chain(b.iter());
|
||||
/// assert_eq!(it.next().get(), &0);
|
||||
/// assert_eq!(it.next().get(), &1);
|
||||
/// assert!(it.next().is_none());
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn chain<U: Iterator<A>>(self, other: U) -> Chain<Self, U> {
|
||||
Chain{a: self, b: other, flag: false}
|
||||
@ -131,13 +131,13 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [0];
|
||||
/// let b = [1];
|
||||
/// let mut it = a.iter().zip(b.iter());
|
||||
/// assert_eq!(it.next().get(), (&0, &1));
|
||||
/// assert!(it.next().is_none());
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn zip<B, U: Iterator<B>>(self, other: U) -> Zip<Self, U> {
|
||||
Zip{a: self, b: other}
|
||||
@ -148,13 +148,13 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2];
|
||||
/// let mut it = a.iter().map(|&x| 2 * x);
|
||||
/// assert_eq!(it.next().get(), 2);
|
||||
/// assert_eq!(it.next().get(), 4);
|
||||
/// assert!(it.next().is_none());
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn map<'r, B>(self, f: &'r fn(A) -> B) -> Map<'r, A, B, Self> {
|
||||
Map{iter: self, f: f}
|
||||
@ -166,12 +166,12 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2];
|
||||
/// let mut it = a.iter().filter(|&x| *x > 1);
|
||||
/// assert_eq!(it.next().get(), &2);
|
||||
/// assert!(it.next().is_none());
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn filter<'r>(self, predicate: &'r fn(&A) -> bool) -> Filter<'r, A, Self> {
|
||||
Filter{iter: self, predicate: predicate}
|
||||
@ -183,12 +183,12 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2];
|
||||
/// let mut it = a.iter().filter_map(|&x| if x > 1 {Some(2 * x)} else {None});
|
||||
/// assert_eq!(it.next().get(), 4);
|
||||
/// assert!(it.next().is_none());
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn filter_map<'r, B>(self, f: &'r fn(A) -> Option<B>) -> FilterMap<'r, A, B, Self> {
|
||||
FilterMap { iter: self, f: f }
|
||||
@ -199,13 +199,13 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [100, 200];
|
||||
/// let mut it = a.iter().enumerate();
|
||||
/// assert_eq!(it.next().get(), (0, &100));
|
||||
/// assert_eq!(it.next().get(), (1, &200));
|
||||
/// assert!(it.next().is_none());
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn enumerate(self) -> Enumerate<Self> {
|
||||
Enumerate{iter: self, count: 0}
|
||||
@ -217,7 +217,7 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [100, 200, 300];
|
||||
/// let mut it = xs.iter().map(|&x|x).peekable();
|
||||
/// assert_eq!(it.peek().unwrap(), &100);
|
||||
@ -228,7 +228,7 @@ pub trait Iterator<A> {
|
||||
/// assert_eq!(it.next().unwrap(), 300);
|
||||
/// assert!(it.peek().is_none());
|
||||
/// assert!(it.next().is_none());
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn peekable(self) -> Peekable<A, Self> {
|
||||
Peekable{iter: self, peeked: None}
|
||||
@ -240,14 +240,14 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 2, 1];
|
||||
/// let mut it = a.iter().skip_while(|&a| *a < 3);
|
||||
/// assert_eq!(it.next().get(), &3);
|
||||
/// assert_eq!(it.next().get(), &2);
|
||||
/// assert_eq!(it.next().get(), &1);
|
||||
/// assert!(it.next().is_none());
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn skip_while<'r>(self, predicate: &'r fn(&A) -> bool) -> SkipWhile<'r, A, Self> {
|
||||
SkipWhile{iter: self, flag: false, predicate: predicate}
|
||||
@ -259,13 +259,13 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 2, 1];
|
||||
/// let mut it = a.iter().take_while(|&a| *a < 3);
|
||||
/// assert_eq!(it.next().get(), &1);
|
||||
/// assert_eq!(it.next().get(), &2);
|
||||
/// assert!(it.next().is_none());
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn take_while<'r>(self, predicate: &'r fn(&A) -> bool) -> TakeWhile<'r, A, Self> {
|
||||
TakeWhile{iter: self, flag: false, predicate: predicate}
|
||||
@ -276,13 +276,13 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter().skip(3);
|
||||
/// assert_eq!(it.next().get(), &4);
|
||||
/// assert_eq!(it.next().get(), &5);
|
||||
/// assert!(it.next().is_none());
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn skip(self, n: uint) -> Skip<Self> {
|
||||
Skip{iter: self, n: n}
|
||||
@ -293,14 +293,14 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter().take(3);
|
||||
/// assert_eq!(it.next().get(), &1);
|
||||
/// assert_eq!(it.next().get(), &2);
|
||||
/// assert_eq!(it.next().get(), &3);
|
||||
/// assert!(it.next().is_none());
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn take(self, n: uint) -> Take<Self> {
|
||||
Take{iter: self, n: n}
|
||||
@ -313,7 +313,7 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter().scan(1, |fac, &x| {
|
||||
/// *fac = *fac * x;
|
||||
@ -325,7 +325,7 @@ pub trait Iterator<A> {
|
||||
/// assert_eq!(it.next().get(), 24);
|
||||
/// assert_eq!(it.next().get(), 120);
|
||||
/// assert!(it.next().is_none());
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn scan<'r, St, B>(self, initial_state: St, f: &'r fn(&mut St, A) -> Option<B>)
|
||||
-> Scan<'r, A, B, Self, St> {
|
||||
@ -337,7 +337,7 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let xs = [2u, 3];
|
||||
/// let ys = [0u, 1, 0, 1, 2];
|
||||
/// let mut it = xs.iter().flat_map(|&x| count(0u, 1).take(x));
|
||||
@ -347,7 +347,7 @@ pub trait Iterator<A> {
|
||||
/// assert_eq!(x, ys[i]);
|
||||
/// i += 1;
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn flat_map<'r, B, U: Iterator<B>>(self, f: &'r fn(A) -> U)
|
||||
-> FlatMap<'r, A, Self, U> {
|
||||
@ -360,7 +360,7 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// fn process<U: Iterator<int>>(it: U) -> int {
|
||||
/// let mut it = it.fuse();
|
||||
/// let mut sum = 0;
|
||||
@ -378,7 +378,7 @@ pub trait Iterator<A> {
|
||||
/// }
|
||||
/// let x = ~[1,2,3,7,8,9];
|
||||
/// assert_eq!(process(x.move_iter()), 1006);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn fuse(self) -> Fuse<Self> {
|
||||
Fuse{iter: self, done: false}
|
||||
@ -390,7 +390,7 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
///let xs = [1u, 4, 2, 3, 8, 9, 6];
|
||||
///let sum = xs.iter()
|
||||
/// .map(|&x| x)
|
||||
@ -399,7 +399,7 @@ pub trait Iterator<A> {
|
||||
/// .inspect(|&x| debug!("%u made it through", x))
|
||||
/// .sum();
|
||||
///println(sum.to_str());
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn inspect<'r>(self, f: &'r fn(&A)) -> Inspect<'r, A, Self> {
|
||||
Inspect{iter: self, f: f}
|
||||
@ -409,13 +409,13 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::iter::count;
|
||||
///
|
||||
/// for i in count(0, 10) {
|
||||
/// printfln!("%d", i);
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn advance(&mut self, f: &fn(A) -> bool) -> bool {
|
||||
loop {
|
||||
@ -433,11 +433,11 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let b: ~[int] = a.iter().map(|&x| x).collect();
|
||||
/// assert!(a == b);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn collect<B: FromIterator<A>>(&mut self) -> B {
|
||||
FromIterator::from_iterator(self)
|
||||
@ -448,11 +448,11 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let b: ~[int] = a.iter().map(|&x| x).to_owned_vec();
|
||||
/// assert!(a == b);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn to_owned_vec(&mut self) -> ~[A] {
|
||||
self.collect()
|
||||
@ -463,12 +463,12 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter();
|
||||
/// assert!(it.nth(2).get() == &3);
|
||||
/// assert!(it.nth(2) == None);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn nth(&mut self, mut n: uint) -> Option<A> {
|
||||
loop {
|
||||
@ -485,10 +485,10 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// assert!(a.iter().last().get() == &5);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn last(&mut self) -> Option<A> {
|
||||
let mut last = None;
|
||||
@ -501,10 +501,10 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// assert!(a.iter().fold(0, |a, &b| a + b) == 15);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn fold<B>(&mut self, init: B, f: &fn(B, A) -> B) -> B {
|
||||
let mut accum = init;
|
||||
@ -521,12 +521,12 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter();
|
||||
/// assert!(it.len() == 5);
|
||||
/// assert!(it.len() == 0);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn len(&mut self) -> uint {
|
||||
self.fold(0, |cnt, _x| cnt + 1)
|
||||
@ -536,11 +536,11 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// assert!(a.iter().all(|&x| *x > 0));
|
||||
/// assert!(!a.iter().all(|&x| *x > 2));
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn all(&mut self, f: &fn(A) -> bool) -> bool {
|
||||
for x in *self { if !f(x) { return false; } }
|
||||
@ -552,12 +552,12 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter();
|
||||
/// assert!(it.any(|&x| *x == 3));
|
||||
/// assert!(!it.any(|&x| *x == 3));
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn any(&mut self, f: &fn(A) -> bool) -> bool {
|
||||
for x in *self { if f(x) { return true; } }
|
||||
@ -601,10 +601,10 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let xs = [-3, 0, 1, 5, -10];
|
||||
/// assert_eq!(*xs.iter().max_by(|x| x.abs()).unwrap(), -10);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn max_by<B: Ord>(&mut self, f: &fn(&A) -> B) -> Option<A> {
|
||||
self.fold(None, |max: Option<(A, B)>, x| {
|
||||
@ -625,10 +625,10 @@ pub trait Iterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let xs = [-3, 0, 1, 5, -10];
|
||||
/// assert_eq!(*xs.iter().min_by(|x| x.abs()).unwrap(), 0);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn min_by<B: Ord>(&mut self, f: &fn(&A) -> B) -> Option<A> {
|
||||
self.fold(None, |min: Option<(A, B)>, x| {
|
||||
@ -777,11 +777,11 @@ pub trait AdditiveIterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter().map(|&x| x);
|
||||
/// assert!(it.sum() == 15);
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn sum(&mut self) -> A;
|
||||
}
|
||||
|
||||
@ -800,7 +800,7 @@ pub trait MultiplicativeIterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::iter::count;
|
||||
///
|
||||
/// fn factorial(n: uint) -> uint {
|
||||
@ -809,7 +809,7 @@ pub trait MultiplicativeIterator<A> {
|
||||
/// assert!(factorial(0) == 1);
|
||||
/// assert!(factorial(1) == 1);
|
||||
/// assert!(factorial(5) == 120);
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn product(&mut self) -> A;
|
||||
}
|
||||
|
||||
@ -828,20 +828,20 @@ pub trait OrdIterator<A> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// assert!(a.iter().max().get() == &5);
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn max(&mut self) -> Option<A>;
|
||||
|
||||
/// Consumes the entire iterator to return the minimum element.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// assert!(a.iter().min().get() == &1);
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn min(&mut self) -> Option<A>;
|
||||
}
|
||||
|
||||
@ -873,12 +873,12 @@ pub trait ClonableIterator {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let a = count(1,1).take(1);
|
||||
/// let mut cy = a.cycle();
|
||||
/// assert_eq!(cy.next(), Some(1));
|
||||
/// assert_eq!(cy.next(), Some(1));
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn cycle(self) -> Cycle<Self>;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ To declare a new key for storing local data of a particular type, use the
|
||||
named and annotated. This name is then passed to the functions in this module to
|
||||
modify/read the slot specified by the key.
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
use std::local_data;
|
||||
|
||||
local_data_key!(key_int: int)
|
||||
@ -33,7 +33,7 @@ local_data::get(key_int, |opt| assert_eq!(opt, Some(&3)));
|
||||
|
||||
local_data::set(key_vector, ~[4]);
|
||||
local_data::get(key_vector, |opt| assert_eq!(opt, Some(&~[4])));
|
||||
~~~
|
||||
```
|
||||
|
||||
*/
|
||||
|
||||
|
@ -346,9 +346,9 @@ impl Round for f32 {
|
||||
///
|
||||
/// The fractional part of the number, satisfying:
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// assert!(x == trunc(x) + fract(x))
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
#[inline]
|
||||
fn fract(&self) -> f32 { *self - self.trunc() }
|
||||
|
@ -364,9 +364,9 @@ impl Round for f64 {
|
||||
///
|
||||
/// The fractional part of the number, satisfying:
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// assert!(x == trunc(x) + fract(x))
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
#[inline]
|
||||
fn fract(&self) -> f64 { *self - self.trunc() }
|
||||
|
@ -414,9 +414,9 @@ impl Round for float {
|
||||
///
|
||||
/// The fractional part of the number, satisfying:
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// assert!(x == trunc(x) + fract(x))
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
#[inline]
|
||||
fn fract(&self) -> float { *self - self.trunc() }
|
||||
|
@ -118,7 +118,7 @@ impl Div<$T,$T> for $T {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ~~~
|
||||
/// ```
|
||||
/// assert!( 8 / 3 == 2);
|
||||
/// assert!( 8 / -3 == -2);
|
||||
/// assert!(-8 / 3 == -2);
|
||||
@ -128,7 +128,7 @@ impl Div<$T,$T> for $T {
|
||||
/// assert!( 1 / -2 == 0);
|
||||
/// assert!(-1 / 2 == 0);
|
||||
/// assert!(-1 / -2 == 0);
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
#[inline]
|
||||
fn div(&self, other: &$T) -> $T { *self / *other }
|
||||
@ -139,13 +139,13 @@ impl Rem<$T,$T> for $T {
|
||||
///
|
||||
/// Returns the integer remainder after division, satisfying:
|
||||
///
|
||||
/// ~~~
|
||||
/// ```
|
||||
/// assert!((n / d) * d + (n % d) == n)
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ~~~
|
||||
/// ```
|
||||
/// assert!( 8 % 3 == 2);
|
||||
/// assert!( 8 % -3 == 2);
|
||||
/// assert!(-8 % 3 == -2);
|
||||
@ -155,7 +155,7 @@ impl Rem<$T,$T> for $T {
|
||||
/// assert!( 1 % -2 == 1);
|
||||
/// assert!(-1 % 2 == -1);
|
||||
/// assert!(-1 % -2 == -1);
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
#[inline]
|
||||
fn rem(&self, other: &$T) -> $T { *self % *other }
|
||||
@ -214,7 +214,7 @@ impl Integer for $T {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ~~~
|
||||
/// ```
|
||||
/// assert!(( 8).div_floor( 3) == 2);
|
||||
/// assert!(( 8).div_floor(-3) == -3);
|
||||
/// assert!((-8).div_floor( 3) == -3);
|
||||
@ -224,7 +224,7 @@ impl Integer for $T {
|
||||
/// assert!(( 1).div_floor(-2) == -1);
|
||||
/// assert!((-1).div_floor( 2) == -1);
|
||||
/// assert!((-1).div_floor(-2) == 0);
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
#[inline]
|
||||
fn div_floor(&self, other: &$T) -> $T {
|
||||
@ -240,13 +240,13 @@ impl Integer for $T {
|
||||
///
|
||||
/// Integer modulo, satisfying:
|
||||
///
|
||||
/// ~~~
|
||||
/// ```
|
||||
/// assert!(n.div_floor(d) * d + n.mod_floor(d) == n)
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ~~~
|
||||
/// ```
|
||||
/// assert!(( 8).mod_floor( 3) == 2);
|
||||
/// assert!(( 8).mod_floor(-3) == -1);
|
||||
/// assert!((-8).mod_floor( 3) == 1);
|
||||
@ -256,7 +256,7 @@ impl Integer for $T {
|
||||
/// assert!(( 1).mod_floor(-2) == -1);
|
||||
/// assert!((-1).mod_floor( 2) == 1);
|
||||
/// assert!((-1).mod_floor(-2) == -1);
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
#[inline]
|
||||
fn mod_floor(&self, other: &$T) -> $T {
|
||||
|
@ -82,12 +82,12 @@ pub trait Unsigned: Num {}
|
||||
|
||||
/// Times trait
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use num::Times;
|
||||
/// let ten = 10 as uint;
|
||||
/// let mut accum = 0;
|
||||
/// do ten.times { accum += 1; }
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
pub trait Times {
|
||||
fn times(&self, it: &fn());
|
||||
@ -357,10 +357,10 @@ pub trait Float: Real
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~
|
||||
/// ```
|
||||
/// let twenty: f32 = num::cast(0x14);
|
||||
/// assert_eq!(twenty, 20f32);
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
#[inline]
|
||||
pub fn cast<T:NumCast,U:NumCast>(n: T) -> U {
|
||||
|
@ -23,7 +23,7 @@ of a value and take action, always accounting for the `None` case.
|
||||
|
||||
# Example
|
||||
|
||||
~~~
|
||||
```
|
||||
let msg = Some(~"howdy");
|
||||
|
||||
// Take a reference to the contained string
|
||||
@ -37,7 +37,7 @@ let unwrapped_msg = match msg {
|
||||
Some(m) => m,
|
||||
None => ~"default message"
|
||||
};
|
||||
~~~
|
||||
```
|
||||
|
||||
*/
|
||||
|
||||
|
@ -65,14 +65,14 @@ fn ziggurat<R:Rng>(rng: &mut R,
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~
|
||||
/// ```
|
||||
/// use std::rand::distributions::StandardNormal;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let normal = 2.0 + (*rand::random::<StandardNormal>()) * 3.0;
|
||||
/// printfln!("%f is from a N(2, 9) distribution", normal)
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
pub struct StandardNormal(f64);
|
||||
|
||||
impl Rand for StandardNormal {
|
||||
@ -119,14 +119,14 @@ impl Rand for StandardNormal {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~
|
||||
/// ```
|
||||
/// use std::rand::distributions::Exp1;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let exp2 = (*rand::random::<Exp1>()) * 0.5;
|
||||
/// printfln!("%f is from a Exp(2) distribution", exp2);
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
pub struct Exp1(f64);
|
||||
|
||||
// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
|
||||
|
@ -21,7 +21,7 @@ distributions like normal and exponential.
|
||||
|
||||
# Examples
|
||||
|
||||
~~~ {.rust}
|
||||
```rust
|
||||
use std::rand;
|
||||
use std::rand::Rng;
|
||||
|
||||
@ -31,16 +31,16 @@ fn main() {
|
||||
printfln!("int: %d, uint: %u", rng.gen(), rng.gen())
|
||||
}
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
~~~ {.rust}
|
||||
```rust
|
||||
use std::rand;
|
||||
|
||||
fn main () {
|
||||
let tuple_ptr = rand::random::<~(f64, char)>();
|
||||
printfln!(tuple_ptr)
|
||||
}
|
||||
~~~
|
||||
```
|
||||
*/
|
||||
|
||||
use cast;
|
||||
@ -264,7 +264,7 @@ pub trait Rng {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
///
|
||||
/// fn main() {
|
||||
@ -273,7 +273,7 @@ pub trait Rng {
|
||||
/// printfln!(x);
|
||||
/// printfln!(rng.gen::<(float, bool)>());
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn gen<T: Rand>(&mut self) -> T {
|
||||
Rand::rand(self)
|
||||
@ -283,7 +283,7 @@ pub trait Rng {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
///
|
||||
/// fn main() {
|
||||
@ -292,7 +292,7 @@ pub trait Rng {
|
||||
/// printfln!(x);
|
||||
/// printfln!(rng.gen_vec::<(float, bool)>(5));
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn gen_vec<T: Rand>(&mut self, len: uint) -> ~[T] {
|
||||
vec::from_fn(len, |_| self.gen())
|
||||
}
|
||||
@ -308,7 +308,7 @@ pub trait Rng {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
///
|
||||
/// fn main() {
|
||||
@ -318,7 +318,7 @@ pub trait Rng {
|
||||
/// let m: i16 = rng.gen_integer_range(-40, 400);
|
||||
/// printfln!(m);
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn gen_integer_range<T: Rand + Int>(&mut self, low: T, high: T) -> T {
|
||||
assert!(low < high, "RNG.gen_integer_range called with low >= high");
|
||||
let range = (high - low).to_u64();
|
||||
@ -335,7 +335,7 @@ pub trait Rng {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
/// use std::rand::Rng;
|
||||
///
|
||||
@ -343,7 +343,7 @@ pub trait Rng {
|
||||
/// let mut rng = rand::rng();
|
||||
/// printfln!("%b", rng.gen_weighted_bool(3));
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn gen_weighted_bool(&mut self, n: uint) -> bool {
|
||||
n == 0 || self.gen_integer_range(0, n) == 0
|
||||
}
|
||||
@ -353,13 +353,13 @@ pub trait Rng {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
///
|
||||
/// fn main() {
|
||||
/// println(rand::task_rng().gen_ascii_str(10));
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn gen_ascii_str(&mut self, len: uint) -> ~str {
|
||||
static GEN_ASCII_STR_CHARSET: &'static [u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ\
|
||||
abcdefghijklmnopqrstuvwxyz\
|
||||
@ -381,14 +381,14 @@ pub trait Rng {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
///
|
||||
/// fn main() {
|
||||
/// printfln!(rand::task_rng().choose_option([1,2,4,8,16,32]));
|
||||
/// printfln!(rand::task_rng().choose_option([]));
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn choose_option<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> {
|
||||
if values.is_empty() {
|
||||
None
|
||||
@ -402,7 +402,7 @@ pub trait Rng {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
/// use std::rand::Rng;
|
||||
///
|
||||
@ -413,7 +413,7 @@ pub trait Rng {
|
||||
/// rand::Weighted {weight: 2, item: 'c'}];
|
||||
/// printfln!("%c", rng.choose_weighted(x));
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn choose_weighted<T:Clone>(&mut self, v: &[Weighted<T>]) -> T {
|
||||
self.choose_weighted_option(v).expect("Rng.choose_weighted: total weight is 0")
|
||||
}
|
||||
@ -423,7 +423,7 @@ pub trait Rng {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
/// use std::rand::Rng;
|
||||
///
|
||||
@ -434,7 +434,7 @@ pub trait Rng {
|
||||
/// rand::Weighted {weight: 2, item: 'c'}];
|
||||
/// printfln!(rng.choose_weighted_option(x));
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn choose_weighted_option<T:Clone>(&mut self, v: &[Weighted<T>])
|
||||
-> Option<T> {
|
||||
let mut total = 0u;
|
||||
@ -460,7 +460,7 @@ pub trait Rng {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
/// use std::rand::Rng;
|
||||
///
|
||||
@ -471,7 +471,7 @@ pub trait Rng {
|
||||
/// rand::Weighted {weight: 2, item: 'c'}];
|
||||
/// printfln!(rng.weighted_vec(x));
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn weighted_vec<T:Clone>(&mut self, v: &[Weighted<T>]) -> ~[T] {
|
||||
let mut r = ~[];
|
||||
for item in v.iter() {
|
||||
@ -486,13 +486,13 @@ pub trait Rng {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
///
|
||||
/// fn main() {
|
||||
/// printfln!(rand::task_rng().shuffle(~[1,2,3]));
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn shuffle<T>(&mut self, values: ~[T]) -> ~[T] {
|
||||
let mut v = values;
|
||||
self.shuffle_mut(v);
|
||||
@ -503,7 +503,7 @@ pub trait Rng {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
///
|
||||
/// fn main() {
|
||||
@ -514,7 +514,7 @@ pub trait Rng {
|
||||
/// rng.shuffle_mut(y);
|
||||
/// printfln!(y);
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn shuffle_mut<T>(&mut self, values: &mut [T]) {
|
||||
let mut i = values.len();
|
||||
while i >= 2u {
|
||||
@ -529,7 +529,7 @@ pub trait Rng {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
///
|
||||
/// fn main() {
|
||||
@ -537,7 +537,7 @@ pub trait Rng {
|
||||
/// let sample = rng.sample(range(1, 100), 5);
|
||||
/// printfln!(sample);
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn sample<A, T: Iterator<A>>(&mut self, iter: T, n: uint) -> ~[A] {
|
||||
let mut reservoir : ~[A] = vec::with_capacity(n);
|
||||
for (i, elem) in iter.enumerate() {
|
||||
|
@ -17,7 +17,7 @@
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ~~~
|
||||
//! ```
|
||||
//! let tcp_stream = TcpStream::connect(addr);
|
||||
//! let reader = BufferedReader::new(tcp_stream);
|
||||
//!
|
||||
@ -26,17 +26,17 @@
|
||||
//! Some(nread) => println!("Read {} bytes", nread),
|
||||
//! None => println!("At the end of the stream!")
|
||||
//! }
|
||||
//! ~~~
|
||||
//! ```
|
||||
//!
|
||||
//! ~~~
|
||||
//! ```
|
||||
//! let tcp_stream = TcpStream::connect(addr);
|
||||
//! let writer = BufferedWriter::new(tcp_stream);
|
||||
//!
|
||||
//! writer.write("hello, world".as_bytes());
|
||||
//! writer.flush();
|
||||
//! ~~~
|
||||
//! ```
|
||||
//!
|
||||
//! ~~~
|
||||
//! ```
|
||||
//! let tcp_stream = TcpStream::connect(addr);
|
||||
//! let stream = BufferedStream::new(tcp_stream);
|
||||
//!
|
||||
@ -48,7 +48,7 @@
|
||||
//! Some(nread) => println!("Read {} bytes", nread),
|
||||
//! None => println!("At the end of the stream!")
|
||||
//! }
|
||||
//! ~~~
|
||||
//! ```
|
||||
//!
|
||||
|
||||
use prelude::*;
|
||||
|
@ -477,7 +477,7 @@ pub trait FileSystemInfo {
|
||||
///
|
||||
/// * Check if a file exists, reading from it if so
|
||||
///
|
||||
/// ~~~{.rust}
|
||||
/// ```rust
|
||||
/// use std;
|
||||
/// use std::path::Path;
|
||||
/// use std::rt::io::file::{FileInfo, FileReader};
|
||||
@ -489,17 +489,17 @@ pub trait FileSystemInfo {
|
||||
/// reader.read(mem);
|
||||
/// // ...
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
/// * Is the given path a file?
|
||||
///
|
||||
/// ~~~{.rust}
|
||||
/// ```rust
|
||||
/// let f = get_file_path_from_wherever();
|
||||
/// match f.is_file() {
|
||||
/// true => doing_something_with_a_file(f),
|
||||
/// _ => {}
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
pub trait FileInfo : FileSystemInfo {
|
||||
/// Whether the underlying implemention (be it a file path,
|
||||
/// or something else) points at a "regular file" on the FS. Will return
|
||||
@ -574,7 +574,7 @@ impl FileInfo for Path { }
|
||||
///
|
||||
/// * Check if a directory exists, `mkdir`'ing it if not
|
||||
///
|
||||
/// ~~~{.rust}
|
||||
/// ```rust
|
||||
/// use std;
|
||||
/// use std::path::Path;
|
||||
/// use std::rt::io::file::{DirectoryInfo};
|
||||
@ -583,11 +583,11 @@ impl FileInfo for Path { }
|
||||
/// if !dir.exists() {
|
||||
/// dir.mkdir();
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
/// * Is the given path a directory? If so, iterate on its contents
|
||||
///
|
||||
/// ~~~{.rust}
|
||||
/// ```rust
|
||||
/// fn visit_dirs(dir: &Path, cb: &fn(&Path)) {
|
||||
/// if dir.is_dir() {
|
||||
/// let contents = dir.readdir();
|
||||
@ -598,7 +598,7 @@ impl FileInfo for Path { }
|
||||
/// }
|
||||
/// else { fail!("nope"); }
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
trait DirectoryInfo : FileSystemInfo {
|
||||
/// Whether the underlying implemention (be it a file path,
|
||||
/// or something else) is pointing at a directory in the underlying FS.
|
||||
@ -971,4 +971,4 @@ mod test {
|
||||
dir.rmdir();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,4 +47,4 @@ impl MockWriter {
|
||||
impl Writer for MockWriter {
|
||||
fn write(&mut self, buf: &[u8]) { (self.write)(buf) }
|
||||
fn flush(&mut self) { (self.flush)() }
|
||||
}
|
||||
}
|
||||
|
@ -71,14 +71,14 @@ before reporting whether it succeeded or failed. A watching parent will only
|
||||
report success if it succeeded and all its children also reported success;
|
||||
otherwise, it will report failure. This is most useful for writing test cases:
|
||||
|
||||
~~~
|
||||
```
|
||||
#[test]
|
||||
fn test_something_in_another_task {
|
||||
do spawn {
|
||||
assert!(collatz_conjecture_is_false());
|
||||
}
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
Here, as the child task will certainly outlive the parent task, we might miss
|
||||
the failure of the child when deciding whether or not the test case passed.
|
||||
|
@ -58,8 +58,7 @@ they contained the following prologue:
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
passes = "strip-hidden")];
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico")];
|
||||
|
||||
// Don't link to std. We are std.
|
||||
#[no_std];
|
||||
|
@ -37,13 +37,13 @@ there are three common kinds of strings in rust:
|
||||
|
||||
As an example, here's a few different kinds of strings.
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
let owned_string = ~"I am an owned string";
|
||||
let managed_string = @"This string is garbage-collected";
|
||||
let borrowed_string1 = "This string is borrowed with the 'static lifetime";
|
||||
let borrowed_string2: &str = owned_string; // owned strings can be borrowed
|
||||
let borrowed_string3: &str = managed_string; // managed strings can also be borrowed
|
||||
~~~
|
||||
```
|
||||
|
||||
From the example above, you can see that rust has 3 different kinds of string
|
||||
literals. The owned/managed literals correspond to the owned/managed string
|
||||
@ -67,12 +67,12 @@ to that string. With these guarantees, strings can easily transition between
|
||||
being mutable/immutable with the same benefits of having mutable strings in
|
||||
other languages.
|
||||
|
||||
~~~{.rust}
|
||||
```rust
|
||||
let mut buf = ~"testing";
|
||||
buf.push_char(' ');
|
||||
buf.push_str("123");
|
||||
assert_eq!(buf, ~"testing 123");
|
||||
~~~
|
||||
```
|
||||
|
||||
# Representation
|
||||
|
||||
@ -1513,10 +1513,10 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let v: ~[char] = "abc åäö".iter().collect();
|
||||
/// assert_eq!(v, ~['a', 'b', 'c', ' ', 'å', 'ä', 'ö']);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn iter(&self) -> CharIterator<'self> {
|
||||
CharIterator{string: *self}
|
||||
@ -1558,13 +1558,13 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let v: ~[&str] = "Mary had a little lamb".split_iter(' ').collect();
|
||||
/// assert_eq!(v, ~["Mary", "had", "a", "little", "lamb"]);
|
||||
///
|
||||
/// let v: ~[&str] = "abc1def2ghi".split_iter(|c: char| c.is_digit()).collect();
|
||||
/// assert_eq!(v, ~["abc", "def", "ghi"]);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn split_iter<Sep: CharEq>(&self, sep: Sep) -> CharSplitIterator<'self, Sep> {
|
||||
CharSplitIterator {
|
||||
@ -1597,10 +1597,10 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let v: ~[&str] = "A.B.".split_terminator_iter('.').collect();
|
||||
/// assert_eq!(v, ~["A", "B"]);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn split_terminator_iter<Sep: CharEq>(&self, sep: Sep)
|
||||
-> CharSplitIterator<'self, Sep> {
|
||||
@ -1615,10 +1615,10 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let v: ~[&str] = "Mary had a little lamb".rsplit_iter(' ').collect();
|
||||
/// assert_eq!(v, ~["lamb", "little", "a", "had", "Mary"]);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn rsplit_iter<Sep: CharEq>(&self, sep: Sep) -> CharRSplitIterator<'self, Sep> {
|
||||
self.split_iter(sep).invert()
|
||||
@ -1655,10 +1655,10 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let v: ~[&str] = "abcXXXabcYYYabc".split_str_iter("abc").collect()
|
||||
/// assert_eq!(v, ["", "XXX", "YYY", ""]);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn split_str_iter(&self, sep: &'self str) -> StrSplitIterator<'self> {
|
||||
StrSplitIterator {
|
||||
@ -1853,11 +1853,11 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// assert_eq!("11foo1bar11".trim_chars(&'1'), "foo1bar")
|
||||
/// assert_eq!("12foo1bar12".trim_chars(& &['1', '2']), "foo1bar")
|
||||
/// assert_eq!("123foo1bar123".trim_chars(&|c: char| c.is_digit()), "foo1bar")
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn trim_chars<C: CharEq>(&self, to_trim: &C) -> &'self str {
|
||||
self.trim_left_chars(to_trim).trim_right_chars(to_trim)
|
||||
@ -1871,11 +1871,11 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// assert_eq!("11foo1bar11".trim_left_chars(&'1'), "foo1bar11")
|
||||
/// assert_eq!("12foo1bar12".trim_left_chars(& &['1', '2']), "foo1bar12")
|
||||
/// assert_eq!("123foo1bar123".trim_left_chars(&|c: char| c.is_digit()), "foo1bar123")
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn trim_left_chars<C: CharEq>(&self, to_trim: &C) -> &'self str {
|
||||
match self.find(|c: char| !to_trim.matches(c)) {
|
||||
@ -1892,11 +1892,11 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// assert_eq!("11foo1bar11".trim_right_chars(&'1'), "11foo1bar")
|
||||
/// assert_eq!("12foo1bar12".trim_right_chars(& &['1', '2']), "12foo1bar")
|
||||
/// assert_eq!("123foo1bar123".trim_right_chars(&|c: char| c.is_digit()), "123foo1bar")
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn trim_right_chars<C: CharEq>(&self, to_trim: &C) -> &'self str {
|
||||
match self.rfind(|c: char| !to_trim.matches(c)) {
|
||||
@ -2000,7 +2000,7 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let s = "中华Việt Nam";
|
||||
/// let i = 0u;
|
||||
/// while i < s.len() {
|
||||
@ -2008,11 +2008,11 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
/// printfln!("%u: %c", i, ch);
|
||||
/// i = next;
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
/// # Example output
|
||||
///
|
||||
/// ~~~
|
||||
/// ```
|
||||
/// 0: 中
|
||||
/// 3: 华
|
||||
/// 6: V
|
||||
@ -2023,7 +2023,7 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
/// 13: N
|
||||
/// 14: a
|
||||
/// 15: m
|
||||
/// ~~~
|
||||
/// ```
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@ -2228,7 +2228,7 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let string = "a\nb\nc";
|
||||
/// let mut lines = ~[];
|
||||
/// for line in string.line_iter() { lines.push(line) }
|
||||
@ -2236,7 +2236,7 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
/// assert!(string.subslice_offset(lines[0]) == 0); // &"a"
|
||||
/// assert!(string.subslice_offset(lines[1]) == 2); // &"b"
|
||||
/// assert!(string.subslice_offset(lines[2]) == 4); // &"c"
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn subslice_offset(&self, inner: &str) -> uint {
|
||||
do self.as_imm_buf |a, a_len| {
|
||||
|
@ -26,11 +26,11 @@
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~
|
||||
* ```
|
||||
* do spawn {
|
||||
* log(error, "Hello, World!");
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
|
||||
#[allow(missing_doc)];
|
||||
@ -565,7 +565,7 @@ pub fn failing() -> bool {
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~
|
||||
* ```
|
||||
* do task::unkillable {
|
||||
* // detach / deschedule / destroy must all be called together
|
||||
* rustrt::rust_port_detach(po);
|
||||
@ -573,7 +573,7 @@ pub fn failing() -> bool {
|
||||
* task::deschedule();
|
||||
* rustrt::rust_port_destroy(po);
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*/
|
||||
pub fn unkillable<U>(f: &fn() -> U) -> U {
|
||||
use rt::task::Task;
|
||||
@ -602,7 +602,7 @@ pub fn unkillable<U>(f: &fn() -> U) -> U {
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ~~~
|
||||
* ```
|
||||
* do task::unkillable {
|
||||
* do task::rekillable {
|
||||
* // Task is killable
|
||||
|
@ -14,13 +14,13 @@ stack closures that emulates Java-style try/finally blocks.
|
||||
|
||||
# Example
|
||||
|
||||
~~~
|
||||
```
|
||||
do || {
|
||||
...
|
||||
}.finally {
|
||||
always_run_this();
|
||||
}
|
||||
~~~
|
||||
```
|
||||
*/
|
||||
|
||||
use ops::Drop;
|
||||
|
@ -16,10 +16,10 @@ The `vec` module contains useful code to help work with vector values.
|
||||
Vectors are Rust's list type. Vectors contain zero or more values of
|
||||
homogeneous types:
|
||||
|
||||
~~~ {.rust}
|
||||
```rust
|
||||
let int_vector = [1,2,3];
|
||||
let str_vector = ["one", "two", "three"];
|
||||
~~~
|
||||
```
|
||||
|
||||
This is a big module, but for a high-level overview:
|
||||
|
||||
@ -40,11 +40,11 @@ case.
|
||||
An example is the method `.slice(a, b)` that returns an immutable "view" into
|
||||
a vector or a vector slice from the index interval `[a, b)`:
|
||||
|
||||
~~~ {.rust}
|
||||
```rust
|
||||
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
|
||||
@ -53,11 +53,11 @@ the allocation of the vector.
|
||||
An example is the method `.push(element)` that will add an element at the end
|
||||
of the vector:
|
||||
|
||||
~~~ {.rust}
|
||||
```rust
|
||||
let mut numbers = ~[0, 1, 2];
|
||||
numbers.push(7);
|
||||
// numbers is now ~[0, 1, 2, 7];
|
||||
~~~
|
||||
```
|
||||
|
||||
## Implementations of other traits
|
||||
|
||||
@ -74,12 +74,12 @@ The method `iter()` returns an iteration value for a vector or a vector slice.
|
||||
The iterator yields borrowed pointers to the vector's elements, so if the element
|
||||
type of the vector is `int`, the element type of the iterator is `&int`.
|
||||
|
||||
~~~ {.rust}
|
||||
```rust
|
||||
let numbers = [0, 1, 2];
|
||||
for &x in numbers.iter() {
|
||||
println!("{} is a number!", x);
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
* `.rev_iter()` returns an iterator with the same values as `.iter()`,
|
||||
but going in the reverse order, starting with the back element.
|
||||
@ -1000,12 +1000,12 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] {
|
||||
* Print the adjacent pairs of a vector (i.e. `[1,2]`, `[2,3]`,
|
||||
* `[3,4]`):
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* let v = &[1,2,3,4];
|
||||
* for win in v.window_iter() {
|
||||
* printfln!(win);
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
fn window_iter(self, size: uint) -> WindowIter<'self, T> {
|
||||
@ -1029,12 +1029,12 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] {
|
||||
* Print the vector two elements at a time (i.e. `[1,2]`,
|
||||
* `[3,4]`, `[5]`):
|
||||
*
|
||||
* ~~~ {.rust}
|
||||
* ```rust
|
||||
* let v = &[1,2,3,4,5];
|
||||
* for win in v.chunk_iter() {
|
||||
* printfln!(win);
|
||||
* }
|
||||
* ~~~
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
fn chunk_iter(self, size: uint) -> ChunkIter<'self, T> {
|
||||
@ -1279,13 +1279,13 @@ impl<T> OwnedVector<T> for ~[T] {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let v = ~[~"a", ~"b"];
|
||||
/// for s in v.move_iter() {
|
||||
/// // s has type ~str, not &~str
|
||||
/// println(s);
|
||||
/// }
|
||||
/// ~~~
|
||||
/// ```
|
||||
fn move_iter(self) -> MoveIterator<T> {
|
||||
MoveIterator { v: self, idx: 0 }
|
||||
}
|
||||
@ -1449,11 +1449,11 @@ impl<T> OwnedVector<T> for ~[T] {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let mut a = ~[~1];
|
||||
/// a.push_all_move(~[~2, ~3, ~4]);
|
||||
/// assert!(a == ~[~1, ~2, ~3, ~4]);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn push_all_move(&mut self, mut rhs: ~[T]) {
|
||||
let self_len = self.len();
|
||||
@ -1697,11 +1697,11 @@ impl<T:Clone> OwnedCopyableVector<T> for ~[T] {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// ```rust
|
||||
/// let mut a = ~[1];
|
||||
/// a.push_all([2, 3, 4]);
|
||||
/// assert!(a == ~[1, 2, 3, 4]);
|
||||
/// ~~~
|
||||
/// ```
|
||||
#[inline]
|
||||
fn push_all(&mut self, rhs: &[T]) {
|
||||
let new_len = self.len() + rhs.len();
|
||||
|
@ -59,7 +59,7 @@ associated with. It is only not `None` when the associated field has
|
||||
an identifier in the source code. For example, the `x`s in the
|
||||
following snippet
|
||||
|
||||
~~~
|
||||
```
|
||||
struct A { x : int }
|
||||
|
||||
struct B(int);
|
||||
@ -82,7 +82,7 @@ represented as a count of 0.
|
||||
|
||||
The following simplified `Eq` is used for in-code examples:
|
||||
|
||||
~~~
|
||||
```
|
||||
trait Eq {
|
||||
fn eq(&self, other: &Self);
|
||||
}
|
||||
@ -91,7 +91,7 @@ impl Eq for int {
|
||||
*self == *other
|
||||
}
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
Some examples of the values of `SubstructureFields` follow, using the
|
||||
above `Eq`, `A`, `B` and `C`.
|
||||
@ -100,50 +100,50 @@ above `Eq`, `A`, `B` and `C`.
|
||||
|
||||
When generating the `expr` for the `A` impl, the `SubstructureFields` is
|
||||
|
||||
~~~
|
||||
```
|
||||
Struct(~[(Some(<ident of x>),
|
||||
<expr for &self.x>,
|
||||
~[<expr for &other.x])])
|
||||
~~~
|
||||
```
|
||||
|
||||
For the `B` impl, called with `B(a)` and `B(b)`,
|
||||
|
||||
~~~
|
||||
```
|
||||
Struct(~[(None,
|
||||
<expr for &a>
|
||||
~[<expr for &b>])])
|
||||
~~~
|
||||
```
|
||||
|
||||
## Enums
|
||||
|
||||
When generating the `expr` for a call with `self == C0(a)` and `other
|
||||
== C0(b)`, the SubstructureFields is
|
||||
|
||||
~~~
|
||||
```
|
||||
EnumMatching(0, <ast::variant for C0>,
|
||||
~[None,
|
||||
<expr for &a>,
|
||||
~[<expr for &b>]])
|
||||
~~~
|
||||
```
|
||||
|
||||
For `C1 {x}` and `C1 {x}`,
|
||||
|
||||
~~~
|
||||
```
|
||||
EnumMatching(1, <ast::variant for C1>,
|
||||
~[Some(<ident of x>),
|
||||
<expr for &self.x>,
|
||||
~[<expr for &other.x>]])
|
||||
~~~
|
||||
```
|
||||
|
||||
For `C0(a)` and `C1 {x}` ,
|
||||
|
||||
~~~
|
||||
```
|
||||
EnumNonMatching(~[(0, <ast::variant for B0>,
|
||||
~[(None, <expr for &a>)]),
|
||||
(1, <ast::variant for B1>,
|
||||
~[(Some(<ident of x>),
|
||||
<expr for &other.x>)])])
|
||||
~~~
|
||||
```
|
||||
|
||||
(and vice versa, but with the order of the outermost list flipped.)
|
||||
|
||||
@ -158,7 +158,7 @@ StaticStruct(<ast::struct_def of B>, Left(1))
|
||||
|
||||
StaticEnum(<ast::enum_def of C>, ~[(<ident of C0>, Left(1)),
|
||||
(<ident of C1>, Right(~[<ident of x>]))])
|
||||
~~~
|
||||
```
|
||||
|
||||
*/
|
||||
|
||||
@ -547,7 +547,7 @@ impl<'self> MethodDef<'self> {
|
||||
}
|
||||
|
||||
/**
|
||||
~~~
|
||||
```
|
||||
#[deriving(Eq)]
|
||||
struct A { x: int, y: int }
|
||||
|
||||
@ -565,7 +565,7 @@ impl<'self> MethodDef<'self> {
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~
|
||||
```
|
||||
*/
|
||||
fn expand_struct_method_body(&self,
|
||||
cx: @ExtCtxt,
|
||||
@ -638,7 +638,7 @@ impl<'self> MethodDef<'self> {
|
||||
}
|
||||
|
||||
/**
|
||||
~~~
|
||||
```
|
||||
#[deriving(Eq)]
|
||||
enum A {
|
||||
A1
|
||||
@ -661,7 +661,7 @@ impl<'self> MethodDef<'self> {
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~
|
||||
```
|
||||
*/
|
||||
fn expand_enum_method_body(&self,
|
||||
cx: @ExtCtxt,
|
||||
@ -681,13 +681,13 @@ impl<'self> MethodDef<'self> {
|
||||
/**
|
||||
Creates the nested matches for an enum definition recursively, i.e.
|
||||
|
||||
~~~
|
||||
```
|
||||
match self {
|
||||
Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... },
|
||||
Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... },
|
||||
...
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
It acts in the most naive way, so every branch (and subbranch,
|
||||
subsubbranch, etc) exists, not just the ones where all the variants in
|
||||
@ -1058,10 +1058,10 @@ pub fn cs_fold(use_foldl: bool,
|
||||
Call the method that is being derived on all the fields, and then
|
||||
process the collected results. i.e.
|
||||
|
||||
~~~
|
||||
```
|
||||
f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
|
||||
self_2.method(__arg_1_2, __arg_2_2)])
|
||||
~~~
|
||||
```
|
||||
*/
|
||||
#[inline]
|
||||
pub fn cs_same_method(f: &fn(@ExtCtxt, Span, ~[@Expr]) -> @Expr,
|
||||
|
@ -944,7 +944,7 @@ pub fn std_macros() -> @str {
|
||||
|
||||
# Example
|
||||
|
||||
~~~ {.rust}
|
||||
```rust
|
||||
fn choose_weighted_item(v: &[Item]) -> Item {
|
||||
assert!(!v.is_empty());
|
||||
let mut so_far = 0u;
|
||||
@ -958,7 +958,7 @@ pub fn std_macros() -> @str {
|
||||
// type checker that it isn't possible to get down here
|
||||
unreachable!();
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
*/
|
||||
macro_rules! unreachable (() => (
|
||||
|
@ -59,11 +59,19 @@ pub fn strip_doc_comment_decoration(comment: &str) -> ~str {
|
||||
fn vertical_trim(lines: ~[~str]) -> ~[~str] {
|
||||
let mut i = 0u;
|
||||
let mut j = lines.len();
|
||||
while i < j && lines[i].trim().is_empty() {
|
||||
i += 1u;
|
||||
// first line of all-stars should be omitted
|
||||
if lines.len() > 0 && lines[0].iter().all(|c| c == '*') {
|
||||
i += 1;
|
||||
}
|
||||
while j > i && lines[j - 1u].trim().is_empty() {
|
||||
j -= 1u;
|
||||
while i < j && lines[i].trim().is_empty() {
|
||||
i += 1;
|
||||
}
|
||||
// like the first, a last line of all stars should be omitted
|
||||
if j > i && lines[j - 1].iter().skip(1).all(|c| c == '*') {
|
||||
j -= 1;
|
||||
}
|
||||
while j > i && lines[j - 1].trim().is_empty() {
|
||||
j -= 1;
|
||||
}
|
||||
return lines.slice(i, j).to_owned();
|
||||
}
|
||||
@ -106,8 +114,12 @@ pub fn strip_doc_comment_decoration(comment: &str) -> ~str {
|
||||
}
|
||||
}
|
||||
|
||||
if comment.starts_with("//") {
|
||||
return comment.slice(3u, comment.len()).to_owned();
|
||||
// one-line comments lose their prefix
|
||||
static ONLINERS: &'static [&'static str] = &["///!", "///", "//!", "//"];
|
||||
for prefix in ONLINERS.iter() {
|
||||
if comment.starts_with(*prefix) {
|
||||
return comment.slice_from(prefix.len()).to_owned();
|
||||
}
|
||||
}
|
||||
|
||||
if comment.starts_with("/*") {
|
||||
@ -384,29 +396,42 @@ mod test {
|
||||
|
||||
#[test] fn test_block_doc_comment_1() {
|
||||
let comment = "/**\n * Test \n ** Test\n * Test\n*/";
|
||||
let correct_stripped = " Test \n* Test\n Test";
|
||||
let stripped = strip_doc_comment_decoration(comment);
|
||||
assert_eq!(stripped.slice(0, stripped.len()), correct_stripped);
|
||||
assert_eq!(stripped, ~" Test \n* Test\n Test");
|
||||
}
|
||||
|
||||
#[test] fn test_block_doc_comment_2() {
|
||||
let comment = "/**\n * Test\n * Test\n*/";
|
||||
let correct_stripped = " Test\n Test";
|
||||
let stripped = strip_doc_comment_decoration(comment);
|
||||
assert_eq!(stripped.slice(0, stripped.len()), correct_stripped);
|
||||
assert_eq!(stripped, ~" Test\n Test");
|
||||
}
|
||||
|
||||
#[test] fn test_block_doc_comment_3() {
|
||||
let comment = "/**\n let a: *int;\n *a = 5;\n*/";
|
||||
let correct_stripped = " let a: *int;\n *a = 5;";
|
||||
let stripped = strip_doc_comment_decoration(comment);
|
||||
assert_eq!(stripped.slice(0, stripped.len()), correct_stripped);
|
||||
assert_eq!(stripped, ~" let a: *int;\n *a = 5;");
|
||||
}
|
||||
|
||||
#[test] fn test_block_doc_comment_4() {
|
||||
let comment = "/*******************\n test\n *********************/";
|
||||
let stripped = strip_doc_comment_decoration(comment);
|
||||
assert_eq!(stripped, ~" test");
|
||||
}
|
||||
|
||||
#[test] fn test_line_doc_comment() {
|
||||
let comment = "/// Test";
|
||||
let correct_stripped = " Test";
|
||||
let stripped = strip_doc_comment_decoration(comment);
|
||||
assert_eq!(stripped.slice(0, stripped.len()), correct_stripped);
|
||||
let stripped = strip_doc_comment_decoration("/// test");
|
||||
assert_eq!(stripped, ~" test");
|
||||
let stripped = strip_doc_comment_decoration("///! test");
|
||||
assert_eq!(stripped, ~" test");
|
||||
let stripped = strip_doc_comment_decoration("// test");
|
||||
assert_eq!(stripped, ~" test");
|
||||
let stripped = strip_doc_comment_decoration("// test");
|
||||
assert_eq!(stripped, ~" test");
|
||||
let stripped = strip_doc_comment_decoration("///test");
|
||||
assert_eq!(stripped, ~"test");
|
||||
let stripped = strip_doc_comment_decoration("///!test");
|
||||
assert_eq!(stripped, ~"test");
|
||||
let stripped = strip_doc_comment_decoration("//test");
|
||||
assert_eq!(stripped, ~"test");
|
||||
}
|
||||
}
|
||||
|
@ -200,3 +200,9 @@ rust_set_stdio_container_fd
|
||||
rust_set_stdio_container_stream
|
||||
rust_uv_process_pid
|
||||
rust_uv_pipe_init
|
||||
sdhtml_renderer
|
||||
sd_markdown_new
|
||||
sd_markdown_render
|
||||
sd_markdown_free
|
||||
bufrelease
|
||||
bufnew
|
||||
|
5
src/rt/sundown/.gitignore
vendored
Normal file
5
src/rt/sundown/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
*.o
|
||||
libsundown.so*
|
||||
sundown
|
||||
smartypants
|
||||
*.exe
|
10
src/rt/sundown/CONTRIBUTING.md
Normal file
10
src/rt/sundown/CONTRIBUTING.md
Normal file
@ -0,0 +1,10 @@
|
||||
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.
|
83
src/rt/sundown/Makefile
Normal file
83
src/rt/sundown/Makefile
Normal file
@ -0,0 +1,83 @@
|
||||
# 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-dependant" 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 $@ $<
|
||||
|
33
src/rt/sundown/Makefile.win
Normal file
33
src/rt/sundown/Makefile.win
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
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$@
|
||||
|
131
src/rt/sundown/README.markdown
Normal file
131
src/rt/sundown/README.markdown
Normal file
@ -0,0 +1,131 @@
|
||||
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.
|
||||
|
||||
<!-- Local Variables: -->
|
||||
<!-- fill-column: 89 -->
|
||||
<!-- End: -->
|
72
src/rt/sundown/examples/smartypants.c
Normal file
72
src/rt/sundown/examples/smartypants.c
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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: */
|
80
src/rt/sundown/examples/sundown.c
Normal file
80
src/rt/sundown/examples/sundown.c
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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: */
|
37
src/rt/sundown/html/houdini.h
Normal file
37
src/rt/sundown/html/houdini.h
Normal file
@ -0,0 +1,37 @@
|
||||
#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
|
108
src/rt/sundown/html/houdini_href_e.c
Normal file
108
src/rt/sundown/html/houdini_href_e.c
Normal file
@ -0,0 +1,108 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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++;
|
||||
}
|
||||
}
|
84
src/rt/sundown/html/houdini_html_e.c
Normal file
84
src/rt/sundown/html/houdini_html_e.c
Normal file
@ -0,0 +1,84 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
635
src/rt/sundown/html/html.c
Executable file
635
src/rt/sundown/html/html.c
Executable file
@ -0,0 +1,635 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#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, "<a href=\"");
|
||||
if (type == MKDA_EMAIL)
|
||||
BUFPUTSL(ob, "mailto:");
|
||||
escape_href(ob, link->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, "</a>");
|
||||
|
||||
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, "<pre><code class=\"");
|
||||
|
||||
for (i = 0, cls = 0; i < lang->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, "<pre><code>");
|
||||
|
||||
if (text)
|
||||
escape_html(ob, text->data, text->size);
|
||||
|
||||
BUFPUTSL(ob, "</code></pre>\n");
|
||||
}
|
||||
|
||||
static void
|
||||
rndr_blockquote(struct buf *ob, const struct buf *text, void *opaque)
|
||||
{
|
||||
if (ob->size) bufputc(ob, '\n');
|
||||
BUFPUTSL(ob, "<blockquote>\n");
|
||||
if (text) bufput(ob, text->data, text->size);
|
||||
BUFPUTSL(ob, "</blockquote>\n");
|
||||
}
|
||||
|
||||
static int
|
||||
rndr_codespan(struct buf *ob, const struct buf *text, void *opaque)
|
||||
{
|
||||
BUFPUTSL(ob, "<code>");
|
||||
if (text) escape_html(ob, text->data, text->size);
|
||||
BUFPUTSL(ob, "</code>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
rndr_strikethrough(struct buf *ob, const struct buf *text, void *opaque)
|
||||
{
|
||||
if (!text || !text->size)
|
||||
return 0;
|
||||
|
||||
BUFPUTSL(ob, "<del>");
|
||||
bufput(ob, text->data, text->size);
|
||||
BUFPUTSL(ob, "</del>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
rndr_double_emphasis(struct buf *ob, const struct buf *text, void *opaque)
|
||||
{
|
||||
if (!text || !text->size)
|
||||
return 0;
|
||||
|
||||
BUFPUTSL(ob, "<strong>");
|
||||
bufput(ob, text->data, text->size);
|
||||
BUFPUTSL(ob, "</strong>");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
rndr_emphasis(struct buf *ob, const struct buf *text, void *opaque)
|
||||
{
|
||||
if (!text || !text->size) return 0;
|
||||
BUFPUTSL(ob, "<em>");
|
||||
if (text) bufput(ob, text->data, text->size);
|
||||
BUFPUTSL(ob, "</em>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
rndr_linebreak(struct buf *ob, void *opaque)
|
||||
{
|
||||
struct html_renderopt *options = opaque;
|
||||
bufputs(ob, USE_XHTML(options) ? "<br/>\n" : "<br>\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, "<h%d id=\"toc_%d\">", level, options->toc_data.header_count++);
|
||||
else
|
||||
bufprintf(ob, "<h%d>", level);
|
||||
|
||||
if (text) bufput(ob, text->data, text->size);
|
||||
bufprintf(ob, "</h%d>\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, "<a href=\"");
|
||||
|
||||
if (link && link->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, "</a>");
|
||||
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 ? "<ol>\n" : "<ul>\n", 5);
|
||||
if (text) bufput(ob, text->data, text->size);
|
||||
bufput(ob, flags & MKD_LIST_ORDERED ? "</ol>\n" : "</ul>\n", 6);
|
||||
}
|
||||
|
||||
static void
|
||||
rndr_listitem(struct buf *ob, const struct buf *text, int flags, void *opaque)
|
||||
{
|
||||
BUFPUTSL(ob, "<li>");
|
||||
if (text) {
|
||||
size_t size = text->size;
|
||||
while (size && text->data[size - 1] == '\n')
|
||||
size--;
|
||||
|
||||
bufput(ob, text->data, size);
|
||||
}
|
||||
BUFPUTSL(ob, "</li>\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, "<p>");
|
||||
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, "</p>\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, "<strong><em>");
|
||||
bufput(ob, text->data, text->size);
|
||||
BUFPUTSL(ob, "</em></strong>");
|
||||
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) ? "<hr/>\n" : "<hr>\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, "<img src=\"");
|
||||
escape_href(ob, link->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, "<table><thead>\n");
|
||||
if (header)
|
||||
bufput(ob, header->data, header->size);
|
||||
BUFPUTSL(ob, "</thead><tbody>\n");
|
||||
if (body)
|
||||
bufput(ob, body->data, body->size);
|
||||
BUFPUTSL(ob, "</tbody></table>\n");
|
||||
}
|
||||
|
||||
static void
|
||||
rndr_tablerow(struct buf *ob, const struct buf *text, void *opaque)
|
||||
{
|
||||
BUFPUTSL(ob, "<tr>\n");
|
||||
if (text)
|
||||
bufput(ob, text->data, text->size);
|
||||
BUFPUTSL(ob, "</tr>\n");
|
||||
}
|
||||
|
||||
static void
|
||||
rndr_tablecell(struct buf *ob, const struct buf *text, int flags, void *opaque)
|
||||
{
|
||||
if (flags & MKD_TABLE_HEADER) {
|
||||
BUFPUTSL(ob, "<th");
|
||||
} else {
|
||||
BUFPUTSL(ob, "<td");
|
||||
}
|
||||
|
||||
switch (flags & MKD_TABLE_ALIGNMASK) {
|
||||
case MKD_TABLE_ALIGN_CENTER:
|
||||
BUFPUTSL(ob, " align=\"center\">");
|
||||
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, "</th>\n");
|
||||
} else {
|
||||
BUFPUTSL(ob, "</td>\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
rndr_superscript(struct buf *ob, const struct buf *text, void *opaque)
|
||||
{
|
||||
if (!text || !text->size) return 0;
|
||||
BUFPUTSL(ob, "<sup>");
|
||||
bufput(ob, text->data, text->size);
|
||||
BUFPUTSL(ob, "</sup>");
|
||||
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, "<ul>\n<li>\n");
|
||||
options->toc_data.current_level++;
|
||||
}
|
||||
} else if (level < options->toc_data.current_level) {
|
||||
BUFPUTSL(ob, "</li>\n");
|
||||
while (level < options->toc_data.current_level) {
|
||||
BUFPUTSL(ob, "</ul>\n</li>\n");
|
||||
options->toc_data.current_level--;
|
||||
}
|
||||
BUFPUTSL(ob,"<li>\n");
|
||||
} else {
|
||||
BUFPUTSL(ob,"</li>\n<li>\n");
|
||||
}
|
||||
|
||||
bufprintf(ob, "<a href=\"#toc_%d\">", options->toc_data.header_count++);
|
||||
if (text)
|
||||
escape_html(ob, text->data, text->size);
|
||||
BUFPUTSL(ob, "</a>\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, "</li>\n</ul>\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;
|
||||
}
|
77
src/rt/sundown/html/html.h
Normal file
77
src/rt/sundown/html/html.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#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
|
||||
|
389
src/rt/sundown/html/html_smartypants.c
Normal file
389
src/rt/sundown/html/html_smartypants.c
Normal file
@ -0,0 +1,389 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
25
src/rt/sundown/html_block_names.txt
Normal file
25
src/rt/sundown/html_block_names.txt
Normal file
@ -0,0 +1,25 @@
|
||||
##
|
||||
p
|
||||
dl
|
||||
h1
|
||||
h2
|
||||
h3
|
||||
h4
|
||||
h5
|
||||
h6
|
||||
ol
|
||||
ul
|
||||
del
|
||||
div
|
||||
ins
|
||||
pre
|
||||
form
|
||||
math
|
||||
table
|
||||
figure
|
||||
iframe
|
||||
script
|
||||
style
|
||||
fieldset
|
||||
noscript
|
||||
blockquote
|
297
src/rt/sundown/src/autolink.c
Normal file
297
src/rt/sundown/src/autolink.c
Normal file
@ -0,0 +1,297 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
51
src/rt/sundown/src/autolink.h
Normal file
51
src/rt/sundown/src/autolink.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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: */
|
225
src/rt/sundown/src/buffer.c
Normal file
225
src/rt/sundown/src/buffer.c
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
96
src/rt/sundown/src/buffer.h
Normal file
96
src/rt/sundown/src/buffer.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
206
src/rt/sundown/src/html_blocks.h
Normal file
206
src/rt/sundown/src/html_blocks.h
Normal file
@ -0,0 +1,206 @@
|
||||
/* 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 <bug-gnu-gperf@gnu.org>."
|
||||
#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;
|
||||
}
|
2556
src/rt/sundown/src/markdown.c
Normal file
2556
src/rt/sundown/src/markdown.c
Normal file
File diff suppressed because it is too large
Load Diff
138
src/rt/sundown/src/markdown.h
Normal file
138
src/rt/sundown/src/markdown.h
Normal file
@ -0,0 +1,138 @@
|
||||
/* 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 /* <li> 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: */
|
81
src/rt/sundown/src/stack.c
Normal file
81
src/rt/sundown/src/stack.c
Normal file
@ -0,0 +1,81 @@
|
||||
#include "stack.h"
|
||||
#include <string.h>
|
||||
|
||||
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];
|
||||
}
|
||||
|
29
src/rt/sundown/src/stack.h
Normal file
29
src/rt/sundown/src/stack.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef STACK_H__
|
||||
#define STACK_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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
|
@ -34,4 +34,4 @@ fn same_variant() {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
}
|
||||
|
@ -32,4 +32,4 @@ fn same_variant() {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
}
|
||||
|
@ -40,4 +40,4 @@ fn same_variant() {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
}
|
||||
|
@ -40,4 +40,4 @@ fn explicit() {
|
||||
rewrite(&mut a)); //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {}
|
||||
|
@ -40,4 +40,4 @@ fn explicit() {
|
||||
a); //~ ERROR cannot move
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {}
|
||||
|
@ -13,4 +13,4 @@ fn let_pat() {
|
||||
//~^ ERROR cannot move out of dereference of & pointer
|
||||
}
|
||||
|
||||
pub fn main() {}
|
||||
pub fn main() {}
|
||||
|
@ -12,4 +12,4 @@ fn foo(t0: &mut int) {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
}
|
||||
|
@ -13,4 +13,4 @@ fn foo<'a>(mut t0: &'a mut int,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
}
|
||||
|
@ -25,4 +25,4 @@ fn main() {
|
||||
let s = @S { unused: 0 };
|
||||
let _s2 = s as @mut T; //~ error: types differ in mutability
|
||||
let _s3 = &s as &mut T; //~ error: types differ in mutability
|
||||
}
|
||||
}
|
||||
|
@ -11,4 +11,4 @@
|
||||
fn main() {
|
||||
let foo = ['h' as u8, 'i' as u8, 0 as u8];
|
||||
let bar = &foo as *u8; //~ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
|
@ -5,4 +5,4 @@ fn take(f: &fn:Foo()) {
|
||||
//~^ ERROR only the builtin traits can be used as closure or object bounds
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {}
|
||||
|
@ -42,4 +42,4 @@ mod NoImport {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {}
|
||||
|
@ -35,4 +35,4 @@ mod NoImport {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {}
|
||||
|
@ -12,4 +12,4 @@
|
||||
#[auto_decode] //~ ERROR: `#[auto_decode]` is deprecated
|
||||
struct A;
|
||||
|
||||
fn main() {}
|
||||
fn main() {}
|
||||
|
@ -12,4 +12,4 @@ fn bad (p: *int) {
|
||||
let _q: &int = p as ∫ //~ ERROR non-scalar cast
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
fn main() { }
|
||||
|
@ -12,4 +12,4 @@ struct NonCopyable(());
|
||||
|
||||
fn main() {
|
||||
let z = NonCopyable{ p: () }; //~ ERROR structure has no field named `p`
|
||||
}
|
||||
}
|
||||
|
@ -21,4 +21,4 @@ fn main()
|
||||
|
||||
twice(x);
|
||||
invoke(sq);
|
||||
}
|
||||
}
|
||||
|
@ -49,4 +49,4 @@ pub fn opt_str3<'a>(maybestr: &'a Option<~str>) -> &'static str {
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
||||
fn main() {}
|
||||
|
@ -52,4 +52,4 @@ pub fn opt_str3<'a>(maybestr: &'a Option<~str>) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {}
|
||||
|
@ -12,4 +12,4 @@ mod m {
|
||||
// An inferred main entry point (that doesn't use #[main])
|
||||
// must appear at the top of the crate
|
||||
fn main() { } //~ NOTE here is a function named 'main'
|
||||
}
|
||||
}
|
||||
|
@ -34,4 +34,4 @@ fn ordering4<'a, 'b>(a: &'a uint, b: &'b uint, x: &fn(&'a &'b uint)) {
|
||||
let z: Option<&'a &'b uint> = None;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user