mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-30 05:51:58 +00:00
rustdoc: Migrate from sundown to hoedown
This primary fix brought on by this upgrade is the proper matching of the ``` and ~~~ doc blocks. This also moves hoedown to a git submodule rather than a bundled repository. Additionally, hoedown is stricter about code blocks, so this ended up fixing a lot of invalid code blocks (ending with " ```" instead of "```", or ending with "~~~~" instead of "~~~"). Closes #12776
This commit is contained in:
parent
9ac9245564
commit
9306e840f5
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -12,3 +12,6 @@
|
||||
[submodule "src/compiler-rt"]
|
||||
path = src/compiler-rt
|
||||
url = https://github.com/rust-lang/compiler-rt.git
|
||||
[submodule "src/rt/hoedown"]
|
||||
path = src/rt/hoedown
|
||||
url = https://github.com/rust-lang/hoedown.git
|
||||
|
@ -38,7 +38,7 @@
|
||||
# DEPS_<crate>
|
||||
# These lists are the dependencies of the <crate> that is to be built.
|
||||
# Rust dependencies are listed bare (i.e. std, green) and native
|
||||
# dependencies have a "native:" prefix (i.e. native:sundown). All deps
|
||||
# dependencies have a "native:" prefix (i.e. native:hoedown). All deps
|
||||
# will be built before the crate itself is built.
|
||||
#
|
||||
# TOOL_DEPS_<tool>/TOOL_SOURCE_<tool>
|
||||
@ -63,7 +63,7 @@ DEPS_native := std
|
||||
DEPS_syntax := std term serialize collections log
|
||||
DEPS_rustc := syntax native:rustllvm flate arena serialize sync getopts \
|
||||
collections time log
|
||||
DEPS_rustdoc := rustc native:sundown serialize sync getopts collections \
|
||||
DEPS_rustdoc := rustc native:hoedown serialize sync getopts collections \
|
||||
test time
|
||||
DEPS_flate := std native:miniz
|
||||
DEPS_arena := std collections
|
||||
|
@ -35,7 +35,8 @@ LICENSE.txt: $(S)COPYRIGHT $(S)LICENSE-APACHE $(S)LICENSE-MIT
|
||||
|
||||
PKG_TAR = dist/$(PKG_NAME).tar.gz
|
||||
|
||||
PKG_GITMODULES := $(S)src/libuv $(S)src/llvm $(S)src/gyp $(S)src/compiler-rt
|
||||
PKG_GITMODULES := $(S)src/libuv $(S)src/llvm $(S)src/gyp $(S)src/compiler-rt \
|
||||
$(S)src/rt/hoedown
|
||||
PKG_FILES := \
|
||||
$(S)COPYRIGHT \
|
||||
$(S)LICENSE-APACHE \
|
||||
|
21
mk/rt.mk
21
mk/rt.mk
@ -35,19 +35,20 @@
|
||||
# that's per-target so you're allowed to conditionally add files based on the
|
||||
# target.
|
||||
################################################################################
|
||||
NATIVE_LIBS := rustrt sundown uv_support morestack miniz context_switch
|
||||
NATIVE_LIBS := rustrt hoedown uv_support morestack miniz context_switch
|
||||
|
||||
# $(1) is the target triple
|
||||
define NATIVE_LIBRARIES
|
||||
|
||||
NATIVE_DEPS_sundown_$(1) := sundown/src/autolink.c \
|
||||
sundown/src/buffer.c \
|
||||
sundown/src/stack.c \
|
||||
sundown/src/markdown.c \
|
||||
sundown/html/houdini_href_e.c \
|
||||
sundown/html/houdini_html_e.c \
|
||||
sundown/html/html_smartypants.c \
|
||||
sundown/html/html.c
|
||||
NATIVE_DEPS_hoedown_$(1) := hoedown/src/autolink.c \
|
||||
hoedown/src/buffer.c \
|
||||
hoedown/src/document.c \
|
||||
hoedown/src/escape.c \
|
||||
hoedown/src/html.c \
|
||||
hoedown/src/html_blocks.c \
|
||||
hoedown/src/html_smartypants.c \
|
||||
hoedown/src/stack.c \
|
||||
hoedown/src/version.c
|
||||
NATIVE_DEPS_uv_support_$(1) := rust_uv.c
|
||||
NATIVE_DEPS_miniz_$(1) = miniz.c
|
||||
NATIVE_DEPS_rustrt_$(1) := rust_builtin.c \
|
||||
@ -79,7 +80,7 @@ $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS)
|
||||
@mkdir -p $$(@D)
|
||||
@$$(call E, compile: $$@)
|
||||
$$(Q)$$(call CFG_COMPILE_C_$(1), $$@, \
|
||||
-I $$(S)src/rt/sundown/src -I $$(S)src/rt/sundown/html \
|
||||
-I $$(S)src/rt/hoedown/src \
|
||||
-I $$(S)src/libuv/include -I $$(S)src/rt \
|
||||
$$(RUNTIME_CFLAGS_$(1))) $$<
|
||||
|
||||
|
@ -62,7 +62,7 @@ use std::str;
|
||||
|
||||
let x: Option<~str> = str::from_utf8_owned(~[104u8,105u8]);
|
||||
let y: ~str = x.unwrap();
|
||||
~~~~
|
||||
~~~
|
||||
|
||||
To return a [`MaybeOwned`](http://static.rust-lang.org/doc/master/std/str/enum.MaybeOwned.html) use the str helper function [`from_utf8_lossy`](http://static.rust-lang.org/doc/master/std/str/fn.from_utf8_owned.html). This function also replaces non-valid utf-8 sequences with U+FFFD replacement character.
|
||||
|
||||
@ -71,7 +71,7 @@ use std::str;
|
||||
|
||||
let x = bytes!(72u8,"ello ",0xF0,0x90,0x80,"World!");
|
||||
let y = str::from_utf8_lossy(x);
|
||||
~~~~
|
||||
~~~
|
||||
|
||||
# File operations
|
||||
|
||||
|
@ -135,7 +135,7 @@ For simplicity, we do not plan to do so. Implementing automatic semicolon insert
|
||||
|
||||
**Short answer** set the RUST_LOG environment variable to the name of your source file, sans extension.
|
||||
|
||||
``` {.sh .notrust}
|
||||
```notrust,sh
|
||||
rustc hello.rs
|
||||
export RUST_LOG=hello
|
||||
./hello
|
||||
|
@ -81,7 +81,7 @@ impl Iterator<int> for ZeroStream {
|
||||
Some(0)
|
||||
}
|
||||
}
|
||||
~~~~
|
||||
~~~
|
||||
|
||||
Reaching the end of the iterator is signalled by returning `None` instead of
|
||||
`Some(item)`:
|
||||
|
@ -496,7 +496,7 @@ fn stringifier(channel: &sync::DuplexStream<~str, uint>) {
|
||||
}
|
||||
}
|
||||
# }
|
||||
~~~~
|
||||
~~~
|
||||
|
||||
The implementation of `DuplexStream` supports both sending and
|
||||
receiving. The `stringifier` function takes a `DuplexStream` that can
|
||||
@ -538,7 +538,7 @@ assert!(from_child.recv() == "23".to_owned());
|
||||
assert!(from_child.recv() == "0".to_owned());
|
||||
|
||||
# }
|
||||
~~~~
|
||||
~~~
|
||||
|
||||
The parent task first calls `DuplexStream` to create a pair of bidirectional
|
||||
endpoints. It then uses `task::spawn` to create the child task, which captures
|
||||
|
@ -4085,7 +4085,7 @@ fn main() {
|
||||
|
||||
These four log levels correspond to levels 1-4, as controlled by `RUST_LOG`:
|
||||
|
||||
``` {.bash .notrust}
|
||||
```notrust,bash
|
||||
$ RUST_LOG=rust=3 ./rust
|
||||
This is an error log
|
||||
This is a warn log
|
||||
|
@ -107,44 +107,35 @@ code blocks as testable-by-default. In order to not run a test over a block of
|
||||
code, the `ignore` string can be added to the three-backtick form of markdown
|
||||
code block.
|
||||
|
||||
/**
|
||||
# nested code fences confuse sundown => indentation + comment to
|
||||
# avoid failing tests
|
||||
```
|
||||
// This is a testable code block
|
||||
```
|
||||
~~~notrust
|
||||
```
|
||||
// This is a testable code block
|
||||
```
|
||||
|
||||
```ignore
|
||||
// This is not a testable code block
|
||||
```
|
||||
```ignore
|
||||
// This is not a testable code block
|
||||
```
|
||||
|
||||
// This is a testable code block (4-space indent)
|
||||
*/
|
||||
# fn foo() {}
|
||||
// This is a testable code block (4-space indent)
|
||||
~~~
|
||||
|
||||
You can specify that the test's execution should fail with the `should_fail`
|
||||
directive.
|
||||
|
||||
/**
|
||||
# nested code fences confuse sundown => indentation + comment to
|
||||
# avoid failing tests
|
||||
```should_fail
|
||||
// This code block is expected to generate a failure when run
|
||||
```
|
||||
*/
|
||||
# fn foo() {}
|
||||
~~~notrust
|
||||
```should_fail
|
||||
// This code block is expected to generate a failure when run
|
||||
```
|
||||
~~~
|
||||
|
||||
You can specify that the code block should be compiled but not run with the
|
||||
`no_run` directive.
|
||||
|
||||
/**
|
||||
# nested code fences confuse sundown => indentation + comment to
|
||||
# avoid failing tests
|
||||
```no_run
|
||||
// This code will be compiled but not executed
|
||||
```
|
||||
*/
|
||||
# fn foo() {}
|
||||
~~~notrust
|
||||
```no_run
|
||||
// This code will be compiled but not executed
|
||||
```
|
||||
~~~
|
||||
|
||||
Rustdoc also supplies some extra sugar for helping with some tedious
|
||||
documentation examples. If a line is prefixed with `# `, then the line
|
||||
@ -152,23 +143,19 @@ will not show up in the HTML documentation, but it will be used when
|
||||
testing the code block (NB. the space after the `#` is required, so
|
||||
that one can still write things like `#[deriving(Eq)]`).
|
||||
|
||||
/**
|
||||
# nested code fences confuse sundown => indentation + comment to
|
||||
# avoid failing tests
|
||||
```rust
|
||||
# /!\ The three following lines are comments, which are usually stripped off by
|
||||
# the doc-generating tool. In order to display them anyway in this particular
|
||||
# case, the character following the leading '#' is not a usual space like in
|
||||
# these first five lines but a non breakable one.
|
||||
#
|
||||
# // showing 'fib' in this documentation would just be tedious and detracts from
|
||||
# // what's actually being documented.
|
||||
# fn fib(n: int) { n + 2 }
|
||||
~~~notrust
|
||||
```
|
||||
# /!\ The three following lines are comments, which are usually stripped off by
|
||||
# the doc-generating tool. In order to display them anyway in this particular
|
||||
# case, the character following the leading '#' is not a usual space like in
|
||||
# these first five lines but a non breakable one.
|
||||
# // showing 'fib' in this documentation would just be tedious and detracts from
|
||||
# // what's actually being documented.
|
||||
# fn fib(n: int) { n + 2 }
|
||||
|
||||
spawn(proc() { fib(200); })
|
||||
```
|
||||
*/
|
||||
# fn foo() {}
|
||||
spawn(proc() { fib(200); })
|
||||
```
|
||||
~~~
|
||||
|
||||
The documentation online would look like `spawn(proc() { fib(200); })`, but when
|
||||
testing this code, the `fib` function will be included (so it can compile).
|
||||
@ -182,10 +169,10 @@ rustc's `--test` flag. Extra arguments can be passed to rustdoc's test harness
|
||||
with the `--test-args` flag.
|
||||
|
||||
~~~ {.notrust}
|
||||
$ # Only run tests containing 'foo' in their name
|
||||
# Only run tests containing 'foo' in their name
|
||||
$ rustdoc --test lib.rs --test-args 'foo'
|
||||
|
||||
$ # See what's possible when running tests
|
||||
# See what's possible when running tests
|
||||
$ rustdoc --test lib.rs --test-args '--help'
|
||||
~~~
|
||||
|
||||
|
@ -1408,7 +1408,7 @@ struct Point {
|
||||
x: f64,
|
||||
y: f64
|
||||
}
|
||||
~~~~
|
||||
~~~
|
||||
|
||||
We can use this simple definition to allocate points in many different
|
||||
ways. For example, in this code, each of these local variables
|
||||
|
@ -31,7 +31,7 @@ fn main() {
|
||||
let little_val = fourcc!("foo ", little);
|
||||
assert_eq!(little_val, 0x21EEFFC0u32);
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
# References
|
||||
|
||||
|
@ -27,7 +27,7 @@ extern crate hexfloat;
|
||||
fn main() {
|
||||
let val = hexfloat!("0x1.ffffb4", f32);
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
# References
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
//! Markdown formatting for rustdoc
|
||||
//!
|
||||
//! This module implements markdown formatting through the sundown C-library
|
||||
//! This module implements markdown formatting through the hoedown C-library
|
||||
//! (bundled into the rust runtime). This module self-contains the C bindings
|
||||
//! and necessary legwork to render markdown, and exposes all of the
|
||||
//! functionality through a unit-struct, `Markdown`, which has an implementation
|
||||
@ -27,11 +27,9 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use libc;
|
||||
use std::cast;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::local_data;
|
||||
use std::mem;
|
||||
use std::str;
|
||||
use std::slice;
|
||||
use collections::HashMap;
|
||||
@ -47,67 +45,76 @@ pub struct Markdown<'a>(pub &'a str);
|
||||
/// table of contents.
|
||||
pub struct MarkdownWithToc<'a>(pub &'a str);
|
||||
|
||||
static OUTPUT_UNIT: libc::size_t = 64;
|
||||
static MKDEXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 0;
|
||||
static MKDEXT_TABLES: libc::c_uint = 1 << 1;
|
||||
static MKDEXT_FENCED_CODE: libc::c_uint = 1 << 2;
|
||||
static MKDEXT_AUTOLINK: libc::c_uint = 1 << 3;
|
||||
static MKDEXT_STRIKETHROUGH: libc::c_uint = 1 << 4;
|
||||
static DEF_OUNIT: libc::size_t = 64;
|
||||
static HOEDOWN_EXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 10;
|
||||
static HOEDOWN_EXT_TABLES: libc::c_uint = 1 << 0;
|
||||
static HOEDOWN_EXT_FENCED_CODE: libc::c_uint = 1 << 1;
|
||||
static HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3;
|
||||
static HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4;
|
||||
|
||||
type sd_markdown = libc::c_void; // this is opaque to us
|
||||
type hoedown_document = libc::c_void; // this is opaque to us
|
||||
|
||||
struct sd_callbacks {
|
||||
blockcode: Option<extern "C" fn(*buf, *buf, *buf, *libc::c_void)>,
|
||||
blockquote: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
|
||||
blockhtml: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
|
||||
header: Option<extern "C" fn(*buf, *buf, libc::c_int, *libc::c_void)>,
|
||||
other: [libc::size_t, ..22],
|
||||
struct hoedown_renderer {
|
||||
opaque: *mut hoedown_html_renderer_state,
|
||||
blockcode: Option<extern "C" fn(*mut hoedown_buffer, *hoedown_buffer,
|
||||
*hoedown_buffer, *mut libc::c_void)>,
|
||||
blockquote: Option<extern "C" fn(*mut hoedown_buffer, *hoedown_buffer,
|
||||
*mut libc::c_void)>,
|
||||
blockhtml: Option<extern "C" fn(*mut hoedown_buffer, *hoedown_buffer,
|
||||
*mut libc::c_void)>,
|
||||
header: Option<extern "C" fn(*mut hoedown_buffer, *hoedown_buffer,
|
||||
libc::c_int, *mut libc::c_void)>,
|
||||
other: [libc::size_t, ..28],
|
||||
}
|
||||
|
||||
struct hoedown_html_renderer_state {
|
||||
opaque: *mut libc::c_void,
|
||||
toc_data: html_toc_data,
|
||||
flags: libc::c_uint,
|
||||
link_attributes: Option<extern "C" fn(*mut hoedown_buffer, *hoedown_buffer,
|
||||
*mut libc::c_void)>,
|
||||
}
|
||||
|
||||
struct html_toc_data {
|
||||
header_count: libc::c_int,
|
||||
current_level: libc::c_int,
|
||||
level_offset: libc::c_int,
|
||||
nesting_level: libc::c_int,
|
||||
}
|
||||
|
||||
struct html_renderopt {
|
||||
toc_data: html_toc_data,
|
||||
flags: libc::c_uint,
|
||||
link_attributes: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
|
||||
}
|
||||
|
||||
struct my_opaque {
|
||||
opt: html_renderopt,
|
||||
dfltblk: extern "C" fn(*buf, *buf, *buf, *libc::c_void),
|
||||
struct MyOpaque {
|
||||
dfltblk: extern "C" fn(*mut hoedown_buffer, *hoedown_buffer,
|
||||
*hoedown_buffer, *mut libc::c_void),
|
||||
toc_builder: Option<TocBuilder>,
|
||||
}
|
||||
|
||||
struct buf {
|
||||
struct hoedown_buffer {
|
||||
data: *u8,
|
||||
size: libc::size_t,
|
||||
asize: libc::size_t,
|
||||
unit: libc::size_t,
|
||||
}
|
||||
|
||||
// sundown FFI
|
||||
#[link(name = "sundown", kind = "static")]
|
||||
// hoedown FFI
|
||||
#[link(name = "hoedown", kind = "static")]
|
||||
extern {
|
||||
fn sdhtml_renderer(callbacks: *sd_callbacks,
|
||||
options_ptr: *html_renderopt,
|
||||
render_flags: libc::c_uint);
|
||||
fn sd_markdown_new(extensions: libc::c_uint,
|
||||
max_nesting: libc::size_t,
|
||||
callbacks: *sd_callbacks,
|
||||
opaque: *libc::c_void) -> *sd_markdown;
|
||||
fn sd_markdown_render(ob: *buf,
|
||||
document: *u8,
|
||||
doc_size: libc::size_t,
|
||||
md: *sd_markdown);
|
||||
fn sd_markdown_free(md: *sd_markdown);
|
||||
fn hoedown_html_renderer_new(render_flags: libc::c_uint,
|
||||
nesting_level: libc::c_int)
|
||||
-> *mut hoedown_renderer;
|
||||
fn hoedown_html_renderer_free(renderer: *mut hoedown_renderer);
|
||||
|
||||
fn bufnew(unit: libc::size_t) -> *buf;
|
||||
fn bufputs(b: *buf, c: *libc::c_char);
|
||||
fn bufrelease(b: *buf);
|
||||
fn hoedown_document_new(rndr: *mut hoedown_renderer,
|
||||
extensions: libc::c_uint,
|
||||
max_nesting: libc::size_t) -> *mut hoedown_document;
|
||||
fn hoedown_document_render(doc: *mut hoedown_document,
|
||||
ob: *mut hoedown_buffer,
|
||||
document: *u8,
|
||||
doc_size: libc::size_t);
|
||||
fn hoedown_document_free(md: *mut hoedown_document);
|
||||
|
||||
fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer;
|
||||
fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *libc::c_char);
|
||||
fn hoedown_buffer_free(b: *mut hoedown_buffer);
|
||||
|
||||
}
|
||||
|
||||
@ -127,15 +134,19 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
|
||||
local_data_key!(used_header_map: HashMap<~str, uint>)
|
||||
|
||||
pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result {
|
||||
extern fn block(ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) {
|
||||
extern fn block(ob: *mut hoedown_buffer, text: *hoedown_buffer,
|
||||
lang: *hoedown_buffer, opaque: *mut libc::c_void) {
|
||||
unsafe {
|
||||
let my_opaque: &my_opaque = cast::transmute(opaque);
|
||||
let opaque = opaque as *mut hoedown_html_renderer_state;
|
||||
let my_opaque: &MyOpaque = &*((*opaque).opaque as *MyOpaque);
|
||||
slice::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
|
||||
let text = str::from_utf8(text).unwrap();
|
||||
let mut lines = text.lines().filter(|l| stripped_filtered_line(*l).is_none());
|
||||
let mut lines = text.lines().filter(|l| {
|
||||
stripped_filtered_line(*l).is_none()
|
||||
});
|
||||
let text = lines.collect::<Vec<&str>>().connect("\n");
|
||||
|
||||
let buf = buf {
|
||||
let buf = hoedown_buffer {
|
||||
data: text.as_bytes().as_ptr(),
|
||||
size: text.len() as libc::size_t,
|
||||
asize: text.len() as libc::size_t,
|
||||
@ -148,7 +159,8 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result {
|
||||
(*lang).size as uint, |rlang| {
|
||||
let rlang = str::from_utf8(rlang).unwrap();
|
||||
if rlang.contains("notrust") {
|
||||
(my_opaque.dfltblk)(ob, &buf, lang, opaque);
|
||||
(my_opaque.dfltblk)(ob, &buf, lang,
|
||||
opaque as *mut libc::c_void);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@ -159,17 +171,17 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result {
|
||||
if !rendered {
|
||||
let output = highlight::highlight(text, None).to_c_str();
|
||||
output.with_ref(|r| {
|
||||
bufputs(ob, r)
|
||||
hoedown_buffer_puts(ob, r)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
extern fn header(ob: *buf, text: *buf, level: libc::c_int,
|
||||
opaque: *libc::c_void) {
|
||||
// sundown does this, we may as well too
|
||||
"\n".with_c_str(|p| unsafe { bufputs(ob, p) });
|
||||
extern fn header(ob: *mut hoedown_buffer, text: *hoedown_buffer,
|
||||
level: libc::c_int, opaque: *mut libc::c_void) {
|
||||
// hoedown does this, we may as well too
|
||||
"\n".with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) });
|
||||
|
||||
// Extract the text provided
|
||||
let s = if text.is_null() {
|
||||
@ -188,7 +200,12 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result {
|
||||
}
|
||||
}).collect::<Vec<~str>>().connect("-");
|
||||
|
||||
let opaque = unsafe {&mut *(opaque as *mut my_opaque)};
|
||||
// This is a terrible hack working around how hoedown gives us rendered
|
||||
// html for text rather than the raw text.
|
||||
let id = id.replace("<code>", "").replace("</code>", "");
|
||||
|
||||
let opaque = opaque as *mut hoedown_html_renderer_state;
|
||||
let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) };
|
||||
|
||||
// Make sure our hyphenated ID is unique for this page
|
||||
let id = local_data::get_mut(used_header_map, |map| {
|
||||
@ -214,40 +231,29 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result {
|
||||
s, lvl = level, id = id,
|
||||
sec_len = sec.len(), sec = sec);
|
||||
|
||||
text.with_c_str(|p| unsafe { bufputs(ob, p) });
|
||||
text.with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) });
|
||||
}
|
||||
|
||||
// This code is all lifted from examples/sundown.c in the sundown repo
|
||||
unsafe {
|
||||
let ob = bufnew(OUTPUT_UNIT);
|
||||
let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES |
|
||||
MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK |
|
||||
MKDEXT_STRIKETHROUGH;
|
||||
let options = html_renderopt {
|
||||
toc_data: html_toc_data {
|
||||
header_count: 0,
|
||||
current_level: 0,
|
||||
level_offset: 0,
|
||||
},
|
||||
flags: 0,
|
||||
link_attributes: None,
|
||||
};
|
||||
let mut callbacks: sd_callbacks = mem::init();
|
||||
|
||||
sdhtml_renderer(&callbacks, &options, 0);
|
||||
let mut opaque = my_opaque {
|
||||
opt: options,
|
||||
dfltblk: callbacks.blockcode.unwrap(),
|
||||
let ob = hoedown_buffer_new(DEF_OUNIT);
|
||||
let extensions = HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES |
|
||||
HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK |
|
||||
HOEDOWN_EXT_STRIKETHROUGH;
|
||||
let renderer = hoedown_html_renderer_new(0, 0);
|
||||
let mut opaque = MyOpaque {
|
||||
dfltblk: (*renderer).blockcode.unwrap(),
|
||||
toc_builder: if print_toc {Some(TocBuilder::new())} else {None}
|
||||
};
|
||||
callbacks.blockcode = Some(block);
|
||||
callbacks.header = Some(header);
|
||||
let markdown = sd_markdown_new(extensions, 16, &callbacks,
|
||||
&mut opaque as *mut my_opaque as *libc::c_void);
|
||||
(*(*renderer).opaque).opaque = &mut opaque as *mut _ as *mut libc::c_void;
|
||||
(*renderer).blockcode = Some(block);
|
||||
(*renderer).header = Some(header);
|
||||
|
||||
let document = hoedown_document_new(renderer, extensions, 16);
|
||||
hoedown_document_render(document, ob, s.as_ptr(),
|
||||
s.len() as libc::size_t);
|
||||
hoedown_document_free(document);
|
||||
|
||||
sd_markdown_render(ob, s.as_ptr(), s.len() as libc::size_t, markdown);
|
||||
sd_markdown_free(markdown);
|
||||
hoedown_html_renderer_free(renderer);
|
||||
|
||||
let mut ret = match opaque.toc_builder {
|
||||
Some(b) => write!(w, "<nav id=\"TOC\">{}</nav>", b.into_toc()),
|
||||
@ -259,13 +265,14 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result {
|
||||
w.write(buf)
|
||||
});
|
||||
}
|
||||
bufrelease(ob);
|
||||
hoedown_buffer_free(ob);
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
|
||||
extern fn block(_ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) {
|
||||
extern fn block(_ob: *mut hoedown_buffer, text: *hoedown_buffer,
|
||||
lang: *hoedown_buffer, opaque: *mut libc::c_void) {
|
||||
unsafe {
|
||||
if text.is_null() { return }
|
||||
let (should_fail, no_run, ignore, notrust) = if lang.is_null() {
|
||||
@ -282,17 +289,23 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
|
||||
};
|
||||
if notrust { return }
|
||||
slice::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
|
||||
let tests = &mut *(opaque as *mut ::test::Collector);
|
||||
let opaque = opaque as *mut hoedown_html_renderer_state;
|
||||
let tests = &mut *((*opaque).opaque as *mut ::test::Collector);
|
||||
let text = str::from_utf8(text).unwrap();
|
||||
let mut lines = text.lines().map(|l| stripped_filtered_line(l).unwrap_or(l));
|
||||
let mut lines = text.lines().map(|l| {
|
||||
stripped_filtered_line(l).unwrap_or(l)
|
||||
});
|
||||
let text = lines.collect::<Vec<&str>>().connect("\n");
|
||||
tests.add_test(text, should_fail, no_run, ignore);
|
||||
})
|
||||
}
|
||||
}
|
||||
extern fn header(_ob: *buf, text: *buf, level: libc::c_int, opaque: *libc::c_void) {
|
||||
|
||||
extern fn header(_ob: *mut hoedown_buffer, text: *hoedown_buffer,
|
||||
level: libc::c_int, opaque: *mut libc::c_void) {
|
||||
unsafe {
|
||||
let tests = &mut *(opaque as *mut ::test::Collector);
|
||||
let opaque = opaque as *mut hoedown_html_renderer_state;
|
||||
let tests = &mut *((*opaque).opaque as *mut ::test::Collector);
|
||||
if text.is_null() {
|
||||
tests.register_header("", level as u32);
|
||||
} else {
|
||||
@ -305,25 +318,22 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let ob = bufnew(OUTPUT_UNIT);
|
||||
let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES |
|
||||
MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK |
|
||||
MKDEXT_STRIKETHROUGH;
|
||||
let callbacks = sd_callbacks {
|
||||
blockcode: Some(block),
|
||||
blockquote: None,
|
||||
blockhtml: None,
|
||||
header: Some(header),
|
||||
other: mem::init()
|
||||
};
|
||||
let ob = hoedown_buffer_new(DEF_OUNIT);
|
||||
let extensions = HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES |
|
||||
HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK |
|
||||
HOEDOWN_EXT_STRIKETHROUGH;
|
||||
let renderer = hoedown_html_renderer_new(0, 0);
|
||||
(*renderer).blockcode = Some(block);
|
||||
(*renderer).header = Some(header);
|
||||
(*(*renderer).opaque).opaque = tests as *mut _ as *mut libc::c_void;
|
||||
|
||||
let tests = tests as *mut ::test::Collector as *libc::c_void;
|
||||
let markdown = sd_markdown_new(extensions, 16, &callbacks, tests);
|
||||
let document = hoedown_document_new(renderer, extensions, 16);
|
||||
hoedown_document_render(document, ob, doc.as_ptr(),
|
||||
doc.len() as libc::size_t);
|
||||
hoedown_document_free(document);
|
||||
|
||||
sd_markdown_render(ob, doc.as_ptr(), doc.len() as libc::size_t,
|
||||
markdown);
|
||||
sd_markdown_free(markdown);
|
||||
bufrelease(ob);
|
||||
hoedown_html_renderer_free(renderer);
|
||||
hoedown_buffer_free(ob);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ fn main() {
|
||||
unsafe { puts(c_buffer); }
|
||||
});
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
*/
|
||||
|
||||
|
@ -52,7 +52,7 @@ loop {
|
||||
None => { break }
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
This `for` loop syntax can be applied to any iterator over any type.
|
||||
|
||||
|
@ -33,7 +33,7 @@ local_data::get(key_int, |opt| assert_eq!(opt.map(|x| *x), Some(3)));
|
||||
|
||||
local_data::set(key_vector, ~[4]);
|
||||
local_data::get(key_vector, |opt| assert_eq!(*opt.unwrap(), ~[4]));
|
||||
```
|
||||
```
|
||||
|
||||
*/
|
||||
|
||||
|
@ -19,7 +19,7 @@ homogeneous types:
|
||||
```rust
|
||||
let int_vector = [1,2,3];
|
||||
let str_vector = ["one", "two", "three"];
|
||||
```
|
||||
```
|
||||
|
||||
This is a big module, but for a high-level overview:
|
||||
|
||||
@ -44,7 +44,7 @@ a vector or a vector slice from the index interval `[a, b)`:
|
||||
let numbers = [0, 1, 2];
|
||||
let last_numbers = numbers.slice(1, 3);
|
||||
// last_numbers is now &[1, 2]
|
||||
```
|
||||
```
|
||||
|
||||
Traits defined for the `~[T]` type, like `OwnedVector`, can only be called
|
||||
on such vectors. These methods deal with adding elements or otherwise changing
|
||||
@ -57,7 +57,7 @@ of the vector:
|
||||
let mut numbers = vec![0, 1, 2];
|
||||
numbers.push(7);
|
||||
// numbers is now vec![0, 1, 2, 7];
|
||||
```
|
||||
```
|
||||
|
||||
## Implementations of other traits
|
||||
|
||||
@ -79,7 +79,7 @@ let numbers = [0, 1, 2];
|
||||
for &x in numbers.iter() {
|
||||
println!("{} is a number!", x);
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
* `.mut_iter()` returns an iterator that allows modifying each value.
|
||||
* `.move_iter()` converts an owned vector into an iterator that
|
||||
|
@ -37,7 +37,7 @@ fn main() {
|
||||
let borrowed_string1 = "This string is borrowed with the 'static lifetime";
|
||||
let borrowed_string2: &str = owned_string; // owned strings can be borrowed
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
From the example above, you can see that Rust has 2 different kinds of string
|
||||
literals. The owned literals correspond to the owned string types, but the
|
||||
|
@ -35,7 +35,7 @@ fn main() {
|
||||
let uuid1 = Uuid::new_v4();
|
||||
println!("{}", uuid1.to_str());
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
# Strings
|
||||
|
||||
|
1
src/rt/hoedown
Submodule
1
src/rt/hoedown
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 238c4d57cce10d33b05cf52a91fc62a09f31ffbb
|
5
src/rt/sundown/.gitignore
vendored
5
src/rt/sundown/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
*.o
|
||||
libsundown.so*
|
||||
sundown
|
||||
smartypants
|
||||
*.exe
|
@ -1,10 +0,0 @@
|
||||
Contributing to Sundown
|
||||
=======================
|
||||
|
||||
Do not.
|
||||
|
||||
Unfortunately, Sundown is currently frozen as we're working with the Reddit, StackOverflow and Meteor developers to design a formal Markdown standard and parser that will supersede Sundown in all these websites (and in GitHub, of course). Our goal is to deprecate Sundown altogether before the end of the year.
|
||||
|
||||
The new parser will be smaller, faster, safer and most importantly, more consistent.
|
||||
|
||||
Please stay tuned.
|
@ -1,83 +0,0 @@
|
||||
# Makefile
|
||||
|
||||
# Copyright (c) 2009, Natacha Porté
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
DEPDIR=depends
|
||||
|
||||
# "Machine-dependent" options
|
||||
#MFLAGS=-fPIC
|
||||
|
||||
CFLAGS=-c -g -O3 -fPIC -Wall -Werror -Wsign-compare -Isrc -Ihtml
|
||||
LDFLAGS=-g -O3 -Wall -Werror
|
||||
CC=gcc
|
||||
|
||||
|
||||
SUNDOWN_SRC=\
|
||||
src/markdown.o \
|
||||
src/stack.o \
|
||||
src/buffer.o \
|
||||
src/autolink.o \
|
||||
html/html.o \
|
||||
html/html_smartypants.o \
|
||||
html/houdini_html_e.o \
|
||||
html/houdini_href_e.o
|
||||
|
||||
all: libsundown.so sundown smartypants html_blocks
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
# libraries
|
||||
|
||||
libsundown.so: libsundown.so.1
|
||||
ln -f -s $^ $@
|
||||
|
||||
libsundown.so.1: $(SUNDOWN_SRC)
|
||||
$(CC) $(LDFLAGS) -shared -Wl $^ -o $@
|
||||
|
||||
# executables
|
||||
|
||||
sundown: examples/sundown.o $(SUNDOWN_SRC)
|
||||
$(CC) $(LDFLAGS) $^ -o $@
|
||||
|
||||
smartypants: examples/smartypants.o $(SUNDOWN_SRC)
|
||||
$(CC) $(LDFLAGS) $^ -o $@
|
||||
|
||||
# perfect hashing
|
||||
html_blocks: src/html_blocks.h
|
||||
|
||||
src/html_blocks.h: html_block_names.txt
|
||||
gperf -N find_block_tag -H hash_block_tag -C -c -E --ignore-case $^ > $@
|
||||
|
||||
|
||||
# housekeeping
|
||||
clean:
|
||||
rm -f src/*.o html/*.o examples/*.o
|
||||
rm -f libsundown.so libsundown.so.1 sundown smartypants
|
||||
rm -f sundown.exe smartypants.exe
|
||||
rm -rf $(DEPDIR)
|
||||
|
||||
|
||||
# dependencies
|
||||
|
||||
include $(wildcard $(DEPDIR)/*.d)
|
||||
|
||||
|
||||
# generic object compilations
|
||||
|
||||
%.o: src/%.c examples/%.c html/%.c
|
||||
@mkdir -p $(DEPDIR)
|
||||
@$(CC) -MM $< > $(DEPDIR)/$*.d
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
@ -1,33 +0,0 @@
|
||||
|
||||
CFLAGS=/O2 /EHsc /I"src/" /I"examples"/ /I"html"/
|
||||
CC=cl
|
||||
|
||||
SUNDOWN_SRC=\
|
||||
src\markdown.obj \
|
||||
src\stack.obj \
|
||||
src\buffer.obj \
|
||||
src\autolink.obj \
|
||||
html\html.obj \
|
||||
html\html_smartypants.obj \
|
||||
html\houdini_html_e.obj \
|
||||
html\houdini_href_e.obj
|
||||
|
||||
all: sundown.dll sundown.exe
|
||||
|
||||
sundown.dll: $(SUNDOWN_SRC) sundown.def
|
||||
$(CC) $(SUNDOWN_SRC) sundown.def /link /DLL $(LDFLAGS) /out:$@
|
||||
|
||||
sundown.exe: examples\sundown.obj $(SUNDOWN_SRC)
|
||||
$(CC) examples\sundown.obj $(SUNDOWN_SRC) /link $(LDFLAGS) /out:$@
|
||||
|
||||
# housekeeping
|
||||
clean:
|
||||
del $(SUNDOWN_SRC)
|
||||
del sundown.dll sundown.exe
|
||||
del sundown.exp sundown.lib
|
||||
|
||||
# generic object compilations
|
||||
|
||||
.c.obj:
|
||||
$(CC) $(CFLAGS) /c $< /Fo$@
|
||||
|
@ -1,131 +0,0 @@
|
||||
Sundown
|
||||
=======
|
||||
|
||||
`Sundown` is a Markdown parser based on the original code of the
|
||||
[Upskirt library](http://fossil.instinctive.eu/libupskirt/index) by Natacha Porté.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* **Fully standards compliant**
|
||||
|
||||
`Sundown` passes out of the box the official Markdown v1.0.0 and v1.0.3
|
||||
test suites, and has been extensively tested with additional corner cases
|
||||
to make sure its output is as sane as possible at all times.
|
||||
|
||||
* **Massive extension support**
|
||||
|
||||
`Sundown` has optional support for several (unofficial) Markdown extensions,
|
||||
such as non-strict emphasis, fenced code blocks, tables, autolinks,
|
||||
strikethrough and more.
|
||||
|
||||
* **UTF-8 aware**
|
||||
|
||||
`Sundown` is fully UTF-8 aware, both when parsing the source document and when
|
||||
generating the resulting (X)HTML code.
|
||||
|
||||
* **Tested & Ready to be used on production**
|
||||
|
||||
`Sundown` has been extensively security audited, and includes protection against
|
||||
all possible DOS attacks (stack overflows, out of memory situations, malformed
|
||||
Markdown syntax...) and against client attacks through malicious embedded HTML.
|
||||
|
||||
We've worked very hard to make `Sundown` never crash or run out of memory
|
||||
under *any* input. `Sundown` renders all the Markdown content in GitHub and so
|
||||
far hasn't crashed a single time.
|
||||
|
||||
* **Customizable renderers**
|
||||
|
||||
`Sundown` is not stuck with XHTML output: the Markdown parser of the library
|
||||
is decoupled from the renderer, so it's trivial to extend the library with
|
||||
custom renderers. A fully functional (X)HTML renderer is included.
|
||||
|
||||
* **Optimized for speed**
|
||||
|
||||
`Sundown` is written in C, with a special emphasis on performance. When wrapped
|
||||
on a dynamic language such as Python or Ruby, it has shown to be up to 40
|
||||
times faster than other native alternatives.
|
||||
|
||||
* **Zero-dependency**
|
||||
|
||||
`Sundown` is a zero-dependency library composed of 3 `.c` files and their headers.
|
||||
No dependencies, no bullshit. Only standard C99 that builds everywhere.
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
`Sundown` is based on the original Upskirt parser by Natacha Porté, with many additions
|
||||
by Vicent Marti (@vmg) and contributions from the following authors:
|
||||
|
||||
Ben Noordhuis, Bruno Michel, Joseph Koshy, Krzysztof Kowalczyk, Samuel Bronson,
|
||||
Shuhei Tanuma
|
||||
|
||||
Bindings
|
||||
--------
|
||||
|
||||
`Sundown` is available from other programming languages thanks to these bindings developed
|
||||
by our awesome contributors.
|
||||
|
||||
- [Redcarpet](https://github.com/vmg/redcarpet) (Ruby)
|
||||
- [RobotSkirt](https://github.com/benmills/robotskirt) (Node.js)
|
||||
- [Misaka](https://github.com/FSX/misaka) (Python)
|
||||
- [ffi-sundown](https://github.com/postmodern/ffi-sundown) (Ruby FFI)
|
||||
- [Sundown HS](https://github.com/bitonic/sundown) (Haskell)
|
||||
- [Goskirt](https://github.com/madari/goskirt) (Go)
|
||||
- [Upskirt.go](https://github.com/buu700/upskirt.go) (Go)
|
||||
- [MoonShine](https://github.com/brandonc/moonshine) (.NET)
|
||||
- [PHP-Sundown](https://github.com/chobie/php-sundown) (PHP)
|
||||
- [Sundown.net](https://github.com/txdv/sundown.net) (.NET)
|
||||
|
||||
Help us
|
||||
-------
|
||||
|
||||
`Sundown` is all about security. If you find a (potential) security vulnerability in the
|
||||
library, or a way to make it crash through malicious input, please report it to us,
|
||||
either directly via email or by opening an Issue on GitHub, and help make the web safer
|
||||
for everybody.
|
||||
|
||||
Unicode character handling
|
||||
--------------------------
|
||||
|
||||
Given that the Markdown spec makes no provision for Unicode character handling, `Sundown`
|
||||
takes a conservative approach towards deciding which extended characters trigger Markdown
|
||||
features:
|
||||
|
||||
* Punctuation characters outside of the U+007F codepoint are not handled as punctuation.
|
||||
They are considered as normal, in-word characters for word-boundary checks.
|
||||
|
||||
* Whitespace characters outside of the U+007F codepoint are not considered as
|
||||
whitespace. They are considered as normal, in-word characters for word-boundary checks.
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
There is nothing to install. `Sundown` is composed of 3 `.c` files (`markdown.c`,
|
||||
`buffer.c` and `array.c`), so just throw them in your project. Zero-dependency means
|
||||
zero-dependency. You might want to include `render/html.c` if you want to use the
|
||||
included XHTML renderer, or write your own renderer. Either way, it's all fun and joy.
|
||||
|
||||
If you are hardcore, you can use the included `Makefile` to build `Sundown` into a dynamic
|
||||
library, or to build the sample `sundown` executable, which is just a commandline
|
||||
Markdown to XHTML parser. (If gcc gives you grief about `-fPIC`, e.g. with MinGW, try
|
||||
`make MFLAGS=` instead of just `make`.)
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
<!-- Local Variables: -->
|
||||
<!-- fill-column: 89 -->
|
||||
<!-- End: -->
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Vicent Marti
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "markdown.h"
|
||||
#include "html.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#include <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: */
|
@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Vicent Marti
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "markdown.h"
|
||||
#include "html.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#include <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: */
|
@ -1,37 +0,0 @@
|
||||
#ifndef HOUDINI_H__
|
||||
#define HOUDINI_H__
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef HOUDINI_USE_LOCALE
|
||||
# define _isxdigit(c) isxdigit(c)
|
||||
# define _isdigit(c) isdigit(c)
|
||||
#else
|
||||
/*
|
||||
* Helper _isdigit methods -- do not trust the current locale
|
||||
* */
|
||||
# define _isxdigit(c) (strchr("0123456789ABCDEFabcdef", (c)) != NULL)
|
||||
# define _isdigit(c) ((c) >= '0' && (c) <= '9')
|
||||
#endif
|
||||
|
||||
extern void houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size);
|
||||
extern void houdini_escape_html0(struct buf *ob, const uint8_t *src, size_t size, int secure);
|
||||
extern void houdini_unescape_html(struct buf *ob, const uint8_t *src, size_t size);
|
||||
extern void houdini_escape_xml(struct buf *ob, const uint8_t *src, size_t size);
|
||||
extern void houdini_escape_uri(struct buf *ob, const uint8_t *src, size_t size);
|
||||
extern void houdini_escape_url(struct buf *ob, const uint8_t *src, size_t size);
|
||||
extern void houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size);
|
||||
extern void houdini_unescape_uri(struct buf *ob, const uint8_t *src, size_t size);
|
||||
extern void houdini_unescape_url(struct buf *ob, const uint8_t *src, size_t size);
|
||||
extern void houdini_escape_js(struct buf *ob, const uint8_t *src, size_t size);
|
||||
extern void houdini_unescape_js(struct buf *ob, const uint8_t *src, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,108 +0,0 @@
|
||||
#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++;
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
|
@ -1,635 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Natacha Porté
|
||||
* Copyright (c) 2011, Vicent Marti
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "markdown.h"
|
||||
#include "html.h"
|
||||
|
||||
#include <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;
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Vicent Marti
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UPSKIRT_HTML_H
|
||||
#define UPSKIRT_HTML_H
|
||||
|
||||
#include "markdown.h"
|
||||
#include "buffer.h"
|
||||
#include <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
|
||||
|
@ -1,389 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Vicent Marti
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "buffer.h"
|
||||
#include "html.h"
|
||||
|
||||
#include <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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,25 +0,0 @@
|
||||
##
|
||||
p
|
||||
dl
|
||||
h1
|
||||
h2
|
||||
h3
|
||||
h4
|
||||
h5
|
||||
h6
|
||||
ol
|
||||
ul
|
||||
del
|
||||
div
|
||||
ins
|
||||
pre
|
||||
form
|
||||
math
|
||||
table
|
||||
figure
|
||||
iframe
|
||||
script
|
||||
style
|
||||
fieldset
|
||||
noscript
|
||||
blockquote
|
@ -1,297 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Vicent Marti
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "buffer.h"
|
||||
#include "autolink.h"
|
||||
|
||||
#include <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;
|
||||
}
|
||||
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Vicent Marti
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UPSKIRT_AUTOLINK_H
|
||||
#define UPSKIRT_AUTOLINK_H
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
SD_AUTOLINK_SHORT_DOMAINS = (1 << 0),
|
||||
};
|
||||
|
||||
int
|
||||
sd_autolink_issafe(const uint8_t *link, size_t link_len);
|
||||
|
||||
size_t
|
||||
sd_autolink__www(size_t *rewind_p, struct buf *link,
|
||||
uint8_t *data, size_t offset, size_t size, unsigned int flags);
|
||||
|
||||
size_t
|
||||
sd_autolink__email(size_t *rewind_p, struct buf *link,
|
||||
uint8_t *data, size_t offset, size_t size, unsigned int flags);
|
||||
|
||||
size_t
|
||||
sd_autolink__url(size_t *rewind_p, struct buf *link,
|
||||
uint8_t *data, size_t offset, size_t size, unsigned int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* vim: set filetype=c: */
|
@ -1,225 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Natacha Porté
|
||||
* Copyright (c) 2011, Vicent Martí
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#define BUFFER_MAX_ALLOC_SIZE (1024 * 1024 * 16) //16mb
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
#include <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);
|
||||
}
|
||||
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Natacha Porté
|
||||
* Copyright (c) 2011, Vicent Martí
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef BUFFER_H__
|
||||
#define BUFFER_H__
|
||||
|
||||
#include <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
|
@ -1,206 +0,0 @@
|
||||
/* C code produced by gperf version 3.0.3 */
|
||||
/* Command-line: gperf -N find_block_tag -H hash_block_tag -C -c -E --ignore-case html_block_names.txt */
|
||||
/* Computed positions: -k'1-2' */
|
||||
|
||||
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
||||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
||||
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
|
||||
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
|
||||
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
|
||||
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
|
||||
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
|
||||
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
|
||||
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
|
||||
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
|
||||
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
|
||||
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
|
||||
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
|
||||
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
|
||||
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
|
||||
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
|
||||
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
|
||||
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
|
||||
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
|
||||
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
|
||||
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
|
||||
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
|
||||
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
|
||||
/* The character set is not based on ISO-646. */
|
||||
error "gperf generated tables don't work with this execution character set. Please report a bug to <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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,138 +0,0 @@
|
||||
/* markdown.h - generic markdown parser */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009, Natacha Porté
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UPSKIRT_MARKDOWN_H
|
||||
#define UPSKIRT_MARKDOWN_H
|
||||
|
||||
#include "buffer.h"
|
||||
#include "autolink.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SUNDOWN_VERSION "1.16.0"
|
||||
#define SUNDOWN_VER_MAJOR 1
|
||||
#define SUNDOWN_VER_MINOR 16
|
||||
#define SUNDOWN_VER_REVISION 0
|
||||
|
||||
/********************
|
||||
* TYPE DEFINITIONS *
|
||||
********************/
|
||||
|
||||
/* mkd_autolink - type of autolink */
|
||||
enum mkd_autolink {
|
||||
MKDA_NOT_AUTOLINK, /* used internally when it is not an autolink*/
|
||||
MKDA_NORMAL, /* normal http/http/ftp/mailto/etc link */
|
||||
MKDA_EMAIL, /* e-mail link without explit mailto: */
|
||||
};
|
||||
|
||||
enum mkd_tableflags {
|
||||
MKD_TABLE_ALIGN_L = 1,
|
||||
MKD_TABLE_ALIGN_R = 2,
|
||||
MKD_TABLE_ALIGN_CENTER = 3,
|
||||
MKD_TABLE_ALIGNMASK = 3,
|
||||
MKD_TABLE_HEADER = 4
|
||||
};
|
||||
|
||||
enum mkd_extensions {
|
||||
MKDEXT_NO_INTRA_EMPHASIS = (1 << 0),
|
||||
MKDEXT_TABLES = (1 << 1),
|
||||
MKDEXT_FENCED_CODE = (1 << 2),
|
||||
MKDEXT_AUTOLINK = (1 << 3),
|
||||
MKDEXT_STRIKETHROUGH = (1 << 4),
|
||||
MKDEXT_SPACE_HEADERS = (1 << 6),
|
||||
MKDEXT_SUPERSCRIPT = (1 << 7),
|
||||
MKDEXT_LAX_SPACING = (1 << 8),
|
||||
};
|
||||
|
||||
/* sd_callbacks - functions for rendering parsed data */
|
||||
struct sd_callbacks {
|
||||
/* block level callbacks - NULL skips the block */
|
||||
void (*blockcode)(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque);
|
||||
void (*blockquote)(struct buf *ob, const struct buf *text, void *opaque);
|
||||
void (*blockhtml)(struct buf *ob,const struct buf *text, void *opaque);
|
||||
void (*header)(struct buf *ob, const struct buf *text, int level, void *opaque);
|
||||
void (*hrule)(struct buf *ob, void *opaque);
|
||||
void (*list)(struct buf *ob, const struct buf *text, int flags, void *opaque);
|
||||
void (*listitem)(struct buf *ob, const struct buf *text, int flags, void *opaque);
|
||||
void (*paragraph)(struct buf *ob, const struct buf *text, void *opaque);
|
||||
void (*table)(struct buf *ob, const struct buf *header, const struct buf *body, void *opaque);
|
||||
void (*table_row)(struct buf *ob, const struct buf *text, void *opaque);
|
||||
void (*table_cell)(struct buf *ob, const struct buf *text, int flags, void *opaque);
|
||||
|
||||
|
||||
/* span level callbacks - NULL or return 0 prints the span verbatim */
|
||||
int (*autolink)(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque);
|
||||
int (*codespan)(struct buf *ob, const struct buf *text, void *opaque);
|
||||
int (*double_emphasis)(struct buf *ob, const struct buf *text, void *opaque);
|
||||
int (*emphasis)(struct buf *ob, const struct buf *text, void *opaque);
|
||||
int (*image)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque);
|
||||
int (*linebreak)(struct buf *ob, void *opaque);
|
||||
int (*link)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque);
|
||||
int (*raw_html_tag)(struct buf *ob, const struct buf *tag, void *opaque);
|
||||
int (*triple_emphasis)(struct buf *ob, const struct buf *text, void *opaque);
|
||||
int (*strikethrough)(struct buf *ob, const struct buf *text, void *opaque);
|
||||
int (*superscript)(struct buf *ob, const struct buf *text, void *opaque);
|
||||
|
||||
/* low level callbacks - NULL copies input directly into the output */
|
||||
void (*entity)(struct buf *ob, const struct buf *entity, void *opaque);
|
||||
void (*normal_text)(struct buf *ob, const struct buf *text, void *opaque);
|
||||
|
||||
/* header and footer */
|
||||
void (*doc_header)(struct buf *ob, void *opaque);
|
||||
void (*doc_footer)(struct buf *ob, void *opaque);
|
||||
};
|
||||
|
||||
struct sd_markdown;
|
||||
|
||||
/*********
|
||||
* FLAGS *
|
||||
*********/
|
||||
|
||||
/* list/listitem flags */
|
||||
#define MKD_LIST_ORDERED 1
|
||||
#define MKD_LI_BLOCK 2 /* <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: */
|
@ -1,81 +0,0 @@
|
||||
#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];
|
||||
}
|
||||
|
@ -1,29 +0,0 @@
|
||||
#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
|
Loading…
Reference in New Issue
Block a user