Use clang-format, llvm style, for formatting.
* Reformatted all source files. * Added 'format' target to Makefile. * Removed 'astyle' target. * Updated .editorconfig.
This commit is contained in:
Родитель
aca7161e53
Коммит
62cb38bf8a
|
@ -9,8 +9,8 @@ insert_final_newline = true
|
|||
|
||||
[*.{c,h}]
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[Makefile]
|
||||
trim_trailing_whitespace = true
|
||||
|
|
8
Makefile
8
Makefile
|
@ -20,7 +20,7 @@ RELEASE?=CommonMark-$(VERSION)
|
|||
INSTALL_PREFIX?=/usr/local
|
||||
CLANG_CHECK?=clang-check
|
||||
|
||||
.PHONY: all cmake_build spec leakcheck clean fuzztest dingus upload test update-site upload-site debug ubsan asan mingw archive bench astyle update-spec afl clang-check
|
||||
.PHONY: all cmake_build spec leakcheck clean fuzztest dingus upload test update-site upload-site debug ubsan asan mingw archive bench format update-spec afl clang-check
|
||||
|
||||
all: cmake_build man/man3/cmark.3
|
||||
|
||||
|
@ -115,6 +115,7 @@ $(SRCDIR)/scanners.c: $(SRCDIR)/scanners.re
|
|||
esac
|
||||
re2c --case-insensitive -b -i --no-generation-date -8 \
|
||||
--encoding-policy substitute -o $@ $<
|
||||
clang-format -style llvm -i $@
|
||||
|
||||
# We include entities.inc in the repository, so normally this
|
||||
# doesn't need to be regenerated:
|
||||
|
@ -167,9 +168,8 @@ bench: $(BENCHFILE)
|
|||
done \
|
||||
} 2>&1 | grep 'real' | awk '{print $$2}' | python3 'bench/stats.py'
|
||||
|
||||
astyle:
|
||||
astyle --style=linux -t -p -r 'src/*.c' --exclude=scanners.c
|
||||
astyle --style=linux -t -p -r 'src/*.h' --exclude=html_unescape.h
|
||||
format:
|
||||
clang-format -style llvm -i src/*.c src/*.h
|
||||
|
||||
operf: $(CMARK)
|
||||
operf $< < $(BENCHINP) > /dev/null
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH cmark 3 "July 13, 2015" "LOCAL" "Library Functions Manual"
|
||||
.TH cmark 3 "July 27, 2015" "LOCAL" "Library Functions Manual"
|
||||
.SH
|
||||
NAME
|
||||
.PP
|
||||
|
@ -24,7 +24,7 @@ Node Structure
|
|||
Creating and Destroying Nodes
|
||||
|
||||
.PP
|
||||
\fIcmark_node*\f[] \fBcmark_node_new\f[](\fIcmark_node_type type\f[])
|
||||
\fIcmark_node *\f[] \fBcmark_node_new\f[](\fIcmark_node_type type\f[])
|
||||
|
||||
.PP
|
||||
Creates a new node of type \f[I]type\f[]. Note that the node may have
|
||||
|
@ -41,34 +41,34 @@ Frees the memory allocated for a node.
|
|||
Tree Traversal
|
||||
|
||||
.PP
|
||||
\fIcmark_node*\f[] \fBcmark_node_next\f[](\fIcmark_node *node\f[])
|
||||
\fIcmark_node *\f[] \fBcmark_node_next\f[](\fIcmark_node *node\f[])
|
||||
|
||||
.PP
|
||||
Returns the next node in the sequence after \f[I]node\f[], or NULL if
|
||||
there is none.
|
||||
|
||||
.PP
|
||||
\fIcmark_node*\f[] \fBcmark_node_previous\f[](\fIcmark_node *node\f[])
|
||||
\fIcmark_node *\f[] \fBcmark_node_previous\f[](\fIcmark_node *node\f[])
|
||||
|
||||
.PP
|
||||
Returns the previous node in the sequence after \f[I]node\f[], or NULL
|
||||
if there is none.
|
||||
|
||||
.PP
|
||||
\fIcmark_node*\f[] \fBcmark_node_parent\f[](\fIcmark_node *node\f[])
|
||||
\fIcmark_node *\f[] \fBcmark_node_parent\f[](\fIcmark_node *node\f[])
|
||||
|
||||
.PP
|
||||
Returns the parent of \f[I]node\f[], or NULL if there is none.
|
||||
|
||||
.PP
|
||||
\fIcmark_node*\f[] \fBcmark_node_first_child\f[](\fIcmark_node *node\f[])
|
||||
\fIcmark_node *\f[] \fBcmark_node_first_child\f[](\fIcmark_node *node\f[])
|
||||
|
||||
.PP
|
||||
Returns the first child of \f[I]node\f[], or NULL if \f[I]node\f[] has
|
||||
no children.
|
||||
|
||||
.PP
|
||||
\fIcmark_node*\f[] \fBcmark_node_last_child\f[](\fIcmark_node *node\f[])
|
||||
\fIcmark_node *\f[] \fBcmark_node_last_child\f[](\fIcmark_node *node\f[])
|
||||
|
||||
.PP
|
||||
Returns the last child of \f[I]node\f[], or NULL if \f[I]node\f[] has no
|
||||
|
@ -130,7 +130,7 @@ Nodes must only be modified after an \f[C]EXIT\f[] event, or an
|
|||
\f[C]ENTER\f[] event for leaf nodes.
|
||||
|
||||
.PP
|
||||
\fIcmark_iter*\f[] \fBcmark_iter_new\f[](\fIcmark_node *root\f[])
|
||||
\fIcmark_iter *\f[] \fBcmark_iter_new\f[](\fIcmark_node *root\f[])
|
||||
|
||||
.PP
|
||||
Creates a new iterator starting at \f[I]root\f[]. The current node and
|
||||
|
@ -152,7 +152,7 @@ Advances to the next node and returns the event type
|
|||
\f[C]CMARK_EVENT_DONE\f[]).
|
||||
|
||||
.PP
|
||||
\fIcmark_node*\f[] \fBcmark_iter_get_node\f[](\fIcmark_iter *iter\f[])
|
||||
\fIcmark_node *\f[] \fBcmark_iter_get_node\f[](\fIcmark_iter *iter\f[])
|
||||
|
||||
.PP
|
||||
Returns the current node.
|
||||
|
@ -164,7 +164,7 @@ Returns the current node.
|
|||
Returns the current event type.
|
||||
|
||||
.PP
|
||||
\fIcmark_node*\f[] \fBcmark_iter_get_root\f[](\fIcmark_iter *iter\f[])
|
||||
\fIcmark_node *\f[] \fBcmark_iter_get_root\f[](\fIcmark_iter *iter\f[])
|
||||
|
||||
.PP
|
||||
Returns the root node.
|
||||
|
@ -181,7 +181,7 @@ descendant of the root node or the root node itself.
|
|||
Accessors
|
||||
|
||||
.PP
|
||||
\fIvoid*\f[] \fBcmark_node_get_user_data\f[](\fIcmark_node *node\f[])
|
||||
\fIvoid *\f[] \fBcmark_node_get_user_data\f[](\fIcmark_node *node\f[])
|
||||
|
||||
.PP
|
||||
Returns the user data of \f[I]node\f[].
|
||||
|
@ -200,14 +200,14 @@ failure.
|
|||
Returns the type of \f[I]node\f[], or \f[C]CMARK_NODE_NONE\f[] on error.
|
||||
|
||||
.PP
|
||||
\fIconst char*\f[] \fBcmark_node_get_type_string\f[](\fIcmark_node *node\f[])
|
||||
\fIconst char *\f[] \fBcmark_node_get_type_string\f[](\fIcmark_node *node\f[])
|
||||
|
||||
.PP
|
||||
Like \f[I]cmark_node_get_type\f[], but returns a string representation
|
||||
of the type, or \f[C]"<unknown>"\f[].
|
||||
|
||||
.PP
|
||||
\fIconst char*\f[] \fBcmark_node_get_literal\f[](\fIcmark_node *node\f[])
|
||||
\fIconst char *\f[] \fBcmark_node_get_literal\f[](\fIcmark_node *node\f[])
|
||||
|
||||
.PP
|
||||
Returns the string contents of \f[I]node\f[], or NULL if none.
|
||||
|
@ -288,7 +288,7 @@ Returns 1 if \f[I]node\f[] is a tight list, 0 otherwise.
|
|||
Sets the "tightness" of a list. Returns 1 on success, 0 on failure.
|
||||
|
||||
.PP
|
||||
\fIconst char*\f[] \fBcmark_node_get_fence_info\f[](\fIcmark_node *node\f[])
|
||||
\fIconst char *\f[] \fBcmark_node_get_fence_info\f[](\fIcmark_node *node\f[])
|
||||
|
||||
.PP
|
||||
Returns the info string from a fenced code block, or NULL if none.
|
||||
|
@ -301,7 +301,7 @@ Sets the info string in a fenced code block, returning 1 on success and
|
|||
0 on failure.
|
||||
|
||||
.PP
|
||||
\fIconst char*\f[] \fBcmark_node_get_url\f[](\fIcmark_node *node\f[])
|
||||
\fIconst char *\f[] \fBcmark_node_get_url\f[](\fIcmark_node *node\f[])
|
||||
|
||||
.PP
|
||||
Gets the URL of a link or image \f[I]node\f[], or NULL if none.
|
||||
|
@ -314,7 +314,7 @@ Sets the URL of a link or image \f[I]node\f[]. Returns 1 on success, 0
|
|||
on failure.
|
||||
|
||||
.PP
|
||||
\fIconst char*\f[] \fBcmark_node_get_title\f[](\fIcmark_node *node\f[])
|
||||
\fIconst char *\f[] \fBcmark_node_get_title\f[](\fIcmark_node *node\f[])
|
||||
|
||||
.PP
|
||||
Gets the title of a link or image \f[I]node\f[], or NULL if none.
|
||||
|
|
16
src/bench.h
16
src/bench.h
|
@ -9,15 +9,15 @@ float _cmark_start_time;
|
|||
float _cmark_end_time;
|
||||
float _cmark_save_time;
|
||||
|
||||
#define start_timer() \
|
||||
_cmark_save_time = _cmark_start_time; \
|
||||
_cmark_start_time = (float)clock()/CLOCKS_PER_SEC
|
||||
#define start_timer() \
|
||||
_cmark_save_time = _cmark_start_time; \
|
||||
_cmark_start_time = (float)clock() / CLOCKS_PER_SEC
|
||||
|
||||
#define end_timer(M) \
|
||||
_cmark_end_time = (float)clock()/CLOCKS_PER_SEC; \
|
||||
fprintf(stderr, "[TIME] (%s:%d) %4.f ns " M "\n", __FILE__, \
|
||||
__LINE__, (_cmark_end_time - _cmark_start_time) * 1000000); \
|
||||
_cmark_start_time = _cmark_save_time;
|
||||
#define end_timer(M) \
|
||||
_cmark_end_time = (float)clock() / CLOCKS_PER_SEC; \
|
||||
fprintf(stderr, "[TIME] (%s:%d) %4.f ns " M "\n", __FILE__, __LINE__, \
|
||||
(_cmark_end_time - _cmark_start_time) * 1000000); \
|
||||
_cmark_start_time = _cmark_save_time;
|
||||
|
||||
#else
|
||||
#define start_timer()
|
||||
|
|
1776
src/blocks.c
1776
src/blocks.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
460
src/buffer.c
460
src/buffer.c
|
@ -16,323 +16,301 @@
|
|||
unsigned char cmark_strbuf__initbuf[1];
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) ((x<y) ? x : y)
|
||||
#define MIN(x, y) ((x < y) ? x : y)
|
||||
#endif
|
||||
|
||||
void cmark_strbuf_init(cmark_strbuf *buf, bufsize_t initial_size)
|
||||
{
|
||||
buf->asize = 0;
|
||||
buf->size = 0;
|
||||
buf->ptr = cmark_strbuf__initbuf;
|
||||
void cmark_strbuf_init(cmark_strbuf *buf, bufsize_t initial_size) {
|
||||
buf->asize = 0;
|
||||
buf->size = 0;
|
||||
buf->ptr = cmark_strbuf__initbuf;
|
||||
|
||||
if (initial_size > 0)
|
||||
cmark_strbuf_grow(buf, initial_size);
|
||||
if (initial_size > 0)
|
||||
cmark_strbuf_grow(buf, initial_size);
|
||||
}
|
||||
|
||||
void cmark_strbuf_overflow_err()
|
||||
{
|
||||
fprintf(stderr, "String buffer overflow");
|
||||
abort();
|
||||
void cmark_strbuf_overflow_err() {
|
||||
fprintf(stderr, "String buffer overflow");
|
||||
abort();
|
||||
}
|
||||
|
||||
static inline void
|
||||
S_strbuf_grow_by(cmark_strbuf *buf, size_t add)
|
||||
{
|
||||
size_t target_size = (size_t)buf->size + add;
|
||||
static inline void S_strbuf_grow_by(cmark_strbuf *buf, size_t add) {
|
||||
size_t target_size = (size_t)buf->size + add;
|
||||
|
||||
if (target_size < add /* Integer overflow. */
|
||||
|| target_size > BUFSIZE_MAX /* Truncation overflow. */
|
||||
) {
|
||||
cmark_strbuf_overflow_err();
|
||||
return; /* unreachable */
|
||||
}
|
||||
if (target_size < add /* Integer overflow. */
|
||||
|| target_size > BUFSIZE_MAX /* Truncation overflow. */
|
||||
) {
|
||||
cmark_strbuf_overflow_err();
|
||||
return; /* unreachable */
|
||||
}
|
||||
|
||||
if ((bufsize_t)target_size >= buf->asize)
|
||||
cmark_strbuf_grow(buf, (bufsize_t)target_size);
|
||||
if ((bufsize_t)target_size >= buf->asize)
|
||||
cmark_strbuf_grow(buf, (bufsize_t)target_size);
|
||||
}
|
||||
|
||||
void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size)
|
||||
{
|
||||
unsigned char *new_ptr;
|
||||
void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) {
|
||||
unsigned char *new_ptr;
|
||||
|
||||
if (target_size < buf->asize)
|
||||
return;
|
||||
if (target_size < buf->asize)
|
||||
return;
|
||||
|
||||
if (buf->asize == 0) {
|
||||
new_ptr = NULL;
|
||||
} else {
|
||||
new_ptr = buf->ptr;
|
||||
}
|
||||
if (buf->asize == 0) {
|
||||
new_ptr = NULL;
|
||||
} else {
|
||||
new_ptr = buf->ptr;
|
||||
}
|
||||
|
||||
/* Oversize the buffer by 50% to guarantee amortized linear time
|
||||
* complexity on append operations. */
|
||||
size_t new_size = (size_t)target_size + (size_t)target_size / 2;
|
||||
/* Oversize the buffer by 50% to guarantee amortized linear time
|
||||
* complexity on append operations. */
|
||||
size_t new_size = (size_t)target_size + (size_t)target_size / 2;
|
||||
|
||||
/* Account for terminating null byte. */
|
||||
new_size += 1;
|
||||
/* Account for terminating null byte. */
|
||||
new_size += 1;
|
||||
|
||||
/* round allocation up to multiple of 8 */
|
||||
new_size = (new_size + 7) & ~7;
|
||||
/* round allocation up to multiple of 8 */
|
||||
new_size = (new_size + 7) & ~7;
|
||||
|
||||
if (new_size < (size_t)target_size /* Integer overflow. */
|
||||
|| new_size > BUFSIZE_MAX /* Truncation overflow. */
|
||||
) {
|
||||
if (target_size >= BUFSIZE_MAX) {
|
||||
/* No space for terminating null byte. */
|
||||
cmark_strbuf_overflow_err();
|
||||
return; /* unreachable */
|
||||
}
|
||||
/* Oversize by the maximum possible amount. */
|
||||
new_size = BUFSIZE_MAX;
|
||||
}
|
||||
if (new_size < (size_t)target_size /* Integer overflow. */
|
||||
|| new_size > BUFSIZE_MAX /* Truncation overflow. */
|
||||
) {
|
||||
if (target_size >= BUFSIZE_MAX) {
|
||||
/* No space for terminating null byte. */
|
||||
cmark_strbuf_overflow_err();
|
||||
return; /* unreachable */
|
||||
}
|
||||
/* Oversize by the maximum possible amount. */
|
||||
new_size = BUFSIZE_MAX;
|
||||
}
|
||||
|
||||
new_ptr = (unsigned char *)realloc(new_ptr, new_size);
|
||||
new_ptr = (unsigned char *)realloc(new_ptr, new_size);
|
||||
|
||||
if (!new_ptr) {
|
||||
perror("realloc in cmark_strbuf_grow");
|
||||
abort();
|
||||
}
|
||||
if (!new_ptr) {
|
||||
perror("realloc in cmark_strbuf_grow");
|
||||
abort();
|
||||
}
|
||||
|
||||
buf->asize = (bufsize_t)new_size;
|
||||
buf->ptr = new_ptr;
|
||||
buf->asize = (bufsize_t)new_size;
|
||||
buf->ptr = new_ptr;
|
||||
}
|
||||
|
||||
bufsize_t cmark_strbuf_len(const cmark_strbuf *buf)
|
||||
{
|
||||
return buf->size;
|
||||
bufsize_t cmark_strbuf_len(const cmark_strbuf *buf) { return buf->size; }
|
||||
|
||||
void cmark_strbuf_free(cmark_strbuf *buf) {
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
if (buf->ptr != cmark_strbuf__initbuf)
|
||||
free(buf->ptr);
|
||||
|
||||
cmark_strbuf_init(buf, 0);
|
||||
}
|
||||
|
||||
void cmark_strbuf_free(cmark_strbuf *buf)
|
||||
{
|
||||
if (!buf) return;
|
||||
void cmark_strbuf_clear(cmark_strbuf *buf) {
|
||||
buf->size = 0;
|
||||
|
||||
if (buf->ptr != cmark_strbuf__initbuf)
|
||||
free(buf->ptr);
|
||||
|
||||
cmark_strbuf_init(buf, 0);
|
||||
if (buf->asize > 0)
|
||||
buf->ptr[0] = '\0';
|
||||
}
|
||||
|
||||
void cmark_strbuf_clear(cmark_strbuf *buf)
|
||||
{
|
||||
buf->size = 0;
|
||||
|
||||
if (buf->asize > 0)
|
||||
buf->ptr[0] = '\0';
|
||||
void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data,
|
||||
bufsize_t len) {
|
||||
if (len <= 0 || data == NULL) {
|
||||
cmark_strbuf_clear(buf);
|
||||
} else {
|
||||
if (data != buf->ptr) {
|
||||
if (len >= buf->asize)
|
||||
cmark_strbuf_grow(buf, len);
|
||||
memmove(buf->ptr, data, len);
|
||||
}
|
||||
buf->size = len;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data, bufsize_t len)
|
||||
{
|
||||
if (len <= 0 || data == NULL) {
|
||||
cmark_strbuf_clear(buf);
|
||||
} else {
|
||||
if (data != buf->ptr) {
|
||||
if (len >= buf->asize)
|
||||
cmark_strbuf_grow(buf, len);
|
||||
memmove(buf->ptr, data, len);
|
||||
}
|
||||
buf->size = len;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
void cmark_strbuf_sets(cmark_strbuf *buf, const char *string) {
|
||||
cmark_strbuf_set(buf, (const unsigned char *)string,
|
||||
string ? cmark_strbuf_safe_strlen(string) : 0);
|
||||
}
|
||||
|
||||
void cmark_strbuf_sets(cmark_strbuf *buf, const char *string)
|
||||
{
|
||||
cmark_strbuf_set(buf, (const unsigned char *)string,
|
||||
string ? cmark_strbuf_safe_strlen(string) : 0);
|
||||
void cmark_strbuf_putc(cmark_strbuf *buf, int c) {
|
||||
S_strbuf_grow_by(buf, 1);
|
||||
buf->ptr[buf->size++] = c;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
|
||||
void cmark_strbuf_putc(cmark_strbuf *buf, int c)
|
||||
{
|
||||
S_strbuf_grow_by(buf, 1);
|
||||
buf->ptr[buf->size++] = c;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
|
||||
bufsize_t len) {
|
||||
if (len <= 0)
|
||||
return;
|
||||
|
||||
S_strbuf_grow_by(buf, len);
|
||||
memmove(buf->ptr + buf->size, data, len);
|
||||
buf->size += len;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
|
||||
void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data, bufsize_t len)
|
||||
{
|
||||
if (len <= 0)
|
||||
return;
|
||||
|
||||
S_strbuf_grow_by(buf, len);
|
||||
memmove(buf->ptr + buf->size, data, len);
|
||||
buf->size += len;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
void cmark_strbuf_puts(cmark_strbuf *buf, const char *string) {
|
||||
cmark_strbuf_put(buf, (const unsigned char *)string,
|
||||
cmark_strbuf_safe_strlen(string));
|
||||
}
|
||||
|
||||
void cmark_strbuf_puts(cmark_strbuf *buf, const char *string)
|
||||
{
|
||||
cmark_strbuf_put(buf, (const unsigned char *)string,
|
||||
cmark_strbuf_safe_strlen(string));
|
||||
void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize,
|
||||
const cmark_strbuf *buf) {
|
||||
bufsize_t copylen;
|
||||
|
||||
assert(buf);
|
||||
if (!data || datasize <= 0)
|
||||
return;
|
||||
|
||||
data[0] = '\0';
|
||||
|
||||
if (buf->size == 0 || buf->asize <= 0)
|
||||
return;
|
||||
|
||||
copylen = buf->size;
|
||||
if (copylen > datasize - 1)
|
||||
copylen = datasize - 1;
|
||||
memmove(data, buf->ptr, copylen);
|
||||
data[copylen] = '\0';
|
||||
}
|
||||
|
||||
void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize, const cmark_strbuf *buf)
|
||||
{
|
||||
bufsize_t copylen;
|
||||
|
||||
assert(buf);
|
||||
if (!data || datasize <= 0)
|
||||
return;
|
||||
|
||||
data[0] = '\0';
|
||||
|
||||
if (buf->size == 0 || buf->asize <= 0)
|
||||
return;
|
||||
|
||||
copylen = buf->size;
|
||||
if (copylen > datasize - 1)
|
||||
copylen = datasize - 1;
|
||||
memmove(data, buf->ptr, copylen);
|
||||
data[copylen] = '\0';
|
||||
void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b) {
|
||||
cmark_strbuf t = *buf_a;
|
||||
*buf_a = *buf_b;
|
||||
*buf_b = t;
|
||||
}
|
||||
|
||||
void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b)
|
||||
{
|
||||
cmark_strbuf t = *buf_a;
|
||||
*buf_a = *buf_b;
|
||||
*buf_b = t;
|
||||
unsigned char *cmark_strbuf_detach(cmark_strbuf *buf) {
|
||||
unsigned char *data = buf->ptr;
|
||||
|
||||
if (buf->asize == 0) {
|
||||
/* return an empty string */
|
||||
return (unsigned char *)calloc(1, 1);
|
||||
}
|
||||
|
||||
cmark_strbuf_init(buf, 0);
|
||||
return data;
|
||||
}
|
||||
|
||||
unsigned char *cmark_strbuf_detach(cmark_strbuf *buf)
|
||||
{
|
||||
unsigned char *data = buf->ptr;
|
||||
|
||||
if (buf->asize == 0) {
|
||||
/* return an empty string */
|
||||
return (unsigned char *)calloc(1, 1);
|
||||
}
|
||||
|
||||
cmark_strbuf_init(buf, 0);
|
||||
return data;
|
||||
int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b) {
|
||||
int result = memcmp(a->ptr, b->ptr, MIN(a->size, b->size));
|
||||
return (result != 0) ? result
|
||||
: (a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0;
|
||||
}
|
||||
|
||||
int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b)
|
||||
{
|
||||
int result = memcmp(a->ptr, b->ptr, MIN(a->size, b->size));
|
||||
return (result != 0) ? result :
|
||||
(a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0;
|
||||
bufsize_t cmark_strbuf_strchr(const cmark_strbuf *buf, int c, bufsize_t pos) {
|
||||
if (pos >= buf->size)
|
||||
return -1;
|
||||
if (pos < 0)
|
||||
pos = 0;
|
||||
|
||||
const unsigned char *p =
|
||||
(unsigned char *)memchr(buf->ptr + pos, c, buf->size - pos);
|
||||
if (!p)
|
||||
return -1;
|
||||
|
||||
return (bufsize_t)(p - (const unsigned char *)buf->ptr);
|
||||
}
|
||||
|
||||
bufsize_t cmark_strbuf_strchr(const cmark_strbuf *buf, int c, bufsize_t pos)
|
||||
{
|
||||
if (pos >= buf->size)
|
||||
return -1;
|
||||
if (pos < 0)
|
||||
pos = 0;
|
||||
bufsize_t cmark_strbuf_strrchr(const cmark_strbuf *buf, int c, bufsize_t pos) {
|
||||
if (pos < 0 || buf->size == 0)
|
||||
return -1;
|
||||
if (pos >= buf->size)
|
||||
pos = buf->size - 1;
|
||||
|
||||
const unsigned char *p = (unsigned char *)memchr(buf->ptr + pos, c, buf->size - pos);
|
||||
if (!p)
|
||||
return -1;
|
||||
for (bufsize_t i = pos; i >= 0; i--) {
|
||||
if (buf->ptr[i] == (unsigned char)c)
|
||||
return i;
|
||||
}
|
||||
|
||||
return (bufsize_t)(p - (const unsigned char *)buf->ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bufsize_t cmark_strbuf_strrchr(const cmark_strbuf *buf, int c, bufsize_t pos)
|
||||
{
|
||||
if (pos < 0 || buf->size == 0)
|
||||
return -1;
|
||||
if (pos >= buf->size)
|
||||
pos = buf->size - 1;
|
||||
void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len) {
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
|
||||
for (bufsize_t i = pos; i >= 0; i--) {
|
||||
if (buf->ptr[i] == (unsigned char) c)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
if (len < buf->size) {
|
||||
buf->size = len;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len)
|
||||
{
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n) {
|
||||
if (n > 0) {
|
||||
if (n > buf->size)
|
||||
n = buf->size;
|
||||
buf->size = buf->size - n;
|
||||
if (buf->size)
|
||||
memmove(buf->ptr, buf->ptr + n, buf->size);
|
||||
|
||||
if (len < buf->size) {
|
||||
buf->size = len;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n)
|
||||
{
|
||||
if (n > 0) {
|
||||
if (n > buf->size)
|
||||
n = buf->size;
|
||||
buf->size = buf->size - n;
|
||||
if (buf->size)
|
||||
memmove(buf->ptr, buf->ptr + n, buf->size);
|
||||
void cmark_strbuf_rtrim(cmark_strbuf *buf) {
|
||||
if (!buf->size)
|
||||
return;
|
||||
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
while (buf->size > 0) {
|
||||
if (!cmark_isspace(buf->ptr[buf->size - 1]))
|
||||
break;
|
||||
|
||||
buf->size--;
|
||||
}
|
||||
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
|
||||
void cmark_strbuf_rtrim(cmark_strbuf *buf)
|
||||
{
|
||||
if (!buf->size)
|
||||
return;
|
||||
void cmark_strbuf_trim(cmark_strbuf *buf) {
|
||||
bufsize_t i = 0;
|
||||
|
||||
while (buf->size > 0) {
|
||||
if (!cmark_isspace(buf->ptr[buf->size - 1]))
|
||||
break;
|
||||
if (!buf->size)
|
||||
return;
|
||||
|
||||
buf->size--;
|
||||
}
|
||||
while (i < buf->size && cmark_isspace(buf->ptr[i]))
|
||||
i++;
|
||||
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
cmark_strbuf_drop(buf, i);
|
||||
|
||||
void cmark_strbuf_trim(cmark_strbuf *buf)
|
||||
{
|
||||
bufsize_t i = 0;
|
||||
|
||||
if (!buf->size)
|
||||
return;
|
||||
|
||||
while (i < buf->size && cmark_isspace(buf->ptr[i]))
|
||||
i++;
|
||||
|
||||
cmark_strbuf_drop(buf, i);
|
||||
|
||||
cmark_strbuf_rtrim(buf);
|
||||
cmark_strbuf_rtrim(buf);
|
||||
}
|
||||
|
||||
// Destructively modify string, collapsing consecutive
|
||||
// space and newline characters into a single space.
|
||||
void cmark_strbuf_normalize_whitespace(cmark_strbuf *s)
|
||||
{
|
||||
bool last_char_was_space = false;
|
||||
bufsize_t r, w;
|
||||
void cmark_strbuf_normalize_whitespace(cmark_strbuf *s) {
|
||||
bool last_char_was_space = false;
|
||||
bufsize_t r, w;
|
||||
|
||||
for (r = 0, w = 0; r < s->size; ++r) {
|
||||
switch (s->ptr[r]) {
|
||||
case ' ':
|
||||
case '\n':
|
||||
if (last_char_was_space)
|
||||
break;
|
||||
for (r = 0, w = 0; r < s->size; ++r) {
|
||||
switch (s->ptr[r]) {
|
||||
case ' ':
|
||||
case '\n':
|
||||
if (last_char_was_space)
|
||||
break;
|
||||
|
||||
s->ptr[w++] = ' ';
|
||||
last_char_was_space = true;
|
||||
break;
|
||||
s->ptr[w++] = ' ';
|
||||
last_char_was_space = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
s->ptr[w++] = s->ptr[r];
|
||||
last_char_was_space = false;
|
||||
}
|
||||
}
|
||||
default:
|
||||
s->ptr[w++] = s->ptr[r];
|
||||
last_char_was_space = false;
|
||||
}
|
||||
}
|
||||
|
||||
cmark_strbuf_truncate(s, w);
|
||||
cmark_strbuf_truncate(s, w);
|
||||
}
|
||||
|
||||
// Destructively unescape a string: remove backslashes before punctuation chars.
|
||||
extern void cmark_strbuf_unescape(cmark_strbuf *buf)
|
||||
{
|
||||
bufsize_t r, w;
|
||||
extern void cmark_strbuf_unescape(cmark_strbuf *buf) {
|
||||
bufsize_t r, w;
|
||||
|
||||
for (r = 0, w = 0; r < buf->size; ++r) {
|
||||
if (buf->ptr[r] == '\\' && cmark_ispunct(buf->ptr[r + 1]))
|
||||
r++;
|
||||
for (r = 0, w = 0; r < buf->size; ++r) {
|
||||
if (buf->ptr[r] == '\\' && cmark_ispunct(buf->ptr[r + 1]))
|
||||
r++;
|
||||
|
||||
buf->ptr[w++] = buf->ptr[r];
|
||||
}
|
||||
buf->ptr[w++] = buf->ptr[r];
|
||||
}
|
||||
|
||||
cmark_strbuf_truncate(buf, w);
|
||||
cmark_strbuf_truncate(buf, w);
|
||||
}
|
||||
|
|
37
src/buffer.h
37
src/buffer.h
|
@ -14,13 +14,14 @@ extern "C" {
|
|||
typedef int bufsize_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned char *ptr;
|
||||
bufsize_t asize, size;
|
||||
unsigned char *ptr;
|
||||
bufsize_t asize, size;
|
||||
} cmark_strbuf;
|
||||
|
||||
extern unsigned char cmark_strbuf__initbuf[];
|
||||
|
||||
#define GH_BUF_INIT { cmark_strbuf__initbuf, 0, 0 }
|
||||
#define GH_BUF_INIT \
|
||||
{ cmark_strbuf__initbuf, 0, 0 }
|
||||
#define BUFSIZE_MAX INT_MAX
|
||||
|
||||
/**
|
||||
|
@ -44,19 +45,21 @@ bufsize_t cmark_strbuf_len(const cmark_strbuf *buf);
|
|||
int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b);
|
||||
|
||||
unsigned char *cmark_strbuf_detach(cmark_strbuf *buf);
|
||||
void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize, const cmark_strbuf *buf);
|
||||
void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize,
|
||||
const cmark_strbuf *buf);
|
||||
|
||||
static inline const char *cmark_strbuf_cstr(const cmark_strbuf *buf)
|
||||
{
|
||||
return (char *)buf->ptr;
|
||||
static inline const char *cmark_strbuf_cstr(const cmark_strbuf *buf) {
|
||||
return (char *)buf->ptr;
|
||||
}
|
||||
|
||||
#define cmark_strbuf_at(buf, n) ((buf)->ptr[n])
|
||||
|
||||
void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data, bufsize_t len);
|
||||
void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data,
|
||||
bufsize_t len);
|
||||
void cmark_strbuf_sets(cmark_strbuf *buf, const char *string);
|
||||
void cmark_strbuf_putc(cmark_strbuf *buf, int c);
|
||||
void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data, bufsize_t len);
|
||||
void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
|
||||
bufsize_t len);
|
||||
void cmark_strbuf_puts(cmark_strbuf *buf, const char *string);
|
||||
void cmark_strbuf_clear(cmark_strbuf *buf);
|
||||
|
||||
|
@ -72,17 +75,15 @@ void cmark_strbuf_unescape(cmark_strbuf *s);
|
|||
/* Print error and abort. */
|
||||
void cmark_strbuf_overflow_err(void);
|
||||
|
||||
static inline bufsize_t
|
||||
cmark_strbuf_check_bufsize(size_t size) {
|
||||
if (size > BUFSIZE_MAX) {
|
||||
cmark_strbuf_overflow_err();
|
||||
}
|
||||
return (bufsize_t)size;
|
||||
static inline bufsize_t cmark_strbuf_check_bufsize(size_t size) {
|
||||
if (size > BUFSIZE_MAX) {
|
||||
cmark_strbuf_overflow_err();
|
||||
}
|
||||
return (bufsize_t)size;
|
||||
}
|
||||
|
||||
static inline bufsize_t
|
||||
cmark_strbuf_safe_strlen(const char *str) {
|
||||
return cmark_strbuf_check_bufsize(strlen(str));
|
||||
static inline bufsize_t cmark_strbuf_safe_strlen(const char *str) {
|
||||
return cmark_strbuf_check_bufsize(strlen(str));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
154
src/chunk.h
154
src/chunk.h
|
@ -7,115 +7,109 @@
|
|||
#include "cmark_ctype.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#define CMARK_CHUNK_EMPTY { NULL, 0, 0 }
|
||||
#define CMARK_CHUNK_EMPTY \
|
||||
{ NULL, 0, 0 }
|
||||
|
||||
typedef struct {
|
||||
unsigned char *data;
|
||||
bufsize_t len;
|
||||
bufsize_t alloc; // also implies a NULL-terminated string
|
||||
unsigned char *data;
|
||||
bufsize_t len;
|
||||
bufsize_t alloc; // also implies a NULL-terminated string
|
||||
} cmark_chunk;
|
||||
|
||||
static inline void cmark_chunk_free(cmark_chunk *c)
|
||||
{
|
||||
if (c->alloc)
|
||||
free(c->data);
|
||||
static inline void cmark_chunk_free(cmark_chunk *c) {
|
||||
if (c->alloc)
|
||||
free(c->data);
|
||||
|
||||
c->data = NULL;
|
||||
c->alloc = 0;
|
||||
c->len = 0;
|
||||
c->data = NULL;
|
||||
c->alloc = 0;
|
||||
c->len = 0;
|
||||
}
|
||||
|
||||
static inline void cmark_chunk_ltrim(cmark_chunk *c)
|
||||
{
|
||||
assert(!c->alloc);
|
||||
static inline void cmark_chunk_ltrim(cmark_chunk *c) {
|
||||
assert(!c->alloc);
|
||||
|
||||
while (c->len && cmark_isspace(c->data[0])) {
|
||||
c->data++;
|
||||
c->len--;
|
||||
}
|
||||
while (c->len && cmark_isspace(c->data[0])) {
|
||||
c->data++;
|
||||
c->len--;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cmark_chunk_rtrim(cmark_chunk *c)
|
||||
{
|
||||
while (c->len > 0) {
|
||||
if (!cmark_isspace(c->data[c->len - 1]))
|
||||
break;
|
||||
static inline void cmark_chunk_rtrim(cmark_chunk *c) {
|
||||
while (c->len > 0) {
|
||||
if (!cmark_isspace(c->data[c->len - 1]))
|
||||
break;
|
||||
|
||||
c->len--;
|
||||
}
|
||||
c->len--;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cmark_chunk_trim(cmark_chunk *c)
|
||||
{
|
||||
cmark_chunk_ltrim(c);
|
||||
cmark_chunk_rtrim(c);
|
||||
static inline void cmark_chunk_trim(cmark_chunk *c) {
|
||||
cmark_chunk_ltrim(c);
|
||||
cmark_chunk_rtrim(c);
|
||||
}
|
||||
|
||||
static inline bufsize_t cmark_chunk_strchr(cmark_chunk *ch, int c, bufsize_t offset)
|
||||
{
|
||||
const unsigned char *p = (unsigned char *)memchr(ch->data + offset, c, ch->len - offset);
|
||||
return p ? (bufsize_t)(p - ch->data) : ch->len;
|
||||
static inline bufsize_t cmark_chunk_strchr(cmark_chunk *ch, int c,
|
||||
bufsize_t offset) {
|
||||
const unsigned char *p =
|
||||
(unsigned char *)memchr(ch->data + offset, c, ch->len - offset);
|
||||
return p ? (bufsize_t)(p - ch->data) : ch->len;
|
||||
}
|
||||
|
||||
static inline const char *cmark_chunk_to_cstr(cmark_chunk *c)
|
||||
{
|
||||
unsigned char *str;
|
||||
static inline const char *cmark_chunk_to_cstr(cmark_chunk *c) {
|
||||
unsigned char *str;
|
||||
|
||||
if (c->alloc) {
|
||||
return (char *)c->data;
|
||||
}
|
||||
str = (unsigned char *)malloc(c->len + 1);
|
||||
if(str != NULL) {
|
||||
if(c->len > 0) {
|
||||
memcpy(str, c->data, c->len);
|
||||
}
|
||||
str[c->len] = 0;
|
||||
}
|
||||
c->data = str;
|
||||
c->alloc = 1;
|
||||
if (c->alloc) {
|
||||
return (char *)c->data;
|
||||
}
|
||||
str = (unsigned char *)malloc(c->len + 1);
|
||||
if (str != NULL) {
|
||||
if (c->len > 0) {
|
||||
memcpy(str, c->data, c->len);
|
||||
}
|
||||
str[c->len] = 0;
|
||||
}
|
||||
c->data = str;
|
||||
c->alloc = 1;
|
||||
|
||||
return (char *)str;
|
||||
return (char *)str;
|
||||
}
|
||||
|
||||
static inline void cmark_chunk_set_cstr(cmark_chunk *c, const char *str)
|
||||
{
|
||||
if (c->alloc) {
|
||||
free(c->data);
|
||||
}
|
||||
if (str == NULL) {
|
||||
c->len = 0;
|
||||
c->data = NULL;
|
||||
c->alloc = 0;
|
||||
} else {
|
||||
c->len = cmark_strbuf_safe_strlen(str);
|
||||
c->data = (unsigned char *)malloc(c->len + 1);
|
||||
c->alloc = 1;
|
||||
memcpy(c->data, str, c->len + 1);
|
||||
}
|
||||
static inline void cmark_chunk_set_cstr(cmark_chunk *c, const char *str) {
|
||||
if (c->alloc) {
|
||||
free(c->data);
|
||||
}
|
||||
if (str == NULL) {
|
||||
c->len = 0;
|
||||
c->data = NULL;
|
||||
c->alloc = 0;
|
||||
} else {
|
||||
c->len = cmark_strbuf_safe_strlen(str);
|
||||
c->data = (unsigned char *)malloc(c->len + 1);
|
||||
c->alloc = 1;
|
||||
memcpy(c->data, str, c->len + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static inline cmark_chunk cmark_chunk_literal(const char *data)
|
||||
{
|
||||
bufsize_t len = data ? cmark_strbuf_safe_strlen(data) : 0;
|
||||
cmark_chunk c = {(unsigned char *)data, len, 0};
|
||||
return c;
|
||||
static inline cmark_chunk cmark_chunk_literal(const char *data) {
|
||||
bufsize_t len = data ? cmark_strbuf_safe_strlen(data) : 0;
|
||||
cmark_chunk c = {(unsigned char *)data, len, 0};
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline cmark_chunk cmark_chunk_dup(const cmark_chunk *ch, bufsize_t pos, bufsize_t len)
|
||||
{
|
||||
cmark_chunk c = {ch->data + pos, len, 0};
|
||||
return c;
|
||||
static inline cmark_chunk cmark_chunk_dup(const cmark_chunk *ch, bufsize_t pos,
|
||||
bufsize_t len) {
|
||||
cmark_chunk c = {ch->data + pos, len, 0};
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline cmark_chunk cmark_chunk_buf_detach(cmark_strbuf *buf)
|
||||
{
|
||||
cmark_chunk c;
|
||||
static inline cmark_chunk cmark_chunk_buf_detach(cmark_strbuf *buf) {
|
||||
cmark_chunk c;
|
||||
|
||||
c.len = buf->size;
|
||||
c.data = cmark_strbuf_detach(buf);
|
||||
c.alloc = 1;
|
||||
c.len = buf->size;
|
||||
c.data = cmark_strbuf_detach(buf);
|
||||
c.alloc = 1;
|
||||
|
||||
return c;
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
36
src/cmark.c
36
src/cmark.c
|
@ -6,26 +6,18 @@
|
|||
#include "cmark.h"
|
||||
#include "buffer.h"
|
||||
|
||||
int cmark_version()
|
||||
{
|
||||
return CMARK_VERSION;
|
||||
int cmark_version() { return CMARK_VERSION; }
|
||||
|
||||
const char *cmark_version_string() { return CMARK_VERSION_STRING; }
|
||||
|
||||
char *cmark_markdown_to_html(const char *text, size_t len, int options) {
|
||||
cmark_node *doc;
|
||||
char *result;
|
||||
|
||||
doc = cmark_parse_document(text, len, options);
|
||||
|
||||
result = cmark_render_html(doc, options);
|
||||
cmark_node_free(doc);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const char *cmark_version_string()
|
||||
{
|
||||
return CMARK_VERSION_STRING;
|
||||
}
|
||||
|
||||
char *cmark_markdown_to_html(const char *text, size_t len, int options)
|
||||
{
|
||||
cmark_node *doc;
|
||||
char *result;
|
||||
|
||||
doc = cmark_parse_document(text, len, options);
|
||||
|
||||
result = cmark_render_html(doc, options);
|
||||
cmark_node_free(doc);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
264
src/cmark.h
264
src/cmark.h
|
@ -30,49 +30,48 @@ char *cmark_markdown_to_html(const char *text, size_t len, int options);
|
|||
*/
|
||||
|
||||
typedef enum {
|
||||
/* Error status */
|
||||
CMARK_NODE_NONE,
|
||||
/* Error status */
|
||||
CMARK_NODE_NONE,
|
||||
|
||||
/* Block */
|
||||
CMARK_NODE_DOCUMENT,
|
||||
CMARK_NODE_BLOCK_QUOTE,
|
||||
CMARK_NODE_LIST,
|
||||
CMARK_NODE_ITEM,
|
||||
CMARK_NODE_CODE_BLOCK,
|
||||
CMARK_NODE_HTML,
|
||||
CMARK_NODE_PARAGRAPH,
|
||||
CMARK_NODE_HEADER,
|
||||
CMARK_NODE_HRULE,
|
||||
/* Block */
|
||||
CMARK_NODE_DOCUMENT,
|
||||
CMARK_NODE_BLOCK_QUOTE,
|
||||
CMARK_NODE_LIST,
|
||||
CMARK_NODE_ITEM,
|
||||
CMARK_NODE_CODE_BLOCK,
|
||||
CMARK_NODE_HTML,
|
||||
CMARK_NODE_PARAGRAPH,
|
||||
CMARK_NODE_HEADER,
|
||||
CMARK_NODE_HRULE,
|
||||
|
||||
CMARK_NODE_FIRST_BLOCK = CMARK_NODE_DOCUMENT,
|
||||
CMARK_NODE_LAST_BLOCK = CMARK_NODE_HRULE,
|
||||
CMARK_NODE_FIRST_BLOCK = CMARK_NODE_DOCUMENT,
|
||||
CMARK_NODE_LAST_BLOCK = CMARK_NODE_HRULE,
|
||||
|
||||
/* Inline */
|
||||
CMARK_NODE_TEXT,
|
||||
CMARK_NODE_SOFTBREAK,
|
||||
CMARK_NODE_LINEBREAK,
|
||||
CMARK_NODE_CODE,
|
||||
CMARK_NODE_INLINE_HTML,
|
||||
CMARK_NODE_EMPH,
|
||||
CMARK_NODE_STRONG,
|
||||
CMARK_NODE_LINK,
|
||||
CMARK_NODE_IMAGE,
|
||||
/* Inline */
|
||||
CMARK_NODE_TEXT,
|
||||
CMARK_NODE_SOFTBREAK,
|
||||
CMARK_NODE_LINEBREAK,
|
||||
CMARK_NODE_CODE,
|
||||
CMARK_NODE_INLINE_HTML,
|
||||
CMARK_NODE_EMPH,
|
||||
CMARK_NODE_STRONG,
|
||||
CMARK_NODE_LINK,
|
||||
CMARK_NODE_IMAGE,
|
||||
|
||||
CMARK_NODE_FIRST_INLINE = CMARK_NODE_TEXT,
|
||||
CMARK_NODE_LAST_INLINE = CMARK_NODE_IMAGE,
|
||||
CMARK_NODE_FIRST_INLINE = CMARK_NODE_TEXT,
|
||||
CMARK_NODE_LAST_INLINE = CMARK_NODE_IMAGE,
|
||||
} cmark_node_type;
|
||||
|
||||
typedef enum {
|
||||
CMARK_NO_LIST,
|
||||
CMARK_BULLET_LIST,
|
||||
CMARK_ORDERED_LIST
|
||||
} cmark_list_type;
|
||||
|
||||
typedef enum {
|
||||
CMARK_NO_LIST,
|
||||
CMARK_BULLET_LIST,
|
||||
CMARK_ORDERED_LIST
|
||||
} cmark_list_type;
|
||||
|
||||
typedef enum {
|
||||
CMARK_NO_DELIM,
|
||||
CMARK_PERIOD_DELIM,
|
||||
CMARK_PAREN_DELIM
|
||||
CMARK_NO_DELIM,
|
||||
CMARK_PERIOD_DELIM,
|
||||
CMARK_PAREN_DELIM
|
||||
} cmark_delim_type;
|
||||
|
||||
typedef struct cmark_node cmark_node;
|
||||
|
@ -80,10 +79,10 @@ typedef struct cmark_parser cmark_parser;
|
|||
typedef struct cmark_iter cmark_iter;
|
||||
|
||||
typedef enum {
|
||||
CMARK_EVENT_NONE,
|
||||
CMARK_EVENT_DONE,
|
||||
CMARK_EVENT_ENTER,
|
||||
CMARK_EVENT_EXIT
|
||||
CMARK_EVENT_NONE,
|
||||
CMARK_EVENT_DONE,
|
||||
CMARK_EVENT_ENTER,
|
||||
CMARK_EVENT_EXIT
|
||||
} cmark_event_type;
|
||||
|
||||
/**
|
||||
|
@ -94,13 +93,11 @@ typedef enum {
|
|||
* other required properties, which it is the caller's responsibility
|
||||
* to assign.
|
||||
*/
|
||||
CMARK_EXPORT cmark_node*
|
||||
cmark_node_new(cmark_node_type type);
|
||||
CMARK_EXPORT cmark_node *cmark_node_new(cmark_node_type type);
|
||||
|
||||
/** Frees the memory allocated for a node.
|
||||
*/
|
||||
CMARK_EXPORT void
|
||||
cmark_node_free(cmark_node *node);
|
||||
CMARK_EXPORT void cmark_node_free(cmark_node *node);
|
||||
|
||||
/**
|
||||
* ## Tree Traversal
|
||||
|
@ -109,29 +106,24 @@ cmark_node_free(cmark_node *node);
|
|||
/** Returns the next node in the sequence after 'node', or NULL if
|
||||
* there is none.
|
||||
*/
|
||||
CMARK_EXPORT cmark_node*
|
||||
cmark_node_next(cmark_node *node);
|
||||
CMARK_EXPORT cmark_node *cmark_node_next(cmark_node *node);
|
||||
|
||||
/** Returns the previous node in the sequence after 'node', or NULL if
|
||||
* there is none.
|
||||
*/
|
||||
CMARK_EXPORT cmark_node*
|
||||
cmark_node_previous(cmark_node *node);
|
||||
CMARK_EXPORT cmark_node *cmark_node_previous(cmark_node *node);
|
||||
|
||||
/** Returns the parent of 'node', or NULL if there is none.
|
||||
*/
|
||||
CMARK_EXPORT cmark_node*
|
||||
cmark_node_parent(cmark_node *node);
|
||||
CMARK_EXPORT cmark_node *cmark_node_parent(cmark_node *node);
|
||||
|
||||
/** Returns the first child of 'node', or NULL if 'node' has no children.
|
||||
*/
|
||||
CMARK_EXPORT cmark_node*
|
||||
cmark_node_first_child(cmark_node *node);
|
||||
CMARK_EXPORT cmark_node *cmark_node_first_child(cmark_node *node);
|
||||
|
||||
/** Returns the last child of 'node', or NULL if 'node' has no children.
|
||||
*/
|
||||
CMARK_EXPORT cmark_node*
|
||||
cmark_node_last_child(cmark_node *node);
|
||||
CMARK_EXPORT cmark_node *cmark_node_last_child(cmark_node *node);
|
||||
|
||||
/**
|
||||
* ## Iterator
|
||||
|
@ -182,48 +174,41 @@ cmark_node_last_child(cmark_node *node);
|
|||
* type are undefined until `cmark_iter_next` is called for the first time.
|
||||
*/
|
||||
CMARK_EXPORT
|
||||
cmark_iter*
|
||||
cmark_iter_new(cmark_node *root);
|
||||
cmark_iter *cmark_iter_new(cmark_node *root);
|
||||
|
||||
/** Frees the memory allocated for an iterator.
|
||||
*/
|
||||
CMARK_EXPORT
|
||||
void
|
||||
cmark_iter_free(cmark_iter *iter);
|
||||
void cmark_iter_free(cmark_iter *iter);
|
||||
|
||||
/** Advances to the next node and returns the event type (`CMARK_EVENT_ENTER`,
|
||||
* `CMARK_EVENT_EXIT` or `CMARK_EVENT_DONE`).
|
||||
*/
|
||||
CMARK_EXPORT
|
||||
cmark_event_type
|
||||
cmark_iter_next(cmark_iter *iter);
|
||||
cmark_event_type cmark_iter_next(cmark_iter *iter);
|
||||
|
||||
/** Returns the current node.
|
||||
*/
|
||||
CMARK_EXPORT
|
||||
cmark_node*
|
||||
cmark_iter_get_node(cmark_iter *iter);
|
||||
cmark_node *cmark_iter_get_node(cmark_iter *iter);
|
||||
|
||||
/** Returns the current event type.
|
||||
*/
|
||||
CMARK_EXPORT
|
||||
cmark_event_type
|
||||
cmark_iter_get_event_type(cmark_iter *iter);
|
||||
cmark_event_type cmark_iter_get_event_type(cmark_iter *iter);
|
||||
|
||||
/** Returns the root node.
|
||||
*/
|
||||
CMARK_EXPORT
|
||||
cmark_node*
|
||||
cmark_iter_get_root(cmark_iter *iter);
|
||||
cmark_node *cmark_iter_get_root(cmark_iter *iter);
|
||||
|
||||
/** Resets the iterator so that the current node is 'current' and
|
||||
* the event type is 'event_type'. The new current node must be a
|
||||
* descendant of the root node or the root node itself.
|
||||
*/
|
||||
CMARK_EXPORT
|
||||
void
|
||||
cmark_iter_reset(cmark_iter *iter, cmark_node *current,
|
||||
cmark_event_type event_type);
|
||||
void cmark_iter_reset(cmark_iter *iter, cmark_node *current,
|
||||
cmark_event_type event_type);
|
||||
|
||||
/**
|
||||
* ## Accessors
|
||||
|
@ -231,144 +216,120 @@ cmark_iter_reset(cmark_iter *iter, cmark_node *current,
|
|||
|
||||
/** Returns the user data of 'node'.
|
||||
*/
|
||||
CMARK_EXPORT void*
|
||||
cmark_node_get_user_data(cmark_node *node);
|
||||
CMARK_EXPORT void *cmark_node_get_user_data(cmark_node *node);
|
||||
|
||||
/** Sets arbitrary user data for 'node'. Returns 1 on success,
|
||||
* 0 on failure.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_set_user_data(cmark_node *node, void *user_data);
|
||||
CMARK_EXPORT int cmark_node_set_user_data(cmark_node *node, void *user_data);
|
||||
|
||||
/** Returns the type of 'node', or `CMARK_NODE_NONE` on error.
|
||||
*/
|
||||
CMARK_EXPORT cmark_node_type
|
||||
cmark_node_get_type(cmark_node *node);
|
||||
CMARK_EXPORT cmark_node_type cmark_node_get_type(cmark_node *node);
|
||||
|
||||
/** Like 'cmark_node_get_type', but returns a string representation
|
||||
of the type, or `"<unknown>"`.
|
||||
*/
|
||||
CMARK_EXPORT
|
||||
const char*
|
||||
cmark_node_get_type_string(cmark_node *node);
|
||||
const char *cmark_node_get_type_string(cmark_node *node);
|
||||
|
||||
/** Returns the string contents of 'node', or NULL if none.
|
||||
*/
|
||||
CMARK_EXPORT const char*
|
||||
cmark_node_get_literal(cmark_node *node);
|
||||
CMARK_EXPORT const char *cmark_node_get_literal(cmark_node *node);
|
||||
|
||||
/** Sets the string contents of 'node'. Returns 1 on success,
|
||||
* 0 on failure.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_set_literal(cmark_node *node, const char *content);
|
||||
CMARK_EXPORT int cmark_node_set_literal(cmark_node *node, const char *content);
|
||||
|
||||
/** Returns the header level of 'node', or 0 if 'node' is not a header.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_get_header_level(cmark_node *node);
|
||||
CMARK_EXPORT int cmark_node_get_header_level(cmark_node *node);
|
||||
|
||||
/** Sets the header level of 'node', returning 1 on success and 0 on error.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_set_header_level(cmark_node *node, int level);
|
||||
CMARK_EXPORT int cmark_node_set_header_level(cmark_node *node, int level);
|
||||
|
||||
/** Returns the list type of 'node', or `CMARK_NO_LIST` if 'node'
|
||||
* is not a list.
|
||||
*/
|
||||
CMARK_EXPORT cmark_list_type
|
||||
cmark_node_get_list_type(cmark_node *node);
|
||||
CMARK_EXPORT cmark_list_type cmark_node_get_list_type(cmark_node *node);
|
||||
|
||||
/** Sets the list type of 'node', returning 1 on success and 0 on error.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_set_list_type(cmark_node *node, cmark_list_type type);
|
||||
CMARK_EXPORT int cmark_node_set_list_type(cmark_node *node,
|
||||
cmark_list_type type);
|
||||
|
||||
/** Returns the list delimiter type of 'node', or `CMARK_NO_DELIM` if 'node'
|
||||
* is not a list.
|
||||
*/
|
||||
CMARK_EXPORT cmark_delim_type
|
||||
cmark_node_get_list_delim(cmark_node *node);
|
||||
CMARK_EXPORT cmark_delim_type cmark_node_get_list_delim(cmark_node *node);
|
||||
|
||||
/** Sets the list delimiter type of 'node', returning 1 on success and 0
|
||||
* on error.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_set_list_delim(cmark_node *node, cmark_delim_type delim);
|
||||
CMARK_EXPORT int cmark_node_set_list_delim(cmark_node *node,
|
||||
cmark_delim_type delim);
|
||||
|
||||
/** Returns starting number of 'node', if it is an ordered list, otherwise 0.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_get_list_start(cmark_node *node);
|
||||
CMARK_EXPORT int cmark_node_get_list_start(cmark_node *node);
|
||||
|
||||
/** Sets starting number of 'node', if it is an ordered list. Returns 1
|
||||
* on success, 0 on failure.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_set_list_start(cmark_node *node, int start);
|
||||
CMARK_EXPORT int cmark_node_set_list_start(cmark_node *node, int start);
|
||||
|
||||
/** Returns 1 if 'node' is a tight list, 0 otherwise.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_get_list_tight(cmark_node *node);
|
||||
CMARK_EXPORT int cmark_node_get_list_tight(cmark_node *node);
|
||||
|
||||
/** Sets the "tightness" of a list. Returns 1 on success, 0 on failure.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_set_list_tight(cmark_node *node, int tight);
|
||||
CMARK_EXPORT int cmark_node_set_list_tight(cmark_node *node, int tight);
|
||||
|
||||
/** Returns the info string from a fenced code block, or NULL if none.
|
||||
*/
|
||||
CMARK_EXPORT const char*
|
||||
cmark_node_get_fence_info(cmark_node *node);
|
||||
CMARK_EXPORT const char *cmark_node_get_fence_info(cmark_node *node);
|
||||
|
||||
/** Sets the info string in a fenced code block, returning 1 on
|
||||
* success and 0 on failure.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_set_fence_info(cmark_node *node, const char *info);
|
||||
CMARK_EXPORT int cmark_node_set_fence_info(cmark_node *node, const char *info);
|
||||
|
||||
/** Gets the URL of a link or image 'node', or NULL if none.
|
||||
*/
|
||||
CMARK_EXPORT const char*
|
||||
cmark_node_get_url(cmark_node *node);
|
||||
CMARK_EXPORT const char *cmark_node_get_url(cmark_node *node);
|
||||
|
||||
/** Sets the URL of a link or image 'node'. Returns 1 on success,
|
||||
* 0 on failure.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_set_url(cmark_node *node, const char *url);
|
||||
CMARK_EXPORT int cmark_node_set_url(cmark_node *node, const char *url);
|
||||
|
||||
/** Gets the title of a link or image 'node', or NULL if none.
|
||||
*/
|
||||
CMARK_EXPORT const char*
|
||||
cmark_node_get_title(cmark_node *node);
|
||||
CMARK_EXPORT const char *cmark_node_get_title(cmark_node *node);
|
||||
|
||||
/** Sets the title of a link or image 'node'. Returns 1 on success,
|
||||
* 0 on failure.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_set_title(cmark_node *node, const char *title);
|
||||
CMARK_EXPORT int cmark_node_set_title(cmark_node *node, const char *title);
|
||||
|
||||
/** Returns the line on which 'node' begins.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_get_start_line(cmark_node *node);
|
||||
CMARK_EXPORT int cmark_node_get_start_line(cmark_node *node);
|
||||
|
||||
/** Returns the column at which 'node' begins.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_get_start_column(cmark_node *node);
|
||||
CMARK_EXPORT int cmark_node_get_start_column(cmark_node *node);
|
||||
|
||||
/** Returns the line on which 'node' ends.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_get_end_line(cmark_node *node);
|
||||
CMARK_EXPORT int cmark_node_get_end_line(cmark_node *node);
|
||||
|
||||
/** Returns the column at which 'node' ends.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_get_end_column(cmark_node *node);
|
||||
CMARK_EXPORT int cmark_node_get_end_column(cmark_node *node);
|
||||
|
||||
/**
|
||||
* ## Tree Manipulation
|
||||
|
@ -377,35 +338,30 @@ cmark_node_get_end_column(cmark_node *node);
|
|||
/** Unlinks a 'node', removing it from the tree, but not freeing its
|
||||
* memory. (Use 'cmark_node_free' for that.)
|
||||
*/
|
||||
CMARK_EXPORT void
|
||||
cmark_node_unlink(cmark_node *node);
|
||||
CMARK_EXPORT void cmark_node_unlink(cmark_node *node);
|
||||
|
||||
/** Inserts 'sibling' before 'node'. Returns 1 on success, 0 on failure.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_insert_before(cmark_node *node, cmark_node *sibling);
|
||||
CMARK_EXPORT int cmark_node_insert_before(cmark_node *node,
|
||||
cmark_node *sibling);
|
||||
|
||||
/** Inserts 'sibling' after 'node'. Returns 1 on success, 0 on failure.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_insert_after(cmark_node *node, cmark_node *sibling);
|
||||
CMARK_EXPORT int cmark_node_insert_after(cmark_node *node, cmark_node *sibling);
|
||||
|
||||
/** Adds 'child' to the beginning of the children of 'node'.
|
||||
* Returns 1 on success, 0 on failure.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_prepend_child(cmark_node *node, cmark_node *child);
|
||||
CMARK_EXPORT int cmark_node_prepend_child(cmark_node *node, cmark_node *child);
|
||||
|
||||
/** Adds 'child' to the end of the children of 'node'.
|
||||
* Returns 1 on success, 0 on failure.
|
||||
*/
|
||||
CMARK_EXPORT int
|
||||
cmark_node_append_child(cmark_node *node, cmark_node *child);
|
||||
CMARK_EXPORT int cmark_node_append_child(cmark_node *node, cmark_node *child);
|
||||
|
||||
/** Consolidates adjacent text nodes.
|
||||
*/
|
||||
CMARK_EXPORT void
|
||||
cmark_consolidate_text_nodes(cmark_node *root);
|
||||
CMARK_EXPORT void cmark_consolidate_text_nodes(cmark_node *root);
|
||||
|
||||
/**
|
||||
* ## Parsing
|
||||
|
@ -552,28 +508,28 @@ const char *cmark_version_string();
|
|||
*/
|
||||
|
||||
#ifndef CMARK_NO_SHORT_NAMES
|
||||
#define NODE_DOCUMENT CMARK_NODE_DOCUMENT
|
||||
#define NODE_BLOCK_QUOTE CMARK_NODE_BLOCK_QUOTE
|
||||
#define NODE_LIST CMARK_NODE_LIST
|
||||
#define NODE_ITEM CMARK_NODE_ITEM
|
||||
#define NODE_CODE_BLOCK CMARK_NODE_CODE_BLOCK
|
||||
#define NODE_HTML CMARK_NODE_HTML
|
||||
#define NODE_PARAGRAPH CMARK_NODE_PARAGRAPH
|
||||
#define NODE_HEADER CMARK_NODE_HEADER
|
||||
#define NODE_HRULE CMARK_NODE_HRULE
|
||||
#define NODE_TEXT CMARK_NODE_TEXT
|
||||
#define NODE_SOFTBREAK CMARK_NODE_SOFTBREAK
|
||||
#define NODE_LINEBREAK CMARK_NODE_LINEBREAK
|
||||
#define NODE_CODE CMARK_NODE_CODE
|
||||
#define NODE_INLINE_HTML CMARK_NODE_INLINE_HTML
|
||||
#define NODE_EMPH CMARK_NODE_EMPH
|
||||
#define NODE_STRONG CMARK_NODE_STRONG
|
||||
#define NODE_LINK CMARK_NODE_LINK
|
||||
#define NODE_IMAGE CMARK_NODE_IMAGE
|
||||
#define BULLET_LIST CMARK_BULLET_LIST
|
||||
#define ORDERED_LIST CMARK_ORDERED_LIST
|
||||
#define PERIOD_DELIM CMARK_PERIOD_DELIM
|
||||
#define PAREN_DELIM CMARK_PAREN_DELIM
|
||||
#define NODE_DOCUMENT CMARK_NODE_DOCUMENT
|
||||
#define NODE_BLOCK_QUOTE CMARK_NODE_BLOCK_QUOTE
|
||||
#define NODE_LIST CMARK_NODE_LIST
|
||||
#define NODE_ITEM CMARK_NODE_ITEM
|
||||
#define NODE_CODE_BLOCK CMARK_NODE_CODE_BLOCK
|
||||
#define NODE_HTML CMARK_NODE_HTML
|
||||
#define NODE_PARAGRAPH CMARK_NODE_PARAGRAPH
|
||||
#define NODE_HEADER CMARK_NODE_HEADER
|
||||
#define NODE_HRULE CMARK_NODE_HRULE
|
||||
#define NODE_TEXT CMARK_NODE_TEXT
|
||||
#define NODE_SOFTBREAK CMARK_NODE_SOFTBREAK
|
||||
#define NODE_LINEBREAK CMARK_NODE_LINEBREAK
|
||||
#define NODE_CODE CMARK_NODE_CODE
|
||||
#define NODE_INLINE_HTML CMARK_NODE_INLINE_HTML
|
||||
#define NODE_EMPH CMARK_NODE_EMPH
|
||||
#define NODE_STRONG CMARK_NODE_STRONG
|
||||
#define NODE_LINK CMARK_NODE_LINK
|
||||
#define NODE_IMAGE CMARK_NODE_IMAGE
|
||||
#define BULLET_LIST CMARK_BULLET_LIST
|
||||
#define ORDERED_LIST CMARK_ORDERED_LIST
|
||||
#define PERIOD_DELIM CMARK_PERIOD_DELIM
|
||||
#define PAREN_DELIM CMARK_PAREN_DELIM
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -5,49 +5,38 @@
|
|||
/** 1 = space, 2 = punct, 3 = digit, 4 = alpha, 0 = other
|
||||
*/
|
||||
static const int8_t cmark_ctype_class[256] = {
|
||||
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
||||
/* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
|
||||
/* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 2 */ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* 3 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2,
|
||||
/* 4 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
/* 5 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2,
|
||||
/* 6 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
/* 7 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0,
|
||||
/* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
||||
/* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
|
||||
/* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 2 */ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* 3 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2,
|
||||
/* 4 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
/* 5 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2,
|
||||
/* 6 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
/* 7 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0,
|
||||
/* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
/**
|
||||
* Returns 1 if c is a "whitespace" character as defined by the spec.
|
||||
*/
|
||||
int cmark_isspace(char c)
|
||||
{
|
||||
return cmark_ctype_class[(int8_t)c] == 1;
|
||||
}
|
||||
int cmark_isspace(char c) { return cmark_ctype_class[(int8_t)c] == 1; }
|
||||
|
||||
/**
|
||||
* Returns 1 if c is an ascii punctuation character.
|
||||
*/
|
||||
int cmark_ispunct(char c)
|
||||
{
|
||||
return cmark_ctype_class[(int8_t)c] == 2;
|
||||
int cmark_ispunct(char c) { return cmark_ctype_class[(int8_t)c] == 2; }
|
||||
|
||||
int cmark_isalnum(char c) {
|
||||
int8_t result;
|
||||
result = cmark_ctype_class[(int8_t)c];
|
||||
return (result == 3 || result == 4);
|
||||
}
|
||||
|
||||
int cmark_isalnum(char c)
|
||||
{
|
||||
int8_t result;
|
||||
result = cmark_ctype_class[(int8_t)c];
|
||||
return (result == 3 || result == 4);
|
||||
}
|
||||
|
||||
int cmark_isdigit(char c)
|
||||
{
|
||||
return cmark_ctype_class[(int8_t)c] == 3;
|
||||
}
|
||||
int cmark_isdigit(char c) { return cmark_ctype_class[(int8_t)c] == 3; }
|
||||
|
|
763
src/commonmark.c
763
src/commonmark.c
|
@ -20,445 +20,408 @@
|
|||
|
||||
// Functions to convert cmark_nodes to commonmark strings.
|
||||
|
||||
static inline void outc(cmark_renderer *renderer,
|
||||
cmark_escaping escape,
|
||||
int32_t c,
|
||||
unsigned char nextc)
|
||||
{
|
||||
bool needs_escaping = false;
|
||||
char encoded[20];
|
||||
static inline void outc(cmark_renderer *renderer, cmark_escaping escape,
|
||||
int32_t c, unsigned char nextc) {
|
||||
bool needs_escaping = false;
|
||||
char encoded[20];
|
||||
|
||||
needs_escaping =
|
||||
escape != LITERAL &&
|
||||
((escape == NORMAL &&
|
||||
(c == '*' || c == '_' || c == '[' || c == ']' || c == '#' ||
|
||||
c == '<' || c == '>' || c == '\\' || c == '`' || c == '!' ||
|
||||
(c == '&' && isalpha(nextc)) ||
|
||||
(c == '!' && nextc == '[') ||
|
||||
(renderer->begin_line &&
|
||||
(c == '-' || c == '+' || c == '=')) ||
|
||||
((c == '.' || c == ')') &&
|
||||
isdigit(renderer->buffer->ptr[renderer->buffer->size - 1])))) ||
|
||||
(escape == URL &&
|
||||
(c == '`' || c == '<' || c == '>' || isspace(c) ||
|
||||
c == '\\' || c == ')' || c == '(')) ||
|
||||
(escape == TITLE &&
|
||||
(c == '`' || c == '<' || c == '>' || c == '"' ||
|
||||
c == '\\')));
|
||||
needs_escaping =
|
||||
escape != LITERAL &&
|
||||
((escape == NORMAL &&
|
||||
(c == '*' || c == '_' || c == '[' || c == ']' || c == '#' || c == '<' ||
|
||||
c == '>' || c == '\\' || c == '`' || c == '!' ||
|
||||
(c == '&' && isalpha(nextc)) || (c == '!' && nextc == '[') ||
|
||||
(renderer->begin_line && (c == '-' || c == '+' || c == '=')) ||
|
||||
((c == '.' || c == ')') &&
|
||||
isdigit(renderer->buffer->ptr[renderer->buffer->size - 1])))) ||
|
||||
(escape == URL && (c == '`' || c == '<' || c == '>' || isspace(c) ||
|
||||
c == '\\' || c == ')' || c == '(')) ||
|
||||
(escape == TITLE &&
|
||||
(c == '`' || c == '<' || c == '>' || c == '"' || c == '\\')));
|
||||
|
||||
if (needs_escaping) {
|
||||
if (isspace(c)) {
|
||||
// use percent encoding for spaces
|
||||
sprintf(encoded, "%%%2x", c);
|
||||
cmark_strbuf_puts(renderer->buffer, encoded);
|
||||
renderer->column += 3;
|
||||
} else {
|
||||
cmark_render_ascii(renderer, "\\");
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
if (needs_escaping) {
|
||||
if (isspace(c)) {
|
||||
// use percent encoding for spaces
|
||||
sprintf(encoded, "%%%2x", c);
|
||||
cmark_strbuf_puts(renderer->buffer, encoded);
|
||||
renderer->column += 3;
|
||||
} else {
|
||||
cmark_render_ascii(renderer, "\\");
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
longest_backtick_sequence(const char *code)
|
||||
{
|
||||
int longest = 0;
|
||||
int current = 0;
|
||||
size_t i = 0;
|
||||
size_t code_len = safe_strlen(code);
|
||||
while (i <= code_len) {
|
||||
if (code[i] == '`') {
|
||||
current++;
|
||||
} else {
|
||||
if (current > longest) {
|
||||
longest = current;
|
||||
}
|
||||
current = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return longest;
|
||||
static int longest_backtick_sequence(const char *code) {
|
||||
int longest = 0;
|
||||
int current = 0;
|
||||
size_t i = 0;
|
||||
size_t code_len = safe_strlen(code);
|
||||
while (i <= code_len) {
|
||||
if (code[i] == '`') {
|
||||
current++;
|
||||
} else {
|
||||
if (current > longest) {
|
||||
longest = current;
|
||||
}
|
||||
current = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return longest;
|
||||
}
|
||||
|
||||
static int
|
||||
shortest_unused_backtick_sequence(const char *code)
|
||||
{
|
||||
int32_t used = 1;
|
||||
int current = 0;
|
||||
size_t i = 0;
|
||||
size_t code_len = safe_strlen(code);
|
||||
while (i <= code_len) {
|
||||
if (code[i] == '`') {
|
||||
current++;
|
||||
} else {
|
||||
if (current) {
|
||||
used |= (1 << current);
|
||||
}
|
||||
current = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// return number of first bit that is 0:
|
||||
i = 0;
|
||||
while (used & 1) {
|
||||
used = used >> 1;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
static int shortest_unused_backtick_sequence(const char *code) {
|
||||
int32_t used = 1;
|
||||
int current = 0;
|
||||
size_t i = 0;
|
||||
size_t code_len = safe_strlen(code);
|
||||
while (i <= code_len) {
|
||||
if (code[i] == '`') {
|
||||
current++;
|
||||
} else {
|
||||
if (current) {
|
||||
used |= (1 << current);
|
||||
}
|
||||
current = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// return number of first bit that is 0:
|
||||
i = 0;
|
||||
while (used & 1) {
|
||||
used = used >> 1;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_autolink(cmark_node *node)
|
||||
{
|
||||
cmark_chunk *title;
|
||||
cmark_chunk *url;
|
||||
cmark_node *link_text;
|
||||
char *realurl;
|
||||
int realurllen;
|
||||
static bool is_autolink(cmark_node *node) {
|
||||
cmark_chunk *title;
|
||||
cmark_chunk *url;
|
||||
cmark_node *link_text;
|
||||
char *realurl;
|
||||
int realurllen;
|
||||
|
||||
if (node->type != CMARK_NODE_LINK) {
|
||||
return false;
|
||||
}
|
||||
if (node->type != CMARK_NODE_LINK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
url = &node->as.link.url;
|
||||
if (url->len == 0 || scan_scheme(url, 0) == 0) {
|
||||
return false;
|
||||
}
|
||||
url = &node->as.link.url;
|
||||
if (url->len == 0 || scan_scheme(url, 0) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
title = &node->as.link.title;
|
||||
// if it has a title, we can't treat it as an autolink:
|
||||
if (title->len > 0) {
|
||||
return false;
|
||||
}
|
||||
title = &node->as.link.title;
|
||||
// if it has a title, we can't treat it as an autolink:
|
||||
if (title->len > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
link_text = node->first_child;
|
||||
cmark_consolidate_text_nodes(link_text);
|
||||
realurl = (char*)url->data;
|
||||
realurllen = url->len;
|
||||
if (strncmp(realurl, "mailto:", 7) == 0) {
|
||||
realurl += 7;
|
||||
realurllen -= 7;
|
||||
}
|
||||
return (realurllen == link_text->as.literal.len &&
|
||||
strncmp(realurl,
|
||||
(char*)link_text->as.literal.data,
|
||||
link_text->as.literal.len) == 0);
|
||||
link_text = node->first_child;
|
||||
cmark_consolidate_text_nodes(link_text);
|
||||
realurl = (char *)url->data;
|
||||
realurllen = url->len;
|
||||
if (strncmp(realurl, "mailto:", 7) == 0) {
|
||||
realurl += 7;
|
||||
realurllen -= 7;
|
||||
}
|
||||
return (realurllen == link_text->as.literal.len &&
|
||||
strncmp(realurl, (char *)link_text->as.literal.data,
|
||||
link_text->as.literal.len) == 0);
|
||||
}
|
||||
|
||||
// if node is a block node, returns node.
|
||||
// otherwise returns first block-level node that is an ancestor of node.
|
||||
static cmark_node*
|
||||
get_containing_block(cmark_node *node)
|
||||
{
|
||||
while (node &&
|
||||
(node->type < CMARK_NODE_FIRST_BLOCK ||
|
||||
node->type > CMARK_NODE_LAST_BLOCK)) {
|
||||
node = node->parent;
|
||||
}
|
||||
return node;
|
||||
static cmark_node *get_containing_block(cmark_node *node) {
|
||||
while (node && (node->type < CMARK_NODE_FIRST_BLOCK ||
|
||||
node->type > CMARK_NODE_LAST_BLOCK)) {
|
||||
node = node->parent;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static int
|
||||
S_render_node(cmark_renderer *renderer,
|
||||
cmark_node *node,
|
||||
cmark_event_type ev_type,
|
||||
int options)
|
||||
{
|
||||
cmark_node *tmp;
|
||||
int list_number;
|
||||
cmark_delim_type list_delim;
|
||||
int numticks;
|
||||
int i;
|
||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||
const char *info, *code, *title;
|
||||
size_t info_len, code_len;
|
||||
char listmarker[20];
|
||||
char *emph_delim;
|
||||
bufsize_t marker_width;
|
||||
static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
||||
cmark_event_type ev_type, int options) {
|
||||
cmark_node *tmp;
|
||||
int list_number;
|
||||
cmark_delim_type list_delim;
|
||||
int numticks;
|
||||
int i;
|
||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||
const char *info, *code, *title;
|
||||
size_t info_len, code_len;
|
||||
char listmarker[20];
|
||||
char *emph_delim;
|
||||
bufsize_t marker_width;
|
||||
|
||||
// Don't adjust tight list status til we've started the list.
|
||||
// Otherwise we loose the blank line between a paragraph and
|
||||
// a following list.
|
||||
if (!(node->type == CMARK_NODE_ITEM && node->prev == NULL &&
|
||||
entering)) {
|
||||
tmp = get_containing_block(node);
|
||||
renderer->in_tight_list_item =
|
||||
(tmp->type == CMARK_NODE_ITEM &&
|
||||
cmark_node_get_list_tight(tmp->parent)) ||
|
||||
(tmp &&
|
||||
tmp->parent &&
|
||||
tmp->parent->type == CMARK_NODE_ITEM &&
|
||||
cmark_node_get_list_tight(tmp->parent->parent));
|
||||
}
|
||||
// Don't adjust tight list status til we've started the list.
|
||||
// Otherwise we loose the blank line between a paragraph and
|
||||
// a following list.
|
||||
if (!(node->type == CMARK_NODE_ITEM && node->prev == NULL && entering)) {
|
||||
tmp = get_containing_block(node);
|
||||
renderer->in_tight_list_item =
|
||||
(tmp->type == CMARK_NODE_ITEM &&
|
||||
cmark_node_get_list_tight(tmp->parent)) ||
|
||||
(tmp && tmp->parent && tmp->parent->type == CMARK_NODE_ITEM &&
|
||||
cmark_node_get_list_tight(tmp->parent->parent));
|
||||
}
|
||||
|
||||
switch (node->type) {
|
||||
case CMARK_NODE_DOCUMENT:
|
||||
break;
|
||||
switch (node->type) {
|
||||
case CMARK_NODE_DOCUMENT:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_BLOCK_QUOTE:
|
||||
if (entering) {
|
||||
LIT("> ");
|
||||
cmark_strbuf_puts(renderer->prefix, "> ");
|
||||
} else {
|
||||
cmark_strbuf_truncate(renderer->prefix,
|
||||
renderer->prefix->size - 2);
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_BLOCK_QUOTE:
|
||||
if (entering) {
|
||||
LIT("> ");
|
||||
cmark_strbuf_puts(renderer->prefix, "> ");
|
||||
} else {
|
||||
cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 2);
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LIST:
|
||||
if (!entering && node->next &&
|
||||
(node->next->type == CMARK_NODE_CODE_BLOCK ||
|
||||
node->next->type == CMARK_NODE_LIST)) {
|
||||
// this ensures 2 blank lines after list,
|
||||
// if before code block or list:
|
||||
LIT("\n");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_LIST:
|
||||
if (!entering && node->next && (node->next->type == CMARK_NODE_CODE_BLOCK ||
|
||||
node->next->type == CMARK_NODE_LIST)) {
|
||||
// this ensures 2 blank lines after list,
|
||||
// if before code block or list:
|
||||
LIT("\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_ITEM:
|
||||
if (cmark_node_get_list_type(node->parent) ==
|
||||
CMARK_BULLET_LIST) {
|
||||
marker_width = 2;
|
||||
} else {
|
||||
list_number = cmark_node_get_list_start(node->parent);
|
||||
list_delim = cmark_node_get_list_delim(node->parent);
|
||||
tmp = node;
|
||||
while (tmp->prev) {
|
||||
tmp = tmp->prev;
|
||||
list_number += 1;
|
||||
}
|
||||
// we ensure a width of at least 4 so
|
||||
// we get nice transition from single digits
|
||||
// to double
|
||||
sprintf(listmarker,
|
||||
"%d%s%s", list_number,
|
||||
list_delim == CMARK_PAREN_DELIM ?
|
||||
")" : ".",
|
||||
list_number < 10 ? " " : " ");
|
||||
marker_width = safe_strlen(listmarker);
|
||||
}
|
||||
if (entering) {
|
||||
if (cmark_node_get_list_type(node->parent) ==
|
||||
CMARK_BULLET_LIST) {
|
||||
LIT("* ");
|
||||
cmark_strbuf_puts(renderer->prefix, " ");
|
||||
} else {
|
||||
LIT(listmarker);
|
||||
for (i = marker_width; i--;) {
|
||||
cmark_strbuf_putc(renderer->prefix, ' ');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cmark_strbuf_truncate(renderer->prefix,
|
||||
renderer->prefix->size -
|
||||
marker_width);
|
||||
CR();
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_ITEM:
|
||||
if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
|
||||
marker_width = 2;
|
||||
} else {
|
||||
list_number = cmark_node_get_list_start(node->parent);
|
||||
list_delim = cmark_node_get_list_delim(node->parent);
|
||||
tmp = node;
|
||||
while (tmp->prev) {
|
||||
tmp = tmp->prev;
|
||||
list_number += 1;
|
||||
}
|
||||
// we ensure a width of at least 4 so
|
||||
// we get nice transition from single digits
|
||||
// to double
|
||||
sprintf(listmarker, "%d%s%s", list_number,
|
||||
list_delim == CMARK_PAREN_DELIM ? ")" : ".",
|
||||
list_number < 10 ? " " : " ");
|
||||
marker_width = safe_strlen(listmarker);
|
||||
}
|
||||
if (entering) {
|
||||
if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
|
||||
LIT("* ");
|
||||
cmark_strbuf_puts(renderer->prefix, " ");
|
||||
} else {
|
||||
LIT(listmarker);
|
||||
for (i = marker_width; i--;) {
|
||||
cmark_strbuf_putc(renderer->prefix, ' ');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cmark_strbuf_truncate(renderer->prefix,
|
||||
renderer->prefix->size - marker_width);
|
||||
CR();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HEADER:
|
||||
if (entering) {
|
||||
for (int i = cmark_node_get_header_level(node); i > 0; i--) {
|
||||
LIT("#");
|
||||
}
|
||||
LIT(" ");
|
||||
renderer->no_wrap = true;
|
||||
} else {
|
||||
renderer->no_wrap = false;
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_HEADER:
|
||||
if (entering) {
|
||||
for (int i = cmark_node_get_header_level(node); i > 0; i--) {
|
||||
LIT("#");
|
||||
}
|
||||
LIT(" ");
|
||||
renderer->no_wrap = true;
|
||||
} else {
|
||||
renderer->no_wrap = false;
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CODE_BLOCK:
|
||||
BLANKLINE();
|
||||
info = cmark_node_get_fence_info(node);
|
||||
info_len = safe_strlen(info);
|
||||
code = cmark_node_get_literal(node);
|
||||
code_len = safe_strlen(code);
|
||||
// use indented form if no info, and code doesn't
|
||||
// begin or end with a blank line, and code isn't
|
||||
// first thing in a list item
|
||||
if (info_len == 0 &&
|
||||
(code_len > 2 &&
|
||||
!isspace(code[0]) &&
|
||||
!(isspace(code[code_len - 1]) &&
|
||||
isspace(code[code_len - 2]))) &&
|
||||
!(node->prev == NULL && node->parent &&
|
||||
node->parent->type == CMARK_NODE_ITEM)) {
|
||||
LIT(" ");
|
||||
cmark_strbuf_puts(renderer->prefix, " ");
|
||||
OUT(cmark_node_get_literal(node), false, LITERAL);
|
||||
cmark_strbuf_truncate(renderer->prefix,
|
||||
renderer->prefix->size - 4);
|
||||
} else {
|
||||
numticks = longest_backtick_sequence(code) + 1;
|
||||
if (numticks < 3) {
|
||||
numticks = 3;
|
||||
}
|
||||
for (i = 0; i < numticks; i++) {
|
||||
LIT("`");
|
||||
}
|
||||
LIT(" ");
|
||||
OUT(info, false, LITERAL);
|
||||
CR();
|
||||
OUT(cmark_node_get_literal(node), false, LITERAL);
|
||||
CR();
|
||||
for (i = 0; i < numticks; i++) {
|
||||
LIT("`");
|
||||
}
|
||||
}
|
||||
BLANKLINE();
|
||||
break;
|
||||
case CMARK_NODE_CODE_BLOCK:
|
||||
BLANKLINE();
|
||||
info = cmark_node_get_fence_info(node);
|
||||
info_len = safe_strlen(info);
|
||||
code = cmark_node_get_literal(node);
|
||||
code_len = safe_strlen(code);
|
||||
// use indented form if no info, and code doesn't
|
||||
// begin or end with a blank line, and code isn't
|
||||
// first thing in a list item
|
||||
if (info_len == 0 &&
|
||||
(code_len > 2 && !isspace(code[0]) &&
|
||||
!(isspace(code[code_len - 1]) && isspace(code[code_len - 2]))) &&
|
||||
!(node->prev == NULL && node->parent &&
|
||||
node->parent->type == CMARK_NODE_ITEM)) {
|
||||
LIT(" ");
|
||||
cmark_strbuf_puts(renderer->prefix, " ");
|
||||
OUT(cmark_node_get_literal(node), false, LITERAL);
|
||||
cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 4);
|
||||
} else {
|
||||
numticks = longest_backtick_sequence(code) + 1;
|
||||
if (numticks < 3) {
|
||||
numticks = 3;
|
||||
}
|
||||
for (i = 0; i < numticks; i++) {
|
||||
LIT("`");
|
||||
}
|
||||
LIT(" ");
|
||||
OUT(info, false, LITERAL);
|
||||
CR();
|
||||
OUT(cmark_node_get_literal(node), false, LITERAL);
|
||||
CR();
|
||||
for (i = 0; i < numticks; i++) {
|
||||
LIT("`");
|
||||
}
|
||||
}
|
||||
BLANKLINE();
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HTML:
|
||||
BLANKLINE();
|
||||
OUT(cmark_node_get_literal(node), false, LITERAL);
|
||||
BLANKLINE();
|
||||
break;
|
||||
case CMARK_NODE_HTML:
|
||||
BLANKLINE();
|
||||
OUT(cmark_node_get_literal(node), false, LITERAL);
|
||||
BLANKLINE();
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HRULE:
|
||||
BLANKLINE();
|
||||
LIT("-----");
|
||||
BLANKLINE();
|
||||
break;
|
||||
case CMARK_NODE_HRULE:
|
||||
BLANKLINE();
|
||||
LIT("-----");
|
||||
BLANKLINE();
|
||||
break;
|
||||
|
||||
case CMARK_NODE_PARAGRAPH:
|
||||
if (!entering) {
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_PARAGRAPH:
|
||||
if (!entering) {
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_TEXT:
|
||||
OUT(cmark_node_get_literal(node), true, NORMAL);
|
||||
break;
|
||||
case CMARK_NODE_TEXT:
|
||||
OUT(cmark_node_get_literal(node), true, NORMAL);
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LINEBREAK:
|
||||
if (!(CMARK_OPT_HARDBREAKS & options)) {
|
||||
LIT("\\");
|
||||
}
|
||||
CR();
|
||||
break;
|
||||
case CMARK_NODE_LINEBREAK:
|
||||
if (!(CMARK_OPT_HARDBREAKS & options)) {
|
||||
LIT("\\");
|
||||
}
|
||||
CR();
|
||||
break;
|
||||
|
||||
case CMARK_NODE_SOFTBREAK:
|
||||
if (renderer->width == 0 &&
|
||||
!(CMARK_OPT_HARDBREAKS & options)) {
|
||||
CR();
|
||||
} else {
|
||||
OUT(" ", true, LITERAL);
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_SOFTBREAK:
|
||||
if (renderer->width == 0 && !(CMARK_OPT_HARDBREAKS & options)) {
|
||||
CR();
|
||||
} else {
|
||||
OUT(" ", true, LITERAL);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CODE:
|
||||
code = cmark_node_get_literal(node);
|
||||
code_len = safe_strlen(code);
|
||||
numticks = shortest_unused_backtick_sequence(code);
|
||||
for (i = 0; i < numticks; i++) {
|
||||
LIT("`");
|
||||
}
|
||||
if (code_len == 0 || code[0] == '`') {
|
||||
LIT(" ");
|
||||
}
|
||||
OUT(cmark_node_get_literal(node), true, LITERAL);
|
||||
if (code_len == 0 || code[code_len - 1] == '`') {
|
||||
LIT(" ");
|
||||
}
|
||||
for (i = 0; i < numticks; i++) {
|
||||
LIT("`");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_CODE:
|
||||
code = cmark_node_get_literal(node);
|
||||
code_len = safe_strlen(code);
|
||||
numticks = shortest_unused_backtick_sequence(code);
|
||||
for (i = 0; i < numticks; i++) {
|
||||
LIT("`");
|
||||
}
|
||||
if (code_len == 0 || code[0] == '`') {
|
||||
LIT(" ");
|
||||
}
|
||||
OUT(cmark_node_get_literal(node), true, LITERAL);
|
||||
if (code_len == 0 || code[code_len - 1] == '`') {
|
||||
LIT(" ");
|
||||
}
|
||||
for (i = 0; i < numticks; i++) {
|
||||
LIT("`");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_INLINE_HTML:
|
||||
OUT(cmark_node_get_literal(node), false, LITERAL);
|
||||
break;
|
||||
case CMARK_NODE_INLINE_HTML:
|
||||
OUT(cmark_node_get_literal(node), false, LITERAL);
|
||||
break;
|
||||
|
||||
case CMARK_NODE_STRONG:
|
||||
if (entering) {
|
||||
LIT("**");
|
||||
} else {
|
||||
LIT("**");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_STRONG:
|
||||
if (entering) {
|
||||
LIT("**");
|
||||
} else {
|
||||
LIT("**");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_EMPH:
|
||||
// If we have EMPH(EMPH(x)), we need to use *_x_*
|
||||
// because **x** is STRONG(x):
|
||||
if (node->parent && node->parent->type == CMARK_NODE_EMPH &&
|
||||
node->next == NULL && node->prev == NULL) {
|
||||
emph_delim = "_";
|
||||
} else {
|
||||
emph_delim = "*";
|
||||
}
|
||||
if (entering) {
|
||||
LIT(emph_delim);
|
||||
} else {
|
||||
LIT(emph_delim);
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_EMPH:
|
||||
// If we have EMPH(EMPH(x)), we need to use *_x_*
|
||||
// because **x** is STRONG(x):
|
||||
if (node->parent && node->parent->type == CMARK_NODE_EMPH &&
|
||||
node->next == NULL && node->prev == NULL) {
|
||||
emph_delim = "_";
|
||||
} else {
|
||||
emph_delim = "*";
|
||||
}
|
||||
if (entering) {
|
||||
LIT(emph_delim);
|
||||
} else {
|
||||
LIT(emph_delim);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LINK:
|
||||
if (is_autolink(node)) {
|
||||
if (entering) {
|
||||
LIT("<");
|
||||
if (strncmp(cmark_node_get_url(node),
|
||||
"mailto:", 7) == 0) {
|
||||
LIT((char *)cmark_node_get_url(node) + 7);
|
||||
} else {
|
||||
LIT((char *)cmark_node_get_url(node));
|
||||
}
|
||||
LIT(">");
|
||||
// return signal to skip contents of node...
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (entering) {
|
||||
LIT("[");
|
||||
} else {
|
||||
LIT("](");
|
||||
OUT(cmark_node_get_url(node), false, URL);
|
||||
title = cmark_node_get_title(node);
|
||||
if (safe_strlen(title) > 0) {
|
||||
LIT(" \"");
|
||||
OUT(title, false, TITLE);
|
||||
LIT("\"");
|
||||
}
|
||||
LIT(")");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_LINK:
|
||||
if (is_autolink(node)) {
|
||||
if (entering) {
|
||||
LIT("<");
|
||||
if (strncmp(cmark_node_get_url(node), "mailto:", 7) == 0) {
|
||||
LIT((char *)cmark_node_get_url(node) + 7);
|
||||
} else {
|
||||
LIT((char *)cmark_node_get_url(node));
|
||||
}
|
||||
LIT(">");
|
||||
// return signal to skip contents of node...
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (entering) {
|
||||
LIT("[");
|
||||
} else {
|
||||
LIT("](");
|
||||
OUT(cmark_node_get_url(node), false, URL);
|
||||
title = cmark_node_get_title(node);
|
||||
if (safe_strlen(title) > 0) {
|
||||
LIT(" \"");
|
||||
OUT(title, false, TITLE);
|
||||
LIT("\"");
|
||||
}
|
||||
LIT(")");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_IMAGE:
|
||||
if (entering) {
|
||||
LIT("![");
|
||||
} else {
|
||||
LIT("](");
|
||||
OUT(cmark_node_get_url(node), false, URL);
|
||||
title = cmark_node_get_title(node);
|
||||
if (safe_strlen(title) > 0) {
|
||||
OUT(" \"", true, LITERAL);
|
||||
OUT(title, false, TITLE);
|
||||
LIT("\"");
|
||||
}
|
||||
LIT(")");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_IMAGE:
|
||||
if (entering) {
|
||||
LIT("![");
|
||||
} else {
|
||||
LIT("](");
|
||||
OUT(cmark_node_get_url(node), false, URL);
|
||||
title = cmark_node_get_title(node);
|
||||
if (safe_strlen(title) > 0) {
|
||||
OUT(" \"", true, LITERAL);
|
||||
OUT(title, false, TITLE);
|
||||
LIT("\"");
|
||||
}
|
||||
LIT(")");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *cmark_render_commonmark(cmark_node *root, int options, int width)
|
||||
{
|
||||
if (options & CMARK_OPT_HARDBREAKS) {
|
||||
// disable breaking on width, since it has
|
||||
// a different meaning with OPT_HARDBREAKS
|
||||
width = 0;
|
||||
}
|
||||
return cmark_render(root, options, width, outc, S_render_node);
|
||||
char *cmark_render_commonmark(cmark_node *root, int options, int width) {
|
||||
if (options & CMARK_OPT_HARDBREAKS) {
|
||||
// disable breaking on width, since it has
|
||||
// a different meaning with OPT_HARDBREAKS
|
||||
width = 0;
|
||||
}
|
||||
return cmark_render(root, options, width, outc, S_render_node);
|
||||
}
|
||||
|
|
|
@ -10,33 +10,39 @@ extern "C" {
|
|||
#include "buffer.h"
|
||||
|
||||
#ifdef HAVE___BUILTIN_EXPECT
|
||||
# define likely(x) __builtin_expect((x),1)
|
||||
# define unlikely(x) __builtin_expect((x),0)
|
||||
#define likely(x) __builtin_expect((x), 1)
|
||||
#define unlikely(x) __builtin_expect((x), 0)
|
||||
#else
|
||||
# define likely(x) (x)
|
||||
# define unlikely(x) (x)
|
||||
#define likely(x) (x)
|
||||
#define unlikely(x) (x)
|
||||
#endif
|
||||
|
||||
#ifdef HOUDINI_USE_LOCALE
|
||||
# define _isxdigit(c) isxdigit(c)
|
||||
# define _isdigit(c) isdigit(c)
|
||||
#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')
|
||||
#define _isxdigit(c) (strchr("0123456789ABCDEFabcdef", (c)) != NULL)
|
||||
#define _isdigit(c) ((c) >= '0' && (c) <= '9')
|
||||
#endif
|
||||
|
||||
#define HOUDINI_ESCAPED_SIZE(x) (((x) * 12) / 10)
|
||||
#define HOUDINI_ESCAPED_SIZE(x) (((x)*12) / 10)
|
||||
#define HOUDINI_UNESCAPED_SIZE(x) (x)
|
||||
|
||||
extern bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src, bufsize_t size);
|
||||
extern int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src, bufsize_t size);
|
||||
extern int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src, bufsize_t size, int secure);
|
||||
extern int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src, bufsize_t size);
|
||||
extern void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src, bufsize_t size);
|
||||
extern int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src, bufsize_t size);
|
||||
extern bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src,
|
||||
bufsize_t size);
|
||||
extern int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src,
|
||||
bufsize_t size);
|
||||
extern int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src,
|
||||
bufsize_t size, int secure);
|
||||
extern int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src,
|
||||
bufsize_t size);
|
||||
extern void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src,
|
||||
bufsize_t size);
|
||||
extern int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src,
|
||||
bufsize_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -30,78 +30,71 @@
|
|||
*
|
||||
*/
|
||||
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,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 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,
|
||||
};
|
||||
|
||||
int
|
||||
houdini_escape_href(cmark_strbuf *ob, const uint8_t *src, bufsize_t size)
|
||||
{
|
||||
static const uint8_t hex_chars[] = "0123456789ABCDEF";
|
||||
bufsize_t i = 0, org;
|
||||
uint8_t hex_str[3];
|
||||
int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src, bufsize_t size) {
|
||||
static const uint8_t hex_chars[] = "0123456789ABCDEF";
|
||||
bufsize_t i = 0, org;
|
||||
uint8_t hex_str[3];
|
||||
|
||||
hex_str[0] = '%';
|
||||
hex_str[0] = '%';
|
||||
|
||||
while (i < size) {
|
||||
org = i;
|
||||
while (i < size && HREF_SAFE[src[i]] != 0)
|
||||
i++;
|
||||
while (i < size) {
|
||||
org = i;
|
||||
while (i < size && HREF_SAFE[src[i]] != 0)
|
||||
i++;
|
||||
|
||||
if (likely(i > org))
|
||||
cmark_strbuf_put(ob, src + org, i - org);
|
||||
if (likely(i > org))
|
||||
cmark_strbuf_put(ob, src + org, i - org);
|
||||
|
||||
/* escaping */
|
||||
if (i >= size)
|
||||
break;
|
||||
/* 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 '&':
|
||||
cmark_strbuf_puts(ob, "&");
|
||||
break;
|
||||
switch (src[i]) {
|
||||
/* amp appears all the time in URLs, but needs
|
||||
* HTML-entity escaping to be inside an href */
|
||||
case '&':
|
||||
cmark_strbuf_puts(ob, "&");
|
||||
break;
|
||||
|
||||
/* the single quote is a valid URL character
|
||||
* according to the standard; it needs HTML
|
||||
* entity escaping too */
|
||||
case '\'':
|
||||
cmark_strbuf_puts(ob, "'");
|
||||
break;
|
||||
/* the single quote is a valid URL character
|
||||
* according to the standard; it needs HTML
|
||||
* entity escaping too */
|
||||
case '\'':
|
||||
cmark_strbuf_puts(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 */
|
||||
/* 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 ' ':
|
||||
cmark_strbuf_putc(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];
|
||||
cmark_strbuf_put(ob, hex_str, 3);
|
||||
}
|
||||
/* 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];
|
||||
cmark_strbuf_put(ob, hex_str, 3);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -16,66 +16,51 @@
|
|||
*
|
||||
*/
|
||||
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,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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[] = {
|
||||
"",
|
||||
""",
|
||||
"&",
|
||||
"'",
|
||||
"/",
|
||||
"<",
|
||||
">"
|
||||
};
|
||||
static const char *HTML_ESCAPES[] = {"", """, "&", "'",
|
||||
"/", "<", ">"};
|
||||
|
||||
int
|
||||
houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src, bufsize_t size, int secure)
|
||||
{
|
||||
bufsize_t i = 0, org, esc = 0;
|
||||
int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src, bufsize_t size,
|
||||
int secure) {
|
||||
bufsize_t i = 0, org, esc = 0;
|
||||
|
||||
while (i < size) {
|
||||
org = i;
|
||||
while (i < size && (esc = HTML_ESCAPE_TABLE[src[i]]) == 0)
|
||||
i++;
|
||||
while (i < size) {
|
||||
org = i;
|
||||
while (i < size && (esc = HTML_ESCAPE_TABLE[src[i]]) == 0)
|
||||
i++;
|
||||
|
||||
if (i > org)
|
||||
cmark_strbuf_put(ob, src + org, i - org);
|
||||
if (i > org)
|
||||
cmark_strbuf_put(ob, src + org, i - org);
|
||||
|
||||
/* escaping */
|
||||
if (unlikely(i >= size))
|
||||
break;
|
||||
/* escaping */
|
||||
if (unlikely(i >= size))
|
||||
break;
|
||||
|
||||
/* The forward slash is only escaped in secure mode */
|
||||
if ((src[i] == '/' || src[i] == '\'') && !secure) {
|
||||
cmark_strbuf_putc(ob, src[i]);
|
||||
} else {
|
||||
cmark_strbuf_puts(ob, HTML_ESCAPES[esc]);
|
||||
}
|
||||
/* The forward slash is only escaped in secure mode */
|
||||
if ((src[i] == '/' || src[i] == '\'') && !secure) {
|
||||
cmark_strbuf_putc(ob, src[i]);
|
||||
} else {
|
||||
cmark_strbuf_puts(ob, HTML_ESCAPES[esc]);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
houdini_escape_html(cmark_strbuf *ob, const uint8_t *src, bufsize_t size)
|
||||
{
|
||||
return houdini_escape_html0(ob, src, size, 1);
|
||||
int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src, bufsize_t size) {
|
||||
return houdini_escape_html0(ob, src, size, 1);
|
||||
}
|
||||
|
|
|
@ -9,145 +9,140 @@
|
|||
|
||||
/* Binary tree lookup code for entities added by JGM */
|
||||
|
||||
static unsigned char *
|
||||
S_lookup(int i, int low, int hi, const unsigned char *s, int len)
|
||||
{
|
||||
int j;
|
||||
int cmp = strncmp((char *)s, (char *)cmark_entities[i].entity, len);
|
||||
if (cmp == 0 && cmark_entities[i].entity[len] == 0) {
|
||||
return (unsigned char *)cmark_entities[i].bytes;
|
||||
} else if (cmp < 0 && i > low) {
|
||||
j = i - ((i - low) / 2);
|
||||
if (j == i) j -= 1;
|
||||
return S_lookup(j, low, i - 1, s, len);
|
||||
} else if (cmp > 0 && i < hi) {
|
||||
j = i + ((hi - i) / 2);
|
||||
if (j == i) j += 1;
|
||||
return S_lookup(j, i + 1, hi, s, len);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
static unsigned char *S_lookup(int i, int low, int hi, const unsigned char *s,
|
||||
int len) {
|
||||
int j;
|
||||
int cmp = strncmp((char *)s, (char *)cmark_entities[i].entity, len);
|
||||
if (cmp == 0 && cmark_entities[i].entity[len] == 0) {
|
||||
return (unsigned char *)cmark_entities[i].bytes;
|
||||
} else if (cmp < 0 && i > low) {
|
||||
j = i - ((i - low) / 2);
|
||||
if (j == i)
|
||||
j -= 1;
|
||||
return S_lookup(j, low, i - 1, s, len);
|
||||
} else if (cmp > 0 && i < hi) {
|
||||
j = i + ((hi - i) / 2);
|
||||
if (j == i)
|
||||
j += 1;
|
||||
return S_lookup(j, i + 1, hi, s, len);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
S_lookup_entity(const unsigned char *s, int len)
|
||||
{
|
||||
return S_lookup(CMARK_NUM_ENTITIES / 2, 0, CMARK_NUM_ENTITIES - 1, s, len);
|
||||
static unsigned char *S_lookup_entity(const unsigned char *s, int len) {
|
||||
return S_lookup(CMARK_NUM_ENTITIES / 2, 0, CMARK_NUM_ENTITIES - 1, s, len);
|
||||
}
|
||||
|
||||
bufsize_t
|
||||
houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src, bufsize_t size)
|
||||
{
|
||||
bufsize_t i = 0;
|
||||
bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src,
|
||||
bufsize_t size) {
|
||||
bufsize_t i = 0;
|
||||
|
||||
if (size >= 3 && src[0] == '#') {
|
||||
int codepoint = 0;
|
||||
int num_digits = 0;
|
||||
if (size >= 3 && src[0] == '#') {
|
||||
int codepoint = 0;
|
||||
int num_digits = 0;
|
||||
|
||||
if (_isdigit(src[1])) {
|
||||
for (i = 1; i < size && _isdigit(src[i]); ++i) {
|
||||
codepoint = (codepoint * 10) + (src[i] - '0');
|
||||
if (_isdigit(src[1])) {
|
||||
for (i = 1; i < size && _isdigit(src[i]); ++i) {
|
||||
codepoint = (codepoint * 10) + (src[i] - '0');
|
||||
|
||||
if (codepoint >= 0x110000) {
|
||||
// Keep counting digits but
|
||||
// avoid integer overflow.
|
||||
codepoint = 0x110000;
|
||||
}
|
||||
}
|
||||
if (codepoint >= 0x110000) {
|
||||
// Keep counting digits but
|
||||
// avoid integer overflow.
|
||||
codepoint = 0x110000;
|
||||
}
|
||||
}
|
||||
|
||||
num_digits = i - 1;
|
||||
}
|
||||
num_digits = i - 1;
|
||||
}
|
||||
|
||||
else if (src[1] == 'x' || src[1] == 'X') {
|
||||
for (i = 2; i < size && _isxdigit(src[i]); ++i) {
|
||||
codepoint = (codepoint * 16) + ((src[i] | 32) % 39 - 9);
|
||||
else if (src[1] == 'x' || src[1] == 'X') {
|
||||
for (i = 2; i < size && _isxdigit(src[i]); ++i) {
|
||||
codepoint = (codepoint * 16) + ((src[i] | 32) % 39 - 9);
|
||||
|
||||
if (codepoint >= 0x110000) {
|
||||
// Keep counting digits but
|
||||
// avoid integer overflow.
|
||||
codepoint = 0x110000;
|
||||
}
|
||||
}
|
||||
if (codepoint >= 0x110000) {
|
||||
// Keep counting digits but
|
||||
// avoid integer overflow.
|
||||
codepoint = 0x110000;
|
||||
}
|
||||
}
|
||||
|
||||
num_digits = i - 2;
|
||||
}
|
||||
num_digits = i - 2;
|
||||
}
|
||||
|
||||
if (num_digits >= 1 && num_digits <= 8 &&
|
||||
i < size && src[i] == ';') {
|
||||
if (codepoint == 0 ||
|
||||
(codepoint >= 0xD800 && codepoint < 0xE000) ||
|
||||
codepoint >= 0x110000) {
|
||||
codepoint = 0xFFFD;
|
||||
}
|
||||
utf8proc_encode_char(codepoint, ob);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
if (num_digits >= 1 && num_digits <= 8 && i < size && src[i] == ';') {
|
||||
if (codepoint == 0 || (codepoint >= 0xD800 && codepoint < 0xE000) ||
|
||||
codepoint >= 0x110000) {
|
||||
codepoint = 0xFFFD;
|
||||
}
|
||||
utf8proc_encode_char(codepoint, ob);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
if (size > CMARK_ENTITY_MAX_LENGTH)
|
||||
size = CMARK_ENTITY_MAX_LENGTH;
|
||||
else {
|
||||
if (size > CMARK_ENTITY_MAX_LENGTH)
|
||||
size = CMARK_ENTITY_MAX_LENGTH;
|
||||
|
||||
for (i = CMARK_ENTITY_MIN_LENGTH; i < size; ++i) {
|
||||
if (src[i] == ' ')
|
||||
break;
|
||||
for (i = CMARK_ENTITY_MIN_LENGTH; i < size; ++i) {
|
||||
if (src[i] == ' ')
|
||||
break;
|
||||
|
||||
if (src[i] == ';') {
|
||||
const unsigned char *entity = S_lookup_entity(src, i);
|
||||
if (src[i] == ';') {
|
||||
const unsigned char *entity = S_lookup_entity(src, i);
|
||||
|
||||
if (entity != NULL) {
|
||||
cmark_strbuf_puts(ob, (const char *)entity);
|
||||
return i + 1;
|
||||
}
|
||||
if (entity != NULL) {
|
||||
cmark_strbuf_puts(ob, (const char *)entity);
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src, bufsize_t size)
|
||||
{
|
||||
bufsize_t i = 0, org, ent;
|
||||
int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src,
|
||||
bufsize_t size) {
|
||||
bufsize_t i = 0, org, ent;
|
||||
|
||||
while (i < size) {
|
||||
org = i;
|
||||
while (i < size && src[i] != '&')
|
||||
i++;
|
||||
while (i < size) {
|
||||
org = i;
|
||||
while (i < size && src[i] != '&')
|
||||
i++;
|
||||
|
||||
if (likely(i > org)) {
|
||||
if (unlikely(org == 0)) {
|
||||
if (i >= size)
|
||||
return 0;
|
||||
if (likely(i > org)) {
|
||||
if (unlikely(org == 0)) {
|
||||
if (i >= size)
|
||||
return 0;
|
||||
|
||||
cmark_strbuf_grow(ob, HOUDINI_UNESCAPED_SIZE(size));
|
||||
}
|
||||
cmark_strbuf_grow(ob, HOUDINI_UNESCAPED_SIZE(size));
|
||||
}
|
||||
|
||||
cmark_strbuf_put(ob, src + org, i - org);
|
||||
}
|
||||
cmark_strbuf_put(ob, src + org, i - org);
|
||||
}
|
||||
|
||||
/* escaping */
|
||||
if (i >= size)
|
||||
break;
|
||||
/* escaping */
|
||||
if (i >= size)
|
||||
break;
|
||||
|
||||
i++;
|
||||
i++;
|
||||
|
||||
ent = houdini_unescape_ent(ob, src + i, size - i);
|
||||
i += ent;
|
||||
ent = houdini_unescape_ent(ob, src + i, size - i);
|
||||
i += ent;
|
||||
|
||||
/* not really an entity */
|
||||
if (ent == 0)
|
||||
cmark_strbuf_putc(ob, '&');
|
||||
}
|
||||
/* not really an entity */
|
||||
if (ent == 0)
|
||||
cmark_strbuf_putc(ob, '&');
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src, bufsize_t size)
|
||||
{
|
||||
if (!houdini_unescape_html(ob, src, size))
|
||||
cmark_strbuf_put(ob, src, size);
|
||||
void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src,
|
||||
bufsize_t size) {
|
||||
if (!houdini_unescape_html(ob, src, size))
|
||||
cmark_strbuf_put(ob, src, size);
|
||||
}
|
||||
|
|
534
src/html.c
534
src/html.c
|
@ -12,324 +12,304 @@
|
|||
|
||||
// Functions to convert cmark_nodes to HTML strings.
|
||||
|
||||
static void escape_html(cmark_strbuf *dest, const unsigned char *source, bufsize_t length)
|
||||
{
|
||||
houdini_escape_html0(dest, source, length, 0);
|
||||
static void escape_html(cmark_strbuf *dest, const unsigned char *source,
|
||||
bufsize_t length) {
|
||||
houdini_escape_html0(dest, source, length, 0);
|
||||
}
|
||||
|
||||
static inline void cr(cmark_strbuf *html)
|
||||
{
|
||||
if (html->size && html->ptr[html->size - 1] != '\n')
|
||||
cmark_strbuf_putc(html, '\n');
|
||||
static inline void cr(cmark_strbuf *html) {
|
||||
if (html->size && html->ptr[html->size - 1] != '\n')
|
||||
cmark_strbuf_putc(html, '\n');
|
||||
}
|
||||
|
||||
struct render_state {
|
||||
cmark_strbuf* html;
|
||||
cmark_node *plain;
|
||||
cmark_strbuf *html;
|
||||
cmark_node *plain;
|
||||
};
|
||||
|
||||
static void
|
||||
S_render_sourcepos(cmark_node *node, cmark_strbuf *html, int options)
|
||||
{
|
||||
char buffer[100];
|
||||
if (CMARK_OPT_SOURCEPOS & options) {
|
||||
sprintf(buffer, " data-sourcepos=\"%d:%d-%d:%d\"",
|
||||
cmark_node_get_start_line(node),
|
||||
cmark_node_get_start_column(node),
|
||||
cmark_node_get_end_line(node),
|
||||
cmark_node_get_end_column(node));
|
||||
cmark_strbuf_puts(html, buffer);
|
||||
}
|
||||
static void S_render_sourcepos(cmark_node *node, cmark_strbuf *html,
|
||||
int options) {
|
||||
char buffer[100];
|
||||
if (CMARK_OPT_SOURCEPOS & options) {
|
||||
sprintf(buffer, " data-sourcepos=\"%d:%d-%d:%d\"",
|
||||
cmark_node_get_start_line(node), cmark_node_get_start_column(node),
|
||||
cmark_node_get_end_line(node), cmark_node_get_end_column(node));
|
||||
cmark_strbuf_puts(html, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||
struct render_state *state, int options)
|
||||
{
|
||||
cmark_node *parent;
|
||||
cmark_node *grandparent;
|
||||
cmark_strbuf *html = state->html;
|
||||
char start_header[] = "<h0";
|
||||
char end_header[] = "</h0";
|
||||
bool tight;
|
||||
char buffer[100];
|
||||
static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||
struct render_state *state, int options) {
|
||||
cmark_node *parent;
|
||||
cmark_node *grandparent;
|
||||
cmark_strbuf *html = state->html;
|
||||
char start_header[] = "<h0";
|
||||
char end_header[] = "</h0";
|
||||
bool tight;
|
||||
char buffer[100];
|
||||
|
||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||
|
||||
if (state->plain == node) { // back at original node
|
||||
state->plain = NULL;
|
||||
}
|
||||
if (state->plain == node) { // back at original node
|
||||
state->plain = NULL;
|
||||
}
|
||||
|
||||
if (state->plain != NULL) {
|
||||
switch(node->type) {
|
||||
case CMARK_NODE_TEXT:
|
||||
case CMARK_NODE_CODE:
|
||||
case CMARK_NODE_INLINE_HTML:
|
||||
escape_html(html, node->as.literal.data,
|
||||
node->as.literal.len);
|
||||
break;
|
||||
if (state->plain != NULL) {
|
||||
switch (node->type) {
|
||||
case CMARK_NODE_TEXT:
|
||||
case CMARK_NODE_CODE:
|
||||
case CMARK_NODE_INLINE_HTML:
|
||||
escape_html(html, node->as.literal.data, node->as.literal.len);
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LINEBREAK:
|
||||
case CMARK_NODE_SOFTBREAK:
|
||||
cmark_strbuf_putc(html, ' ');
|
||||
break;
|
||||
case CMARK_NODE_LINEBREAK:
|
||||
case CMARK_NODE_SOFTBREAK:
|
||||
cmark_strbuf_putc(html, ' ');
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (node->type) {
|
||||
case CMARK_NODE_DOCUMENT:
|
||||
break;
|
||||
switch (node->type) {
|
||||
case CMARK_NODE_DOCUMENT:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_BLOCK_QUOTE:
|
||||
if (entering) {
|
||||
cr(html);
|
||||
cmark_strbuf_puts(html, "<blockquote");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, ">\n");
|
||||
} else {
|
||||
cr(html);
|
||||
cmark_strbuf_puts(html, "</blockquote>\n");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_BLOCK_QUOTE:
|
||||
if (entering) {
|
||||
cr(html);
|
||||
cmark_strbuf_puts(html, "<blockquote");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, ">\n");
|
||||
} else {
|
||||
cr(html);
|
||||
cmark_strbuf_puts(html, "</blockquote>\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LIST: {
|
||||
cmark_list_type list_type = node->as.list.list_type;
|
||||
int start = node->as.list.start;
|
||||
case CMARK_NODE_LIST: {
|
||||
cmark_list_type list_type = node->as.list.list_type;
|
||||
int start = node->as.list.start;
|
||||
|
||||
if (entering) {
|
||||
cr(html);
|
||||
if (list_type == CMARK_BULLET_LIST) {
|
||||
cmark_strbuf_puts(html, "<ul");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, ">\n");
|
||||
} else if (start == 1) {
|
||||
cmark_strbuf_puts(html, "<ol");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, ">\n");
|
||||
} else {
|
||||
sprintf(buffer, "<ol start=\"%d\"", start);
|
||||
cmark_strbuf_puts(html, buffer);
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, ">\n");
|
||||
}
|
||||
} else {
|
||||
cmark_strbuf_puts(html,
|
||||
list_type == CMARK_BULLET_LIST ?
|
||||
"</ul>\n" : "</ol>\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (entering) {
|
||||
cr(html);
|
||||
if (list_type == CMARK_BULLET_LIST) {
|
||||
cmark_strbuf_puts(html, "<ul");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, ">\n");
|
||||
} else if (start == 1) {
|
||||
cmark_strbuf_puts(html, "<ol");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, ">\n");
|
||||
} else {
|
||||
sprintf(buffer, "<ol start=\"%d\"", start);
|
||||
cmark_strbuf_puts(html, buffer);
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, ">\n");
|
||||
}
|
||||
} else {
|
||||
cmark_strbuf_puts(html,
|
||||
list_type == CMARK_BULLET_LIST ? "</ul>\n" : "</ol>\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CMARK_NODE_ITEM:
|
||||
if (entering) {
|
||||
cr(html);
|
||||
cmark_strbuf_puts(html, "<li");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_putc(html, '>');
|
||||
} else {
|
||||
cmark_strbuf_puts(html, "</li>\n");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_ITEM:
|
||||
if (entering) {
|
||||
cr(html);
|
||||
cmark_strbuf_puts(html, "<li");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_putc(html, '>');
|
||||
} else {
|
||||
cmark_strbuf_puts(html, "</li>\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HEADER:
|
||||
if (entering) {
|
||||
cr(html);
|
||||
start_header[2] = '0' + node->as.header.level;
|
||||
cmark_strbuf_puts(html, start_header);
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_putc(html, '>');
|
||||
} else {
|
||||
end_header[3] = '0' + node->as.header.level;
|
||||
cmark_strbuf_puts(html, end_header);
|
||||
cmark_strbuf_puts(html, ">\n");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_HEADER:
|
||||
if (entering) {
|
||||
cr(html);
|
||||
start_header[2] = '0' + node->as.header.level;
|
||||
cmark_strbuf_puts(html, start_header);
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_putc(html, '>');
|
||||
} else {
|
||||
end_header[3] = '0' + node->as.header.level;
|
||||
cmark_strbuf_puts(html, end_header);
|
||||
cmark_strbuf_puts(html, ">\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CODE_BLOCK:
|
||||
cr(html);
|
||||
case CMARK_NODE_CODE_BLOCK:
|
||||
cr(html);
|
||||
|
||||
if (!node->as.code.fenced || node->as.code.info.len == 0) {
|
||||
cmark_strbuf_puts(html, "<pre");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, "><code>");
|
||||
} else {
|
||||
bufsize_t first_tag = 0;
|
||||
while (first_tag < node->as.code.info.len &&
|
||||
!cmark_isspace(node->as.code.info.data[first_tag])) {
|
||||
first_tag += 1;
|
||||
}
|
||||
if (!node->as.code.fenced || node->as.code.info.len == 0) {
|
||||
cmark_strbuf_puts(html, "<pre");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, "><code>");
|
||||
} else {
|
||||
bufsize_t first_tag = 0;
|
||||
while (first_tag < node->as.code.info.len &&
|
||||
!cmark_isspace(node->as.code.info.data[first_tag])) {
|
||||
first_tag += 1;
|
||||
}
|
||||
|
||||
cmark_strbuf_puts(html, "<pre");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, "><code class=\"language-");
|
||||
escape_html(html, node->as.code.info.data, first_tag);
|
||||
cmark_strbuf_puts(html, "\">");
|
||||
}
|
||||
cmark_strbuf_puts(html, "<pre");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, "><code class=\"language-");
|
||||
escape_html(html, node->as.code.info.data, first_tag);
|
||||
cmark_strbuf_puts(html, "\">");
|
||||
}
|
||||
|
||||
escape_html(html, node->as.code.literal.data,
|
||||
node->as.code.literal.len);
|
||||
cmark_strbuf_puts(html, "</code></pre>\n");
|
||||
break;
|
||||
escape_html(html, node->as.code.literal.data, node->as.code.literal.len);
|
||||
cmark_strbuf_puts(html, "</code></pre>\n");
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HTML:
|
||||
cr(html);
|
||||
if (options & CMARK_OPT_SAFE) {
|
||||
cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
|
||||
} else {
|
||||
cmark_strbuf_put(html, node->as.literal.data,
|
||||
node->as.literal.len);
|
||||
}
|
||||
cr(html);
|
||||
break;
|
||||
case CMARK_NODE_HTML:
|
||||
cr(html);
|
||||
if (options & CMARK_OPT_SAFE) {
|
||||
cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
|
||||
} else {
|
||||
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
|
||||
}
|
||||
cr(html);
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HRULE:
|
||||
cr(html);
|
||||
cmark_strbuf_puts(html, "<hr");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, " />\n");
|
||||
break;
|
||||
case CMARK_NODE_HRULE:
|
||||
cr(html);
|
||||
cmark_strbuf_puts(html, "<hr");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_puts(html, " />\n");
|
||||
break;
|
||||
|
||||
case CMARK_NODE_PARAGRAPH:
|
||||
parent = cmark_node_parent(node);
|
||||
grandparent = cmark_node_parent(parent);
|
||||
if (grandparent != NULL &&
|
||||
grandparent->type == CMARK_NODE_LIST) {
|
||||
tight = grandparent->as.list.tight;
|
||||
} else {
|
||||
tight = false;
|
||||
}
|
||||
if (!tight) {
|
||||
if (entering) {
|
||||
cr(html);
|
||||
cmark_strbuf_puts(html, "<p");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_putc(html, '>');
|
||||
} else {
|
||||
cmark_strbuf_puts(html, "</p>\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_PARAGRAPH:
|
||||
parent = cmark_node_parent(node);
|
||||
grandparent = cmark_node_parent(parent);
|
||||
if (grandparent != NULL && grandparent->type == CMARK_NODE_LIST) {
|
||||
tight = grandparent->as.list.tight;
|
||||
} else {
|
||||
tight = false;
|
||||
}
|
||||
if (!tight) {
|
||||
if (entering) {
|
||||
cr(html);
|
||||
cmark_strbuf_puts(html, "<p");
|
||||
S_render_sourcepos(node, html, options);
|
||||
cmark_strbuf_putc(html, '>');
|
||||
} else {
|
||||
cmark_strbuf_puts(html, "</p>\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_TEXT:
|
||||
escape_html(html, node->as.literal.data, node->as.literal.len);
|
||||
break;
|
||||
case CMARK_NODE_TEXT:
|
||||
escape_html(html, node->as.literal.data, node->as.literal.len);
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LINEBREAK:
|
||||
cmark_strbuf_puts(html, "<br />\n");
|
||||
break;
|
||||
case CMARK_NODE_LINEBREAK:
|
||||
cmark_strbuf_puts(html, "<br />\n");
|
||||
break;
|
||||
|
||||
case CMARK_NODE_SOFTBREAK:
|
||||
if (options & CMARK_OPT_HARDBREAKS) {
|
||||
cmark_strbuf_puts(html, "<br />\n");
|
||||
} else {
|
||||
cmark_strbuf_putc(html, '\n');
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_SOFTBREAK:
|
||||
if (options & CMARK_OPT_HARDBREAKS) {
|
||||
cmark_strbuf_puts(html, "<br />\n");
|
||||
} else {
|
||||
cmark_strbuf_putc(html, '\n');
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CODE:
|
||||
cmark_strbuf_puts(html, "<code>");
|
||||
escape_html(html, node->as.literal.data, node->as.literal.len);
|
||||
cmark_strbuf_puts(html, "</code>");
|
||||
break;
|
||||
case CMARK_NODE_CODE:
|
||||
cmark_strbuf_puts(html, "<code>");
|
||||
escape_html(html, node->as.literal.data, node->as.literal.len);
|
||||
cmark_strbuf_puts(html, "</code>");
|
||||
break;
|
||||
|
||||
case CMARK_NODE_INLINE_HTML:
|
||||
if (options & CMARK_OPT_SAFE) {
|
||||
cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
|
||||
} else {
|
||||
cmark_strbuf_put(html, node->as.literal.data,
|
||||
node->as.literal.len);
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_INLINE_HTML:
|
||||
if (options & CMARK_OPT_SAFE) {
|
||||
cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
|
||||
} else {
|
||||
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_STRONG:
|
||||
if (entering) {
|
||||
cmark_strbuf_puts(html, "<strong>");
|
||||
} else {
|
||||
cmark_strbuf_puts(html, "</strong>");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_STRONG:
|
||||
if (entering) {
|
||||
cmark_strbuf_puts(html, "<strong>");
|
||||
} else {
|
||||
cmark_strbuf_puts(html, "</strong>");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_EMPH:
|
||||
if (entering) {
|
||||
cmark_strbuf_puts(html, "<em>");
|
||||
} else {
|
||||
cmark_strbuf_puts(html, "</em>");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_EMPH:
|
||||
if (entering) {
|
||||
cmark_strbuf_puts(html, "<em>");
|
||||
} else {
|
||||
cmark_strbuf_puts(html, "</em>");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LINK:
|
||||
if (entering) {
|
||||
cmark_strbuf_puts(html, "<a href=\"");
|
||||
if (!((options & CMARK_OPT_SAFE) &&
|
||||
scan_dangerous_url(&node->as.link.url, 0))) {
|
||||
houdini_escape_href(html,
|
||||
node->as.link.url.data,
|
||||
node->as.link.url.len);
|
||||
case CMARK_NODE_LINK:
|
||||
if (entering) {
|
||||
cmark_strbuf_puts(html, "<a href=\"");
|
||||
if (!((options & CMARK_OPT_SAFE) &&
|
||||
scan_dangerous_url(&node->as.link.url, 0))) {
|
||||
houdini_escape_href(html, node->as.link.url.data,
|
||||
node->as.link.url.len);
|
||||
}
|
||||
if (node->as.link.title.len) {
|
||||
cmark_strbuf_puts(html, "\" title=\"");
|
||||
escape_html(html, node->as.link.title.data, node->as.link.title.len);
|
||||
}
|
||||
cmark_strbuf_puts(html, "\">");
|
||||
} else {
|
||||
cmark_strbuf_puts(html, "</a>");
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
if (node->as.link.title.len) {
|
||||
cmark_strbuf_puts(html, "\" title=\"");
|
||||
escape_html(html,
|
||||
node->as.link.title.data,
|
||||
node->as.link.title.len);
|
||||
}
|
||||
cmark_strbuf_puts(html, "\">");
|
||||
} else {
|
||||
cmark_strbuf_puts(html, "</a>");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_IMAGE:
|
||||
if (entering) {
|
||||
cmark_strbuf_puts(html, "<img src=\"");
|
||||
if (!((options & CMARK_OPT_SAFE) &&
|
||||
scan_dangerous_url(&node->as.link.url, 0))) {
|
||||
houdini_escape_href(html, node->as.link.url.data,
|
||||
node->as.link.url.len);
|
||||
}
|
||||
cmark_strbuf_puts(html, "\" alt=\"");
|
||||
state->plain = node;
|
||||
} else {
|
||||
if (node->as.link.title.len) {
|
||||
cmark_strbuf_puts(html, "\" title=\"");
|
||||
escape_html(html, node->as.link.title.data, node->as.link.title.len);
|
||||
}
|
||||
|
||||
case CMARK_NODE_IMAGE:
|
||||
if (entering) {
|
||||
cmark_strbuf_puts(html, "<img src=\"");
|
||||
if (!((options & CMARK_OPT_SAFE) &&
|
||||
scan_dangerous_url(&node->as.link.url, 0))) {
|
||||
houdini_escape_href(html,
|
||||
node->as.link.url.data,
|
||||
node->as.link.url.len);
|
||||
cmark_strbuf_puts(html, "\" />");
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
cmark_strbuf_puts(html, "\" alt=\"");
|
||||
state->plain = node;
|
||||
} else {
|
||||
if (node->as.link.title.len) {
|
||||
cmark_strbuf_puts(html, "\" title=\"");
|
||||
escape_html(html, node->as.link.title.data,
|
||||
node->as.link.title.len);
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
cmark_strbuf_puts(html, "\" />");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
// cmark_strbuf_putc(html, 'x');
|
||||
return 1;
|
||||
// cmark_strbuf_putc(html, 'x');
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *cmark_render_html(cmark_node *root, int options)
|
||||
{
|
||||
char *result;
|
||||
cmark_strbuf html = GH_BUF_INIT;
|
||||
cmark_event_type ev_type;
|
||||
cmark_node *cur;
|
||||
struct render_state state = { &html, NULL };
|
||||
cmark_iter *iter = cmark_iter_new(root);
|
||||
char *cmark_render_html(cmark_node *root, int options) {
|
||||
char *result;
|
||||
cmark_strbuf html = GH_BUF_INIT;
|
||||
cmark_event_type ev_type;
|
||||
cmark_node *cur;
|
||||
struct render_state state = {&html, NULL};
|
||||
cmark_iter *iter = cmark_iter_new(root);
|
||||
|
||||
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
||||
cur = cmark_iter_get_node(iter);
|
||||
S_render_node(cur, ev_type, &state, options);
|
||||
}
|
||||
result = (char *)cmark_strbuf_detach(&html);
|
||||
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
||||
cur = cmark_iter_get_node(iter);
|
||||
S_render_node(cur, ev_type, &state, options);
|
||||
}
|
||||
result = (char *)cmark_strbuf_detach(&html);
|
||||
|
||||
cmark_iter_free(iter);
|
||||
return result;
|
||||
cmark_iter_free(iter);
|
||||
return result;
|
||||
}
|
||||
|
|
1841
src/inlines.c
1841
src/inlines.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,9 +8,11 @@ extern "C" {
|
|||
cmark_chunk cmark_clean_url(cmark_chunk *url);
|
||||
cmark_chunk cmark_clean_title(cmark_chunk *title);
|
||||
|
||||
void cmark_parse_inlines(cmark_node* parent, cmark_reference_map *refmap, int options);
|
||||
void cmark_parse_inlines(cmark_node *parent, cmark_reference_map *refmap,
|
||||
int options);
|
||||
|
||||
bufsize_t cmark_parse_reference_inline(cmark_strbuf *input, cmark_reference_map *refmap);
|
||||
bufsize_t cmark_parse_reference_inline(cmark_strbuf *input,
|
||||
cmark_reference_map *refmap);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
224
src/iterator.c
224
src/iterator.c
|
@ -7,142 +7,112 @@
|
|||
#include "iterator.h"
|
||||
|
||||
static const int S_leaf_mask =
|
||||
(1 << CMARK_NODE_HTML) |
|
||||
(1 << CMARK_NODE_HRULE) |
|
||||
(1 << CMARK_NODE_CODE_BLOCK) |
|
||||
(1 << CMARK_NODE_TEXT) |
|
||||
(1 << CMARK_NODE_SOFTBREAK) |
|
||||
(1 << CMARK_NODE_LINEBREAK) |
|
||||
(1 << CMARK_NODE_CODE) |
|
||||
(1 << CMARK_NODE_INLINE_HTML);
|
||||
(1 << CMARK_NODE_HTML) | (1 << CMARK_NODE_HRULE) |
|
||||
(1 << CMARK_NODE_CODE_BLOCK) | (1 << CMARK_NODE_TEXT) |
|
||||
(1 << CMARK_NODE_SOFTBREAK) | (1 << CMARK_NODE_LINEBREAK) |
|
||||
(1 << CMARK_NODE_CODE) | (1 << CMARK_NODE_INLINE_HTML);
|
||||
|
||||
cmark_iter*
|
||||
cmark_iter_new(cmark_node *root)
|
||||
{
|
||||
if (root == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
cmark_iter *iter = (cmark_iter*)malloc(sizeof(cmark_iter));
|
||||
if (iter == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
iter->root = root;
|
||||
iter->cur.ev_type = CMARK_EVENT_NONE;
|
||||
iter->cur.node = NULL;
|
||||
iter->next.ev_type = CMARK_EVENT_ENTER;
|
||||
iter->next.node = root;
|
||||
return iter;
|
||||
cmark_iter *cmark_iter_new(cmark_node *root) {
|
||||
if (root == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
cmark_iter *iter = (cmark_iter *)malloc(sizeof(cmark_iter));
|
||||
if (iter == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
iter->root = root;
|
||||
iter->cur.ev_type = CMARK_EVENT_NONE;
|
||||
iter->cur.node = NULL;
|
||||
iter->next.ev_type = CMARK_EVENT_ENTER;
|
||||
iter->next.node = root;
|
||||
return iter;
|
||||
}
|
||||
|
||||
void
|
||||
cmark_iter_free(cmark_iter *iter)
|
||||
{
|
||||
free(iter);
|
||||
void cmark_iter_free(cmark_iter *iter) { free(iter); }
|
||||
|
||||
static bool S_is_leaf(cmark_node *node) {
|
||||
return (1 << node->type) & S_leaf_mask;
|
||||
}
|
||||
|
||||
static bool
|
||||
S_is_leaf(cmark_node *node)
|
||||
{
|
||||
return (1 << node->type) & S_leaf_mask;
|
||||
cmark_event_type cmark_iter_next(cmark_iter *iter) {
|
||||
cmark_event_type ev_type = iter->next.ev_type;
|
||||
cmark_node *node = iter->next.node;
|
||||
|
||||
iter->cur.ev_type = ev_type;
|
||||
iter->cur.node = node;
|
||||
|
||||
if (ev_type == CMARK_EVENT_DONE) {
|
||||
return ev_type;
|
||||
}
|
||||
|
||||
/* roll forward to next item, setting both fields */
|
||||
if (ev_type == CMARK_EVENT_ENTER && !S_is_leaf(node)) {
|
||||
if (node->first_child == NULL) {
|
||||
/* stay on this node but exit */
|
||||
iter->next.ev_type = CMARK_EVENT_EXIT;
|
||||
} else {
|
||||
iter->next.ev_type = CMARK_EVENT_ENTER;
|
||||
iter->next.node = node->first_child;
|
||||
}
|
||||
} else if (node == iter->root) {
|
||||
/* don't move past root */
|
||||
iter->next.ev_type = CMARK_EVENT_DONE;
|
||||
iter->next.node = NULL;
|
||||
} else if (node->next) {
|
||||
iter->next.ev_type = CMARK_EVENT_ENTER;
|
||||
iter->next.node = node->next;
|
||||
} else if (node->parent) {
|
||||
iter->next.ev_type = CMARK_EVENT_EXIT;
|
||||
iter->next.node = node->parent;
|
||||
} else {
|
||||
assert(false);
|
||||
iter->next.ev_type = CMARK_EVENT_DONE;
|
||||
iter->next.node = NULL;
|
||||
}
|
||||
|
||||
return ev_type;
|
||||
}
|
||||
|
||||
cmark_event_type
|
||||
cmark_iter_next(cmark_iter *iter)
|
||||
{
|
||||
cmark_event_type ev_type = iter->next.ev_type;
|
||||
cmark_node *node = iter->next.node;
|
||||
|
||||
iter->cur.ev_type = ev_type;
|
||||
iter->cur.node = node;
|
||||
|
||||
if (ev_type == CMARK_EVENT_DONE) {
|
||||
return ev_type;
|
||||
}
|
||||
|
||||
/* roll forward to next item, setting both fields */
|
||||
if (ev_type == CMARK_EVENT_ENTER && !S_is_leaf(node)) {
|
||||
if (node->first_child == NULL) {
|
||||
/* stay on this node but exit */
|
||||
iter->next.ev_type = CMARK_EVENT_EXIT;
|
||||
} else {
|
||||
iter->next.ev_type = CMARK_EVENT_ENTER;
|
||||
iter->next.node = node->first_child;
|
||||
}
|
||||
} else if (node == iter->root) {
|
||||
/* don't move past root */
|
||||
iter->next.ev_type = CMARK_EVENT_DONE;
|
||||
iter->next.node = NULL;
|
||||
} else if (node->next) {
|
||||
iter->next.ev_type = CMARK_EVENT_ENTER;
|
||||
iter->next.node = node->next;
|
||||
} else if (node->parent) {
|
||||
iter->next.ev_type = CMARK_EVENT_EXIT;
|
||||
iter->next.node = node->parent;
|
||||
} else {
|
||||
assert(false);
|
||||
iter->next.ev_type = CMARK_EVENT_DONE;
|
||||
iter->next.node = NULL;
|
||||
}
|
||||
|
||||
return ev_type;
|
||||
void cmark_iter_reset(cmark_iter *iter, cmark_node *current,
|
||||
cmark_event_type event_type) {
|
||||
iter->next.ev_type = event_type;
|
||||
iter->next.node = current;
|
||||
cmark_iter_next(iter);
|
||||
}
|
||||
|
||||
void
|
||||
cmark_iter_reset(cmark_iter *iter, cmark_node *current,
|
||||
cmark_event_type event_type)
|
||||
{
|
||||
iter->next.ev_type = event_type;
|
||||
iter->next.node = current;
|
||||
cmark_iter_next(iter);
|
||||
cmark_node *cmark_iter_get_node(cmark_iter *iter) { return iter->cur.node; }
|
||||
|
||||
cmark_event_type cmark_iter_get_event_type(cmark_iter *iter) {
|
||||
return iter->cur.ev_type;
|
||||
}
|
||||
|
||||
cmark_node*
|
||||
cmark_iter_get_node(cmark_iter *iter)
|
||||
{
|
||||
return iter->cur.node;
|
||||
}
|
||||
|
||||
cmark_event_type
|
||||
cmark_iter_get_event_type(cmark_iter *iter)
|
||||
{
|
||||
return iter->cur.ev_type;
|
||||
}
|
||||
|
||||
cmark_node*
|
||||
cmark_iter_get_root(cmark_iter *iter)
|
||||
{
|
||||
return iter->root;
|
||||
}
|
||||
|
||||
|
||||
void cmark_consolidate_text_nodes(cmark_node *root)
|
||||
{
|
||||
cmark_iter *iter = cmark_iter_new(root);
|
||||
cmark_strbuf buf = GH_BUF_INIT;
|
||||
cmark_event_type ev_type;
|
||||
cmark_node *cur, *tmp, *next;
|
||||
|
||||
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
||||
cur = cmark_iter_get_node(iter);
|
||||
if (ev_type == CMARK_EVENT_ENTER &&
|
||||
cur->type == CMARK_NODE_TEXT &&
|
||||
cur->next &&
|
||||
cur->next->type == CMARK_NODE_TEXT) {
|
||||
cmark_strbuf_clear(&buf);
|
||||
cmark_strbuf_put(&buf, cur->as.literal.data, cur->as.literal.len);
|
||||
tmp = cur->next;
|
||||
while (tmp && tmp->type == CMARK_NODE_TEXT) {
|
||||
cmark_iter_next(iter); // advance pointer
|
||||
cmark_strbuf_put(&buf, tmp->as.literal.data, tmp->as.literal.len);
|
||||
next = tmp->next;
|
||||
cmark_node_free(tmp);
|
||||
tmp = next;
|
||||
}
|
||||
cmark_chunk_free(&cur->as.literal);
|
||||
cur->as.literal = cmark_chunk_buf_detach(&buf);
|
||||
}
|
||||
}
|
||||
|
||||
cmark_strbuf_free(&buf);
|
||||
cmark_iter_free(iter);
|
||||
cmark_node *cmark_iter_get_root(cmark_iter *iter) { return iter->root; }
|
||||
|
||||
void cmark_consolidate_text_nodes(cmark_node *root) {
|
||||
cmark_iter *iter = cmark_iter_new(root);
|
||||
cmark_strbuf buf = GH_BUF_INIT;
|
||||
cmark_event_type ev_type;
|
||||
cmark_node *cur, *tmp, *next;
|
||||
|
||||
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
||||
cur = cmark_iter_get_node(iter);
|
||||
if (ev_type == CMARK_EVENT_ENTER && cur->type == CMARK_NODE_TEXT &&
|
||||
cur->next && cur->next->type == CMARK_NODE_TEXT) {
|
||||
cmark_strbuf_clear(&buf);
|
||||
cmark_strbuf_put(&buf, cur->as.literal.data, cur->as.literal.len);
|
||||
tmp = cur->next;
|
||||
while (tmp && tmp->type == CMARK_NODE_TEXT) {
|
||||
cmark_iter_next(iter); // advance pointer
|
||||
cmark_strbuf_put(&buf, tmp->as.literal.data, tmp->as.literal.len);
|
||||
next = tmp->next;
|
||||
cmark_node_free(tmp);
|
||||
tmp = next;
|
||||
}
|
||||
cmark_chunk_free(&cur->as.literal);
|
||||
cur->as.literal = cmark_chunk_buf_detach(&buf);
|
||||
}
|
||||
}
|
||||
|
||||
cmark_strbuf_free(&buf);
|
||||
cmark_iter_free(iter);
|
||||
}
|
||||
|
|
|
@ -8,14 +8,14 @@ extern "C" {
|
|||
#include "cmark.h"
|
||||
|
||||
typedef struct {
|
||||
cmark_event_type ev_type;
|
||||
cmark_node *node;
|
||||
cmark_event_type ev_type;
|
||||
cmark_node *node;
|
||||
} cmark_iter_state;
|
||||
|
||||
struct cmark_iter {
|
||||
cmark_node *root;
|
||||
cmark_iter_state cur;
|
||||
cmark_iter_state next;
|
||||
cmark_node *root;
|
||||
cmark_iter_state cur;
|
||||
cmark_iter_state next;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
722
src/latex.c
722
src/latex.c
|
@ -18,413 +18,391 @@
|
|||
#define CR() renderer->cr(renderer)
|
||||
#define BLANKLINE() renderer->blankline(renderer)
|
||||
|
||||
static inline void outc(cmark_renderer *renderer,
|
||||
cmark_escaping escape,
|
||||
int32_t c,
|
||||
unsigned char nextc)
|
||||
{
|
||||
if (escape == LITERAL) {
|
||||
cmark_render_code_point(renderer, c);
|
||||
return;
|
||||
}
|
||||
static inline void outc(cmark_renderer *renderer, cmark_escaping escape,
|
||||
int32_t c, unsigned char nextc) {
|
||||
if (escape == LITERAL) {
|
||||
cmark_render_code_point(renderer, c);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(c) {
|
||||
case 123: // '{'
|
||||
case 125: // '}'
|
||||
case 35: // '#'
|
||||
case 37: // '%'
|
||||
case 38: // '&'
|
||||
cmark_render_ascii(renderer, "\\");
|
||||
cmark_render_code_point(renderer, c);
|
||||
break;
|
||||
case 36: // '$'
|
||||
case 95: // '_'
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "\\");
|
||||
}
|
||||
cmark_render_code_point(renderer, c);
|
||||
break;
|
||||
case 45 : // '-'
|
||||
if (nextc == 45) { // prevent ligature
|
||||
cmark_render_ascii(renderer, "\\-");
|
||||
} else {
|
||||
cmark_render_ascii(renderer, "-");
|
||||
}
|
||||
break;
|
||||
case 126: // '~'
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "\\textasciitilde{}");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 94: // '^'
|
||||
cmark_render_ascii(renderer, "\\^{}");
|
||||
break;
|
||||
case 92: // '\\'
|
||||
if (escape == URL) {
|
||||
// / acts as path sep even on windows:
|
||||
cmark_render_ascii(renderer, "/");
|
||||
} else {
|
||||
cmark_render_ascii(renderer, "\\textbackslash{}");
|
||||
}
|
||||
break;
|
||||
case 124: // '|'
|
||||
cmark_render_ascii(renderer, "\\textbar{}");
|
||||
break;
|
||||
case 60: // '<'
|
||||
cmark_render_ascii(renderer, "\\textless{}");
|
||||
break;
|
||||
case 62: // '>'
|
||||
cmark_render_ascii(renderer, "\\textgreater{}");
|
||||
break;
|
||||
case 91: // '['
|
||||
case 93: // ']'
|
||||
cmark_render_ascii(renderer, "{");
|
||||
cmark_render_code_point(renderer, c);
|
||||
cmark_render_ascii(renderer, "}");
|
||||
break;
|
||||
case 34: // '"'
|
||||
cmark_render_ascii(renderer, "\\textquotedbl{}");
|
||||
// requires \usepackage[T1]{fontenc}
|
||||
break;
|
||||
case 39: // '\''
|
||||
cmark_render_ascii(renderer, "\\textquotesingle{}");
|
||||
// requires \usepackage{textcomp}
|
||||
break;
|
||||
case 160: // nbsp
|
||||
cmark_render_ascii(renderer, "~");
|
||||
break;
|
||||
case 8230: // hellip
|
||||
cmark_render_ascii(renderer, "\\ldots{}");
|
||||
break;
|
||||
case 8216: // lsquo
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "`");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 8217: // rsquo
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "\'");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 8220: // ldquo
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "``");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 8221: // rdquo
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "''");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 8212: // emdash
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "---");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 8211: // endash
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "--");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
switch (c) {
|
||||
case 123: // '{'
|
||||
case 125: // '}'
|
||||
case 35: // '#'
|
||||
case 37: // '%'
|
||||
case 38: // '&'
|
||||
cmark_render_ascii(renderer, "\\");
|
||||
cmark_render_code_point(renderer, c);
|
||||
break;
|
||||
case 36: // '$'
|
||||
case 95: // '_'
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "\\");
|
||||
}
|
||||
cmark_render_code_point(renderer, c);
|
||||
break;
|
||||
case 45: // '-'
|
||||
if (nextc == 45) { // prevent ligature
|
||||
cmark_render_ascii(renderer, "\\-");
|
||||
} else {
|
||||
cmark_render_ascii(renderer, "-");
|
||||
}
|
||||
break;
|
||||
case 126: // '~'
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "\\textasciitilde{}");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 94: // '^'
|
||||
cmark_render_ascii(renderer, "\\^{}");
|
||||
break;
|
||||
case 92: // '\\'
|
||||
if (escape == URL) {
|
||||
// / acts as path sep even on windows:
|
||||
cmark_render_ascii(renderer, "/");
|
||||
} else {
|
||||
cmark_render_ascii(renderer, "\\textbackslash{}");
|
||||
}
|
||||
break;
|
||||
case 124: // '|'
|
||||
cmark_render_ascii(renderer, "\\textbar{}");
|
||||
break;
|
||||
case 60: // '<'
|
||||
cmark_render_ascii(renderer, "\\textless{}");
|
||||
break;
|
||||
case 62: // '>'
|
||||
cmark_render_ascii(renderer, "\\textgreater{}");
|
||||
break;
|
||||
case 91: // '['
|
||||
case 93: // ']'
|
||||
cmark_render_ascii(renderer, "{");
|
||||
cmark_render_code_point(renderer, c);
|
||||
cmark_render_ascii(renderer, "}");
|
||||
break;
|
||||
case 34: // '"'
|
||||
cmark_render_ascii(renderer, "\\textquotedbl{}");
|
||||
// requires \usepackage[T1]{fontenc}
|
||||
break;
|
||||
case 39: // '\''
|
||||
cmark_render_ascii(renderer, "\\textquotesingle{}");
|
||||
// requires \usepackage{textcomp}
|
||||
break;
|
||||
case 160: // nbsp
|
||||
cmark_render_ascii(renderer, "~");
|
||||
break;
|
||||
case 8230: // hellip
|
||||
cmark_render_ascii(renderer, "\\ldots{}");
|
||||
break;
|
||||
case 8216: // lsquo
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "`");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 8217: // rsquo
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "\'");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 8220: // ldquo
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "``");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 8221: // rdquo
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "''");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 8212: // emdash
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "---");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 8211: // endash
|
||||
if (escape == NORMAL) {
|
||||
cmark_render_ascii(renderer, "--");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
NO_LINK,
|
||||
URL_AUTOLINK,
|
||||
EMAIL_AUTOLINK,
|
||||
NORMAL_LINK
|
||||
} link_type;
|
||||
typedef enum { NO_LINK, URL_AUTOLINK, EMAIL_AUTOLINK, NORMAL_LINK } link_type;
|
||||
|
||||
static link_type
|
||||
get_link_type(cmark_node *node)
|
||||
{
|
||||
size_t title_len, url_len;
|
||||
cmark_node *link_text;
|
||||
char *realurl;
|
||||
int realurllen;
|
||||
bool isemail = false;
|
||||
static link_type get_link_type(cmark_node *node) {
|
||||
size_t title_len, url_len;
|
||||
cmark_node *link_text;
|
||||
char *realurl;
|
||||
int realurllen;
|
||||
bool isemail = false;
|
||||
|
||||
if (node->type != CMARK_NODE_LINK) {
|
||||
return NO_LINK;
|
||||
}
|
||||
if (node->type != CMARK_NODE_LINK) {
|
||||
return NO_LINK;
|
||||
}
|
||||
|
||||
const char* url = cmark_node_get_url(node);
|
||||
cmark_chunk url_chunk = cmark_chunk_literal(url);
|
||||
const char *url = cmark_node_get_url(node);
|
||||
cmark_chunk url_chunk = cmark_chunk_literal(url);
|
||||
|
||||
url_len = safe_strlen(url);
|
||||
if (url_len == 0 || scan_scheme(&url_chunk, 0) == 0) {
|
||||
return NO_LINK;
|
||||
}
|
||||
url_len = safe_strlen(url);
|
||||
if (url_len == 0 || scan_scheme(&url_chunk, 0) == 0) {
|
||||
return NO_LINK;
|
||||
}
|
||||
|
||||
const char* title = cmark_node_get_title(node);
|
||||
title_len = safe_strlen(title);
|
||||
// if it has a title, we can't treat it as an autolink:
|
||||
if (title_len > 0) {
|
||||
return NORMAL_LINK;
|
||||
}
|
||||
const char *title = cmark_node_get_title(node);
|
||||
title_len = safe_strlen(title);
|
||||
// if it has a title, we can't treat it as an autolink:
|
||||
if (title_len > 0) {
|
||||
return NORMAL_LINK;
|
||||
}
|
||||
|
||||
link_text = node->first_child;
|
||||
cmark_consolidate_text_nodes(link_text);
|
||||
realurl = (char*)url;
|
||||
realurllen = url_len;
|
||||
if (strncmp(realurl, "mailto:", 7) == 0) {
|
||||
realurl += 7;
|
||||
realurllen -= 7;
|
||||
isemail = true;
|
||||
}
|
||||
if (realurllen == link_text->as.literal.len &&
|
||||
strncmp(realurl,
|
||||
(char*)link_text->as.literal.data,
|
||||
link_text->as.literal.len) == 0) {
|
||||
if (isemail) {
|
||||
return EMAIL_AUTOLINK;
|
||||
} else {
|
||||
return URL_AUTOLINK;
|
||||
}
|
||||
} else {
|
||||
return NORMAL_LINK;
|
||||
}
|
||||
link_text = node->first_child;
|
||||
cmark_consolidate_text_nodes(link_text);
|
||||
realurl = (char *)url;
|
||||
realurllen = url_len;
|
||||
if (strncmp(realurl, "mailto:", 7) == 0) {
|
||||
realurl += 7;
|
||||
realurllen -= 7;
|
||||
isemail = true;
|
||||
}
|
||||
if (realurllen == link_text->as.literal.len &&
|
||||
strncmp(realurl, (char *)link_text->as.literal.data,
|
||||
link_text->as.literal.len) == 0) {
|
||||
if (isemail) {
|
||||
return EMAIL_AUTOLINK;
|
||||
} else {
|
||||
return URL_AUTOLINK;
|
||||
}
|
||||
} else {
|
||||
return NORMAL_LINK;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
S_get_enumlevel(cmark_node *node)
|
||||
{
|
||||
int enumlevel = 0;
|
||||
cmark_node *tmp = node;
|
||||
while (tmp) {
|
||||
if (tmp->type == CMARK_NODE_LIST &&
|
||||
cmark_node_get_list_type(node) == CMARK_ORDERED_LIST) {
|
||||
enumlevel++;
|
||||
}
|
||||
tmp = tmp->parent;
|
||||
}
|
||||
return enumlevel;
|
||||
static int S_get_enumlevel(cmark_node *node) {
|
||||
int enumlevel = 0;
|
||||
cmark_node *tmp = node;
|
||||
while (tmp) {
|
||||
if (tmp->type == CMARK_NODE_LIST &&
|
||||
cmark_node_get_list_type(node) == CMARK_ORDERED_LIST) {
|
||||
enumlevel++;
|
||||
}
|
||||
tmp = tmp->parent;
|
||||
}
|
||||
return enumlevel;
|
||||
}
|
||||
|
||||
static int
|
||||
S_render_node(cmark_renderer *renderer,
|
||||
cmark_node *node,
|
||||
cmark_event_type ev_type,
|
||||
int options)
|
||||
{
|
||||
int list_number;
|
||||
char list_number_string[20];
|
||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||
cmark_list_type list_type;
|
||||
const char* roman_numerals[] = { "", "i", "ii", "iii", "iv", "v",
|
||||
"vi", "vii", "viii", "ix", "x"
|
||||
};
|
||||
static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
||||
cmark_event_type ev_type, int options) {
|
||||
int list_number;
|
||||
char list_number_string[20];
|
||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||
cmark_list_type list_type;
|
||||
const char *roman_numerals[] = {"", "i", "ii", "iii", "iv", "v",
|
||||
"vi", "vii", "viii", "ix", "x"};
|
||||
|
||||
// avoid warning about unused parameter:
|
||||
(void)(options);
|
||||
// avoid warning about unused parameter:
|
||||
(void)(options);
|
||||
|
||||
switch (node->type) {
|
||||
case CMARK_NODE_DOCUMENT:
|
||||
break;
|
||||
switch (node->type) {
|
||||
case CMARK_NODE_DOCUMENT:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_BLOCK_QUOTE:
|
||||
if (entering) {
|
||||
LIT("\\begin{quote}");
|
||||
CR();
|
||||
} else {
|
||||
LIT("\\end{quote}");
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_BLOCK_QUOTE:
|
||||
if (entering) {
|
||||
LIT("\\begin{quote}");
|
||||
CR();
|
||||
} else {
|
||||
LIT("\\end{quote}");
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LIST:
|
||||
list_type = cmark_node_get_list_type(node);
|
||||
if (entering) {
|
||||
LIT("\\begin{");
|
||||
LIT(list_type == CMARK_ORDERED_LIST ?
|
||||
"enumerate" : "itemize");
|
||||
LIT("}");
|
||||
CR();
|
||||
list_number = cmark_node_get_list_start(node);
|
||||
if (list_number > 1) {
|
||||
sprintf(list_number_string,
|
||||
"%d", list_number);
|
||||
LIT("\\setcounter{enum");
|
||||
LIT((char *)roman_numerals[S_get_enumlevel(node)]);
|
||||
LIT("}{");
|
||||
OUT(list_number_string, false, NORMAL);
|
||||
LIT("}");
|
||||
CR();
|
||||
}
|
||||
} else {
|
||||
LIT("\\end{");
|
||||
LIT(list_type == CMARK_ORDERED_LIST ?
|
||||
"enumerate" : "itemize");
|
||||
LIT("}");
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_LIST:
|
||||
list_type = cmark_node_get_list_type(node);
|
||||
if (entering) {
|
||||
LIT("\\begin{");
|
||||
LIT(list_type == CMARK_ORDERED_LIST ? "enumerate" : "itemize");
|
||||
LIT("}");
|
||||
CR();
|
||||
list_number = cmark_node_get_list_start(node);
|
||||
if (list_number > 1) {
|
||||
sprintf(list_number_string, "%d", list_number);
|
||||
LIT("\\setcounter{enum");
|
||||
LIT((char *)roman_numerals[S_get_enumlevel(node)]);
|
||||
LIT("}{");
|
||||
OUT(list_number_string, false, NORMAL);
|
||||
LIT("}");
|
||||
CR();
|
||||
}
|
||||
} else {
|
||||
LIT("\\end{");
|
||||
LIT(list_type == CMARK_ORDERED_LIST ? "enumerate" : "itemize");
|
||||
LIT("}");
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_ITEM:
|
||||
if (entering) {
|
||||
LIT("\\item ");
|
||||
} else {
|
||||
CR();
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_ITEM:
|
||||
if (entering) {
|
||||
LIT("\\item ");
|
||||
} else {
|
||||
CR();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HEADER:
|
||||
if (entering) {
|
||||
switch (cmark_node_get_header_level(node)) {
|
||||
case 1:
|
||||
LIT("\\section");
|
||||
break;
|
||||
case 2:
|
||||
LIT("\\subsection");
|
||||
break;
|
||||
case 3:
|
||||
LIT("\\subsubsection");
|
||||
break;
|
||||
case 4:
|
||||
LIT("\\paragraph");
|
||||
break;
|
||||
case 5:
|
||||
LIT("\\subparagraph");
|
||||
break;
|
||||
}
|
||||
LIT("{");
|
||||
} else {
|
||||
LIT("}");
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_HEADER:
|
||||
if (entering) {
|
||||
switch (cmark_node_get_header_level(node)) {
|
||||
case 1:
|
||||
LIT("\\section");
|
||||
break;
|
||||
case 2:
|
||||
LIT("\\subsection");
|
||||
break;
|
||||
case 3:
|
||||
LIT("\\subsubsection");
|
||||
break;
|
||||
case 4:
|
||||
LIT("\\paragraph");
|
||||
break;
|
||||
case 5:
|
||||
LIT("\\subparagraph");
|
||||
break;
|
||||
}
|
||||
LIT("{");
|
||||
} else {
|
||||
LIT("}");
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CODE_BLOCK:
|
||||
CR();
|
||||
LIT("\\begin{verbatim}");
|
||||
CR();
|
||||
OUT(cmark_node_get_literal(node), false, LITERAL);
|
||||
CR();
|
||||
LIT("\\end{verbatim}");
|
||||
BLANKLINE();
|
||||
break;
|
||||
case CMARK_NODE_CODE_BLOCK:
|
||||
CR();
|
||||
LIT("\\begin{verbatim}");
|
||||
CR();
|
||||
OUT(cmark_node_get_literal(node), false, LITERAL);
|
||||
CR();
|
||||
LIT("\\end{verbatim}");
|
||||
BLANKLINE();
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HTML:
|
||||
break;
|
||||
case CMARK_NODE_HTML:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HRULE:
|
||||
BLANKLINE();
|
||||
LIT("\\begin{center}\\rule{0.5\\linewidth}{\\linethickness}\\end{center}");
|
||||
BLANKLINE();
|
||||
break;
|
||||
case CMARK_NODE_HRULE:
|
||||
BLANKLINE();
|
||||
LIT("\\begin{center}\\rule{0.5\\linewidth}{\\linethickness}\\end{center}");
|
||||
BLANKLINE();
|
||||
break;
|
||||
|
||||
case CMARK_NODE_PARAGRAPH:
|
||||
if (!entering) {
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_PARAGRAPH:
|
||||
if (!entering) {
|
||||
BLANKLINE();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_TEXT:
|
||||
OUT(cmark_node_get_literal(node), true, NORMAL);
|
||||
break;
|
||||
case CMARK_NODE_TEXT:
|
||||
OUT(cmark_node_get_literal(node), true, NORMAL);
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LINEBREAK:
|
||||
LIT("\\\\");
|
||||
CR();
|
||||
break;
|
||||
case CMARK_NODE_LINEBREAK:
|
||||
LIT("\\\\");
|
||||
CR();
|
||||
break;
|
||||
|
||||
case CMARK_NODE_SOFTBREAK:
|
||||
if (renderer->width == 0) {
|
||||
CR();
|
||||
} else {
|
||||
OUT(" ", true, NORMAL);
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_SOFTBREAK:
|
||||
if (renderer->width == 0) {
|
||||
CR();
|
||||
} else {
|
||||
OUT(" ", true, NORMAL);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CODE:
|
||||
LIT("\\texttt{");
|
||||
OUT(cmark_node_get_literal(node), false, NORMAL);
|
||||
LIT("}");
|
||||
break;
|
||||
case CMARK_NODE_CODE:
|
||||
LIT("\\texttt{");
|
||||
OUT(cmark_node_get_literal(node), false, NORMAL);
|
||||
LIT("}");
|
||||
break;
|
||||
|
||||
case CMARK_NODE_INLINE_HTML:
|
||||
break;
|
||||
case CMARK_NODE_INLINE_HTML:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_STRONG:
|
||||
if (entering) {
|
||||
LIT("\\textbf{");
|
||||
} else {
|
||||
LIT("}");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_STRONG:
|
||||
if (entering) {
|
||||
LIT("\\textbf{");
|
||||
} else {
|
||||
LIT("}");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_EMPH:
|
||||
if (entering) {
|
||||
LIT("\\emph{");
|
||||
} else {
|
||||
LIT("}");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_EMPH:
|
||||
if (entering) {
|
||||
LIT("\\emph{");
|
||||
} else {
|
||||
LIT("}");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LINK:
|
||||
if (entering) {
|
||||
const char* url = cmark_node_get_url(node);
|
||||
// requires \usepackage{hyperref}
|
||||
switch(get_link_type(node)) {
|
||||
case URL_AUTOLINK:
|
||||
LIT("\\url{");
|
||||
OUT(url, false, URL);
|
||||
break;
|
||||
case EMAIL_AUTOLINK:
|
||||
LIT("\\href{");
|
||||
OUT(url, false, URL);
|
||||
LIT("}\\nolinkurl{");
|
||||
break;
|
||||
case NORMAL_LINK:
|
||||
LIT("\\href{");
|
||||
OUT(url, false, URL);
|
||||
LIT("}{");
|
||||
break;
|
||||
case NO_LINK:
|
||||
LIT("{"); // error?
|
||||
}
|
||||
} else {
|
||||
LIT("}");
|
||||
}
|
||||
case CMARK_NODE_LINK:
|
||||
if (entering) {
|
||||
const char *url = cmark_node_get_url(node);
|
||||
// requires \usepackage{hyperref}
|
||||
switch (get_link_type(node)) {
|
||||
case URL_AUTOLINK:
|
||||
LIT("\\url{");
|
||||
OUT(url, false, URL);
|
||||
break;
|
||||
case EMAIL_AUTOLINK:
|
||||
LIT("\\href{");
|
||||
OUT(url, false, URL);
|
||||
LIT("}\\nolinkurl{");
|
||||
break;
|
||||
case NORMAL_LINK:
|
||||
LIT("\\href{");
|
||||
OUT(url, false, URL);
|
||||
LIT("}{");
|
||||
break;
|
||||
case NO_LINK:
|
||||
LIT("{"); // error?
|
||||
}
|
||||
} else {
|
||||
LIT("}");
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case CMARK_NODE_IMAGE:
|
||||
if (entering) {
|
||||
LIT("\\protect\\includegraphics{");
|
||||
// requires \include{graphicx}
|
||||
OUT(cmark_node_get_url(node), false, URL);
|
||||
LIT("}");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_IMAGE:
|
||||
if (entering) {
|
||||
LIT("\\protect\\includegraphics{");
|
||||
// requires \include{graphicx}
|
||||
OUT(cmark_node_get_url(node), false, URL);
|
||||
LIT("}");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *cmark_render_latex(cmark_node *root, int options, int width)
|
||||
{
|
||||
return cmark_render(root, options, width, outc, S_render_node);
|
||||
char *cmark_render_latex(cmark_node *root, int options, int width) {
|
||||
return cmark_render(root, options, width, outc, S_render_node);
|
||||
}
|
||||
|
|
319
src/main.c
319
src/main.c
|
@ -12,190 +12,183 @@
|
|||
#endif
|
||||
|
||||
typedef enum {
|
||||
FORMAT_NONE,
|
||||
FORMAT_HTML,
|
||||
FORMAT_XML,
|
||||
FORMAT_MAN,
|
||||
FORMAT_COMMONMARK,
|
||||
FORMAT_LATEX
|
||||
FORMAT_NONE,
|
||||
FORMAT_HTML,
|
||||
FORMAT_XML,
|
||||
FORMAT_MAN,
|
||||
FORMAT_COMMONMARK,
|
||||
FORMAT_LATEX
|
||||
} writer_format;
|
||||
|
||||
void print_usage()
|
||||
{
|
||||
printf("Usage: cmark [FILE*]\n");
|
||||
printf("Options:\n");
|
||||
printf(" --to, -t FORMAT Specify output format (html, xml, man, commonmark, latex)\n");
|
||||
printf(" --width WIDTH Specify wrap width (default 0 = nowrap)\n");
|
||||
printf(" --sourcepos Include source position attribute\n");
|
||||
printf(" --hardbreaks Treat newlines as hard line breaks\n");
|
||||
printf(" --safe Suppress raw HTML and dangerous URLs\n");
|
||||
printf(" --smart Use smart punctuation\n");
|
||||
printf(" --normalize Consolidate adjacent text nodes\n");
|
||||
printf(" --help, -h Print usage information\n");
|
||||
printf(" --version Print version\n");
|
||||
void print_usage() {
|
||||
printf("Usage: cmark [FILE*]\n");
|
||||
printf("Options:\n");
|
||||
printf(" --to, -t FORMAT Specify output format (html, xml, man, "
|
||||
"commonmark, latex)\n");
|
||||
printf(" --width WIDTH Specify wrap width (default 0 = nowrap)\n");
|
||||
printf(" --sourcepos Include source position attribute\n");
|
||||
printf(" --hardbreaks Treat newlines as hard line breaks\n");
|
||||
printf(" --safe Suppress raw HTML and dangerous URLs\n");
|
||||
printf(" --smart Use smart punctuation\n");
|
||||
printf(" --normalize Consolidate adjacent text nodes\n");
|
||||
printf(" --help, -h Print usage information\n");
|
||||
printf(" --version Print version\n");
|
||||
}
|
||||
|
||||
static void print_document(cmark_node *document, writer_format writer,
|
||||
int options, int width)
|
||||
{
|
||||
char *result;
|
||||
int options, int width) {
|
||||
char *result;
|
||||
|
||||
switch (writer) {
|
||||
case FORMAT_HTML:
|
||||
result = cmark_render_html(document, options);
|
||||
break;
|
||||
case FORMAT_XML:
|
||||
result = cmark_render_xml(document, options);
|
||||
break;
|
||||
case FORMAT_MAN:
|
||||
result = cmark_render_man(document, options, width);
|
||||
break;
|
||||
case FORMAT_COMMONMARK:
|
||||
result = cmark_render_commonmark(document, options, width);
|
||||
break;
|
||||
case FORMAT_LATEX:
|
||||
result = cmark_render_latex(document, options, width);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown format %d\n", writer);
|
||||
exit(1);
|
||||
}
|
||||
printf("%s", result);
|
||||
free(result);
|
||||
switch (writer) {
|
||||
case FORMAT_HTML:
|
||||
result = cmark_render_html(document, options);
|
||||
break;
|
||||
case FORMAT_XML:
|
||||
result = cmark_render_xml(document, options);
|
||||
break;
|
||||
case FORMAT_MAN:
|
||||
result = cmark_render_man(document, options, width);
|
||||
break;
|
||||
case FORMAT_COMMONMARK:
|
||||
result = cmark_render_commonmark(document, options, width);
|
||||
break;
|
||||
case FORMAT_LATEX:
|
||||
result = cmark_render_latex(document, options, width);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown format %d\n", writer);
|
||||
exit(1);
|
||||
}
|
||||
printf("%s", result);
|
||||
free(result);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, numfps = 0;
|
||||
int *files;
|
||||
char buffer[4096];
|
||||
cmark_parser *parser;
|
||||
size_t bytes;
|
||||
cmark_node *document;
|
||||
int width = 0;
|
||||
char *unparsed;
|
||||
writer_format writer = FORMAT_HTML;
|
||||
int options = CMARK_OPT_DEFAULT;
|
||||
int main(int argc, char *argv[]) {
|
||||
int i, numfps = 0;
|
||||
int *files;
|
||||
char buffer[4096];
|
||||
cmark_parser *parser;
|
||||
size_t bytes;
|
||||
cmark_node *document;
|
||||
int width = 0;
|
||||
char *unparsed;
|
||||
writer_format writer = FORMAT_HTML;
|
||||
int options = CMARK_OPT_DEFAULT;
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
_setmode(_fileno(stdout), _O_BINARY);
|
||||
_setmode(_fileno(stdout), _O_BINARY);
|
||||
#endif
|
||||
|
||||
files = (int *)malloc(argc * sizeof(*files));
|
||||
files = (int *)malloc(argc * sizeof(*files));
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--version") == 0) {
|
||||
printf("cmark %s", CMARK_VERSION_STRING);
|
||||
printf(" - CommonMark converter\n(C) 2014, 2015 John MacFarlane\n");
|
||||
exit(0);
|
||||
} else if (strcmp(argv[i], "--sourcepos") == 0) {
|
||||
options |= CMARK_OPT_SOURCEPOS;
|
||||
} else if (strcmp(argv[i], "--hardbreaks") == 0) {
|
||||
options |= CMARK_OPT_HARDBREAKS;
|
||||
} else if (strcmp(argv[i], "--smart") == 0) {
|
||||
options |= CMARK_OPT_SMART;
|
||||
} else if (strcmp(argv[i], "--safe") == 0) {
|
||||
options |= CMARK_OPT_SAFE;
|
||||
} else if (strcmp(argv[i], "--normalize") == 0) {
|
||||
options |= CMARK_OPT_NORMALIZE;
|
||||
} else if (strcmp(argv[i], "--validate-utf8") == 0) {
|
||||
options |= CMARK_OPT_VALIDATE_UTF8;
|
||||
} else if ((strcmp(argv[i], "--help") == 0) ||
|
||||
(strcmp(argv[i], "-h") == 0)) {
|
||||
print_usage();
|
||||
exit(0);
|
||||
} else if (strcmp(argv[i], "--width") == 0) {
|
||||
i += 1;
|
||||
if (i < argc) {
|
||||
width = (int)strtol(argv[i], &unparsed, 10);
|
||||
if (unparsed && strlen(unparsed) > 0) {
|
||||
fprintf(stderr,
|
||||
"failed parsing width '%s' at '%s'\n",
|
||||
argv[i], unparsed);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"--width requires an argument\n");
|
||||
exit(1);
|
||||
}
|
||||
} else if ((strcmp(argv[i], "-t") == 0) ||
|
||||
(strcmp(argv[i], "--to") == 0)) {
|
||||
i += 1;
|
||||
if (i < argc) {
|
||||
if (strcmp(argv[i], "man") == 0) {
|
||||
writer = FORMAT_MAN;
|
||||
} else if (strcmp(argv[i], "html") == 0) {
|
||||
writer = FORMAT_HTML;
|
||||
} else if (strcmp(argv[i], "xml") == 0) {
|
||||
writer = FORMAT_XML;
|
||||
} else if (strcmp(argv[i], "commonmark") == 0) {
|
||||
writer = FORMAT_COMMONMARK;
|
||||
} else if (strcmp(argv[i], "latex") == 0) {
|
||||
writer = FORMAT_LATEX;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Unknown format %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "No argument provided for %s\n",
|
||||
argv[i - 1]);
|
||||
exit(1);
|
||||
}
|
||||
} else if (*argv[i] == '-') {
|
||||
print_usage();
|
||||
exit(1);
|
||||
} else { // treat as file argument
|
||||
files[numfps++] = i;
|
||||
}
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--version") == 0) {
|
||||
printf("cmark %s", CMARK_VERSION_STRING);
|
||||
printf(" - CommonMark converter\n(C) 2014, 2015 John MacFarlane\n");
|
||||
exit(0);
|
||||
} else if (strcmp(argv[i], "--sourcepos") == 0) {
|
||||
options |= CMARK_OPT_SOURCEPOS;
|
||||
} else if (strcmp(argv[i], "--hardbreaks") == 0) {
|
||||
options |= CMARK_OPT_HARDBREAKS;
|
||||
} else if (strcmp(argv[i], "--smart") == 0) {
|
||||
options |= CMARK_OPT_SMART;
|
||||
} else if (strcmp(argv[i], "--safe") == 0) {
|
||||
options |= CMARK_OPT_SAFE;
|
||||
} else if (strcmp(argv[i], "--normalize") == 0) {
|
||||
options |= CMARK_OPT_NORMALIZE;
|
||||
} else if (strcmp(argv[i], "--validate-utf8") == 0) {
|
||||
options |= CMARK_OPT_VALIDATE_UTF8;
|
||||
} else if ((strcmp(argv[i], "--help") == 0) ||
|
||||
(strcmp(argv[i], "-h") == 0)) {
|
||||
print_usage();
|
||||
exit(0);
|
||||
} else if (strcmp(argv[i], "--width") == 0) {
|
||||
i += 1;
|
||||
if (i < argc) {
|
||||
width = (int)strtol(argv[i], &unparsed, 10);
|
||||
if (unparsed && strlen(unparsed) > 0) {
|
||||
fprintf(stderr, "failed parsing width '%s' at '%s'\n", argv[i],
|
||||
unparsed);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "--width requires an argument\n");
|
||||
exit(1);
|
||||
}
|
||||
} else if ((strcmp(argv[i], "-t") == 0) || (strcmp(argv[i], "--to") == 0)) {
|
||||
i += 1;
|
||||
if (i < argc) {
|
||||
if (strcmp(argv[i], "man") == 0) {
|
||||
writer = FORMAT_MAN;
|
||||
} else if (strcmp(argv[i], "html") == 0) {
|
||||
writer = FORMAT_HTML;
|
||||
} else if (strcmp(argv[i], "xml") == 0) {
|
||||
writer = FORMAT_XML;
|
||||
} else if (strcmp(argv[i], "commonmark") == 0) {
|
||||
writer = FORMAT_COMMONMARK;
|
||||
} else if (strcmp(argv[i], "latex") == 0) {
|
||||
writer = FORMAT_LATEX;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown format %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "No argument provided for %s\n", argv[i - 1]);
|
||||
exit(1);
|
||||
}
|
||||
} else if (*argv[i] == '-') {
|
||||
print_usage();
|
||||
exit(1);
|
||||
} else { // treat as file argument
|
||||
files[numfps++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
parser = cmark_parser_new(options);
|
||||
for (i = 0; i < numfps; i++) {
|
||||
FILE *fp = fopen(argv[files[i]], "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "Error opening file %s: %s\n",
|
||||
argv[files[i]], strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
parser = cmark_parser_new(options);
|
||||
for (i = 0; i < numfps; i++) {
|
||||
FILE *fp = fopen(argv[files[i]], "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "Error opening file %s: %s\n", argv[files[i]],
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
start_timer();
|
||||
while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
|
||||
cmark_parser_feed(parser, buffer, bytes);
|
||||
if (bytes < sizeof(buffer)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
end_timer("processing lines");
|
||||
start_timer();
|
||||
while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
|
||||
cmark_parser_feed(parser, buffer, bytes);
|
||||
if (bytes < sizeof(buffer)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
end_timer("processing lines");
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (numfps == 0) {
|
||||
if (numfps == 0) {
|
||||
|
||||
while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
|
||||
cmark_parser_feed(parser, buffer, bytes);
|
||||
if (bytes < sizeof(buffer)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
|
||||
cmark_parser_feed(parser, buffer, bytes);
|
||||
if (bytes < sizeof(buffer)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start_timer();
|
||||
document = cmark_parser_finish(parser);
|
||||
end_timer("finishing document");
|
||||
cmark_parser_free(parser);
|
||||
start_timer();
|
||||
document = cmark_parser_finish(parser);
|
||||
end_timer("finishing document");
|
||||
cmark_parser_free(parser);
|
||||
|
||||
start_timer();
|
||||
print_document(document, writer, options, width);
|
||||
end_timer("print_document");
|
||||
start_timer();
|
||||
print_document(document, writer, options, width);
|
||||
end_timer("print_document");
|
||||
|
||||
start_timer();
|
||||
cmark_node_free(document);
|
||||
end_timer("free_blocks");
|
||||
start_timer();
|
||||
cmark_node_free(document);
|
||||
end_timer("free_blocks");
|
||||
|
||||
free(files);
|
||||
free(files);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
392
src/man.c
392
src/man.c
|
@ -16,234 +16,220 @@
|
|||
#define BLANKLINE() renderer->blankline(renderer)
|
||||
|
||||
// Functions to convert cmark_nodes to groff man strings.
|
||||
static
|
||||
void S_outc(cmark_renderer *renderer,
|
||||
cmark_escaping escape,
|
||||
int32_t c,
|
||||
unsigned char nextc)
|
||||
{
|
||||
(void)(nextc);
|
||||
static void S_outc(cmark_renderer *renderer, cmark_escaping escape, int32_t c,
|
||||
unsigned char nextc) {
|
||||
(void)(nextc);
|
||||
|
||||
if (escape == LITERAL) {
|
||||
cmark_render_code_point(renderer, c);
|
||||
return;
|
||||
}
|
||||
if (escape == LITERAL) {
|
||||
cmark_render_code_point(renderer, c);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(c) {
|
||||
case 46:
|
||||
if (renderer->begin_line) {
|
||||
cmark_render_ascii(renderer, "\\&.");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 39:
|
||||
if (renderer->begin_line) {
|
||||
cmark_render_ascii(renderer, "\\&'");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 45:
|
||||
cmark_render_ascii(renderer, "\\-");
|
||||
break;
|
||||
case 92:
|
||||
cmark_render_ascii(renderer, "\\e");
|
||||
break;
|
||||
case 8216: // left single quote
|
||||
cmark_render_ascii(renderer, "\\[oq]");
|
||||
break;
|
||||
case 8217: // right single quote
|
||||
cmark_render_ascii(renderer, "\\[cq]");
|
||||
break;
|
||||
case 8220: // left double quote
|
||||
cmark_render_ascii(renderer, "\\[lq]");
|
||||
break;
|
||||
case 8221: // right double quote
|
||||
cmark_render_ascii(renderer, "\\[rq]");
|
||||
break;
|
||||
case 8212: // em dash
|
||||
cmark_render_ascii(renderer, "\\[em]");
|
||||
break;
|
||||
case 8211: // en dash
|
||||
cmark_render_ascii(renderer, "\\[en]");
|
||||
break;
|
||||
default:
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
switch (c) {
|
||||
case 46:
|
||||
if (renderer->begin_line) {
|
||||
cmark_render_ascii(renderer, "\\&.");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 39:
|
||||
if (renderer->begin_line) {
|
||||
cmark_render_ascii(renderer, "\\&'");
|
||||
} else {
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
break;
|
||||
case 45:
|
||||
cmark_render_ascii(renderer, "\\-");
|
||||
break;
|
||||
case 92:
|
||||
cmark_render_ascii(renderer, "\\e");
|
||||
break;
|
||||
case 8216: // left single quote
|
||||
cmark_render_ascii(renderer, "\\[oq]");
|
||||
break;
|
||||
case 8217: // right single quote
|
||||
cmark_render_ascii(renderer, "\\[cq]");
|
||||
break;
|
||||
case 8220: // left double quote
|
||||
cmark_render_ascii(renderer, "\\[lq]");
|
||||
break;
|
||||
case 8221: // right double quote
|
||||
cmark_render_ascii(renderer, "\\[rq]");
|
||||
break;
|
||||
case 8212: // em dash
|
||||
cmark_render_ascii(renderer, "\\[em]");
|
||||
break;
|
||||
case 8211: // en dash
|
||||
cmark_render_ascii(renderer, "\\[en]");
|
||||
break;
|
||||
default:
|
||||
cmark_render_code_point(renderer, c);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
S_render_node(cmark_renderer *renderer,
|
||||
cmark_node *node,
|
||||
cmark_event_type ev_type,
|
||||
int options)
|
||||
{
|
||||
cmark_node *tmp;
|
||||
int list_number;
|
||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||
static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
||||
cmark_event_type ev_type, int options) {
|
||||
cmark_node *tmp;
|
||||
int list_number;
|
||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||
|
||||
// avoid unused parameter error:
|
||||
(void)(options);
|
||||
// avoid unused parameter error:
|
||||
(void)(options);
|
||||
|
||||
switch (node->type) {
|
||||
case CMARK_NODE_DOCUMENT:
|
||||
break;
|
||||
switch (node->type) {
|
||||
case CMARK_NODE_DOCUMENT:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_BLOCK_QUOTE:
|
||||
if (entering) {
|
||||
CR();
|
||||
LIT(".RS");
|
||||
CR();
|
||||
} else {
|
||||
CR();
|
||||
LIT(".RE");
|
||||
CR();
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_BLOCK_QUOTE:
|
||||
if (entering) {
|
||||
CR();
|
||||
LIT(".RS");
|
||||
CR();
|
||||
} else {
|
||||
CR();
|
||||
LIT(".RE");
|
||||
CR();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LIST:
|
||||
break;
|
||||
case CMARK_NODE_LIST:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_ITEM:
|
||||
if (entering) {
|
||||
CR();
|
||||
LIT(".IP ");
|
||||
if (cmark_node_get_list_type(node->parent) ==
|
||||
CMARK_BULLET_LIST) {
|
||||
LIT("\\[bu] 2");
|
||||
} else {
|
||||
list_number = cmark_node_get_list_start(node->parent);
|
||||
tmp = node;
|
||||
while (tmp->prev) {
|
||||
tmp = tmp->prev;
|
||||
list_number += 1;
|
||||
}
|
||||
char list_number_s[20];
|
||||
sprintf(list_number_s, "\"%d.\" 4", list_number);
|
||||
LIT(list_number_s);
|
||||
}
|
||||
CR();
|
||||
} else {
|
||||
CR();
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_ITEM:
|
||||
if (entering) {
|
||||
CR();
|
||||
LIT(".IP ");
|
||||
if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
|
||||
LIT("\\[bu] 2");
|
||||
} else {
|
||||
list_number = cmark_node_get_list_start(node->parent);
|
||||
tmp = node;
|
||||
while (tmp->prev) {
|
||||
tmp = tmp->prev;
|
||||
list_number += 1;
|
||||
}
|
||||
char list_number_s[20];
|
||||
sprintf(list_number_s, "\"%d.\" 4", list_number);
|
||||
LIT(list_number_s);
|
||||
}
|
||||
CR();
|
||||
} else {
|
||||
CR();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HEADER:
|
||||
if (entering) {
|
||||
CR();
|
||||
LIT(cmark_node_get_header_level(node) == 1 ?
|
||||
".SH" : ".SS");
|
||||
CR();
|
||||
} else {
|
||||
CR();
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_HEADER:
|
||||
if (entering) {
|
||||
CR();
|
||||
LIT(cmark_node_get_header_level(node) == 1 ? ".SH" : ".SS");
|
||||
CR();
|
||||
} else {
|
||||
CR();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CODE_BLOCK:
|
||||
CR();
|
||||
LIT(".IP\n.nf\n\\f[C]\n");
|
||||
OUT(cmark_node_get_literal(node),
|
||||
false,
|
||||
NORMAL);
|
||||
CR();
|
||||
LIT("\\f[]\n.fi");
|
||||
CR();
|
||||
break;
|
||||
case CMARK_NODE_CODE_BLOCK:
|
||||
CR();
|
||||
LIT(".IP\n.nf\n\\f[C]\n");
|
||||
OUT(cmark_node_get_literal(node), false, NORMAL);
|
||||
CR();
|
||||
LIT("\\f[]\n.fi");
|
||||
CR();
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HTML:
|
||||
break;
|
||||
case CMARK_NODE_HTML:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HRULE:
|
||||
CR();
|
||||
LIT(".PP\n * * * * *");
|
||||
CR();
|
||||
break;
|
||||
case CMARK_NODE_HRULE:
|
||||
CR();
|
||||
LIT(".PP\n * * * * *");
|
||||
CR();
|
||||
break;
|
||||
|
||||
case CMARK_NODE_PARAGRAPH:
|
||||
if (entering) {
|
||||
// no blank line if first paragraph in list:
|
||||
if (node->parent &&
|
||||
node->parent->type == CMARK_NODE_ITEM &&
|
||||
node->prev == NULL) {
|
||||
// no blank line or .PP
|
||||
} else {
|
||||
CR();
|
||||
LIT(".PP");
|
||||
CR();
|
||||
}
|
||||
} else {
|
||||
CR();
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_PARAGRAPH:
|
||||
if (entering) {
|
||||
// no blank line if first paragraph in list:
|
||||
if (node->parent && node->parent->type == CMARK_NODE_ITEM &&
|
||||
node->prev == NULL) {
|
||||
// no blank line or .PP
|
||||
} else {
|
||||
CR();
|
||||
LIT(".PP");
|
||||
CR();
|
||||
}
|
||||
} else {
|
||||
CR();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_TEXT:
|
||||
OUT(cmark_node_get_literal(node), true, NORMAL);
|
||||
break;
|
||||
case CMARK_NODE_TEXT:
|
||||
OUT(cmark_node_get_literal(node), true, NORMAL);
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LINEBREAK:
|
||||
LIT(".PD 0\n.P\n.PD");
|
||||
CR();
|
||||
break;
|
||||
case CMARK_NODE_LINEBREAK:
|
||||
LIT(".PD 0\n.P\n.PD");
|
||||
CR();
|
||||
break;
|
||||
|
||||
case CMARK_NODE_SOFTBREAK:
|
||||
if (renderer->width == 0) {
|
||||
CR();
|
||||
} else {
|
||||
OUT(" ", true, LITERAL);
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_SOFTBREAK:
|
||||
if (renderer->width == 0) {
|
||||
CR();
|
||||
} else {
|
||||
OUT(" ", true, LITERAL);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CODE:
|
||||
LIT("\\f[C]");
|
||||
OUT(cmark_node_get_literal(node), true, NORMAL);
|
||||
LIT("\\f[]");
|
||||
break;
|
||||
case CMARK_NODE_CODE:
|
||||
LIT("\\f[C]");
|
||||
OUT(cmark_node_get_literal(node), true, NORMAL);
|
||||
LIT("\\f[]");
|
||||
break;
|
||||
|
||||
case CMARK_NODE_INLINE_HTML:
|
||||
break;
|
||||
case CMARK_NODE_INLINE_HTML:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_STRONG:
|
||||
if (entering) {
|
||||
LIT("\\f[B]");
|
||||
} else {
|
||||
LIT("\\f[]");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_STRONG:
|
||||
if (entering) {
|
||||
LIT("\\f[B]");
|
||||
} else {
|
||||
LIT("\\f[]");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_EMPH:
|
||||
if (entering) {
|
||||
LIT("\\f[I]");
|
||||
} else {
|
||||
LIT("\\f[]");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_EMPH:
|
||||
if (entering) {
|
||||
LIT("\\f[I]");
|
||||
} else {
|
||||
LIT("\\f[]");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LINK:
|
||||
if (!entering) {
|
||||
LIT(" (");
|
||||
OUT(cmark_node_get_url(node), true, URL);
|
||||
LIT(")");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_LINK:
|
||||
if (!entering) {
|
||||
LIT(" (");
|
||||
OUT(cmark_node_get_url(node), true, URL);
|
||||
LIT(")");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_IMAGE:
|
||||
if (entering) {
|
||||
LIT("[IMAGE: ");
|
||||
} else {
|
||||
LIT("]");
|
||||
}
|
||||
break;
|
||||
case CMARK_NODE_IMAGE:
|
||||
if (entering) {
|
||||
LIT("[IMAGE: ");
|
||||
} else {
|
||||
LIT("]");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *cmark_render_man(cmark_node *root, int options, int width)
|
||||
{
|
||||
return cmark_render(root, options, width, S_outc, S_render_node);
|
||||
char *cmark_render_man(cmark_node *root, int options, int width) {
|
||||
return cmark_render(root, options, width, S_outc, S_render_node);
|
||||
}
|
||||
|
|
1267
src/node.c
1267
src/node.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
83
src/node.h
83
src/node.h
|
@ -13,68 +13,67 @@ extern "C" {
|
|||
#include "chunk.h"
|
||||
|
||||
typedef struct {
|
||||
cmark_list_type list_type;
|
||||
int marker_offset;
|
||||
int padding;
|
||||
int start;
|
||||
cmark_delim_type delimiter;
|
||||
unsigned char bullet_char;
|
||||
bool tight;
|
||||
cmark_list_type list_type;
|
||||
int marker_offset;
|
||||
int padding;
|
||||
int start;
|
||||
cmark_delim_type delimiter;
|
||||
unsigned char bullet_char;
|
||||
bool tight;
|
||||
} cmark_list;
|
||||
|
||||
typedef struct {
|
||||
cmark_chunk info;
|
||||
cmark_chunk literal;
|
||||
int fence_length;
|
||||
/* fence_offset must be 0-3, so we can use int8_t */
|
||||
int8_t fence_offset;
|
||||
unsigned char fence_char;
|
||||
bool fenced;
|
||||
cmark_chunk info;
|
||||
cmark_chunk literal;
|
||||
int fence_length;
|
||||
/* fence_offset must be 0-3, so we can use int8_t */
|
||||
int8_t fence_offset;
|
||||
unsigned char fence_char;
|
||||
bool fenced;
|
||||
} cmark_code;
|
||||
|
||||
typedef struct {
|
||||
int level;
|
||||
bool setext;
|
||||
int level;
|
||||
bool setext;
|
||||
} cmark_header;
|
||||
|
||||
typedef struct {
|
||||
cmark_chunk url;
|
||||
cmark_chunk title;
|
||||
cmark_chunk url;
|
||||
cmark_chunk title;
|
||||
} cmark_link;
|
||||
|
||||
struct cmark_node {
|
||||
struct cmark_node *next;
|
||||
struct cmark_node *prev;
|
||||
struct cmark_node *parent;
|
||||
struct cmark_node *first_child;
|
||||
struct cmark_node *last_child;
|
||||
struct cmark_node *next;
|
||||
struct cmark_node *prev;
|
||||
struct cmark_node *parent;
|
||||
struct cmark_node *first_child;
|
||||
struct cmark_node *last_child;
|
||||
|
||||
void *user_data;
|
||||
void *user_data;
|
||||
|
||||
int start_line;
|
||||
int start_column;
|
||||
int end_line;
|
||||
int end_column;
|
||||
int start_line;
|
||||
int start_column;
|
||||
int end_line;
|
||||
int end_column;
|
||||
|
||||
cmark_node_type type;
|
||||
cmark_node_type type;
|
||||
|
||||
bool open;
|
||||
bool last_line_blank;
|
||||
bool open;
|
||||
bool last_line_blank;
|
||||
|
||||
cmark_strbuf string_content;
|
||||
cmark_strbuf string_content;
|
||||
|
||||
union {
|
||||
cmark_chunk literal;
|
||||
cmark_list list;
|
||||
cmark_code code;
|
||||
cmark_header header;
|
||||
cmark_link link;
|
||||
int html_block_type;
|
||||
} as;
|
||||
union {
|
||||
cmark_chunk literal;
|
||||
cmark_list list;
|
||||
cmark_code code;
|
||||
cmark_header header;
|
||||
cmark_link link;
|
||||
int html_block_type;
|
||||
} as;
|
||||
};
|
||||
|
||||
CMARK_EXPORT int
|
||||
cmark_node_check(cmark_node *node, FILE *out);
|
||||
CMARK_EXPORT int cmark_node_check(cmark_node *node, FILE *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
28
src/parser.h
28
src/parser.h
|
@ -12,20 +12,20 @@ extern "C" {
|
|||
#define MAX_LINK_LABEL_LENGTH 1000
|
||||
|
||||
struct cmark_parser {
|
||||
struct cmark_reference_map *refmap;
|
||||
struct cmark_node* root;
|
||||
struct cmark_node* current;
|
||||
int line_number;
|
||||
bufsize_t offset;
|
||||
bufsize_t column;
|
||||
bufsize_t first_nonspace;
|
||||
bufsize_t first_nonspace_column;
|
||||
int indent;
|
||||
bool blank;
|
||||
cmark_strbuf *curline;
|
||||
bufsize_t last_line_length;
|
||||
cmark_strbuf *linebuf;
|
||||
int options;
|
||||
struct cmark_reference_map *refmap;
|
||||
struct cmark_node *root;
|
||||
struct cmark_node *current;
|
||||
int line_number;
|
||||
bufsize_t offset;
|
||||
bufsize_t column;
|
||||
bufsize_t first_nonspace;
|
||||
bufsize_t first_nonspace_column;
|
||||
int indent;
|
||||
bool blank;
|
||||
cmark_strbuf *curline;
|
||||
bufsize_t last_line_length;
|
||||
cmark_strbuf *linebuf;
|
||||
int options;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
194
src/references.c
194
src/references.c
|
@ -5,150 +5,140 @@
|
|||
#include "inlines.h"
|
||||
#include "chunk.h"
|
||||
|
||||
static unsigned int
|
||||
refhash(const unsigned char *link_ref)
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
static unsigned int refhash(const unsigned char *link_ref) {
|
||||
unsigned int hash = 0;
|
||||
|
||||
while (*link_ref)
|
||||
hash = (*link_ref++) + (hash << 6) + (hash << 16) - hash;
|
||||
while (*link_ref)
|
||||
hash = (*link_ref++) + (hash << 6) + (hash << 16) - hash;
|
||||
|
||||
return hash;
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void reference_free(cmark_reference *ref)
|
||||
{
|
||||
if(ref != NULL) {
|
||||
free(ref->label);
|
||||
cmark_chunk_free(&ref->url);
|
||||
cmark_chunk_free(&ref->title);
|
||||
free(ref);
|
||||
}
|
||||
static void reference_free(cmark_reference *ref) {
|
||||
if (ref != NULL) {
|
||||
free(ref->label);
|
||||
cmark_chunk_free(&ref->url);
|
||||
cmark_chunk_free(&ref->title);
|
||||
free(ref);
|
||||
}
|
||||
}
|
||||
|
||||
// normalize reference: collapse internal whitespace to single space,
|
||||
// remove leading/trailing whitespace, case fold
|
||||
// Return NULL if the reference name is actually empty (i.e. composed
|
||||
// solely from whitespace)
|
||||
static unsigned char *normalize_reference(cmark_chunk *ref)
|
||||
{
|
||||
cmark_strbuf normalized = GH_BUF_INIT;
|
||||
unsigned char *result;
|
||||
static unsigned char *normalize_reference(cmark_chunk *ref) {
|
||||
cmark_strbuf normalized = GH_BUF_INIT;
|
||||
unsigned char *result;
|
||||
|
||||
if(ref == NULL)
|
||||
return NULL;
|
||||
if (ref == NULL)
|
||||
return NULL;
|
||||
|
||||
if (ref->len == 0)
|
||||
return NULL;
|
||||
if (ref->len == 0)
|
||||
return NULL;
|
||||
|
||||
utf8proc_case_fold(&normalized, ref->data, ref->len);
|
||||
cmark_strbuf_trim(&normalized);
|
||||
cmark_strbuf_normalize_whitespace(&normalized);
|
||||
utf8proc_case_fold(&normalized, ref->data, ref->len);
|
||||
cmark_strbuf_trim(&normalized);
|
||||
cmark_strbuf_normalize_whitespace(&normalized);
|
||||
|
||||
result = cmark_strbuf_detach(&normalized);
|
||||
assert(result);
|
||||
result = cmark_strbuf_detach(&normalized);
|
||||
assert(result);
|
||||
|
||||
if (result[0] == '\0') {
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
if (result[0] == '\0') {
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void add_reference(cmark_reference_map *map, cmark_reference* ref)
|
||||
{
|
||||
cmark_reference *t = ref->next = map->table[ref->hash % REFMAP_SIZE];
|
||||
static void add_reference(cmark_reference_map *map, cmark_reference *ref) {
|
||||
cmark_reference *t = ref->next = map->table[ref->hash % REFMAP_SIZE];
|
||||
|
||||
while (t) {
|
||||
if (t->hash == ref->hash &&
|
||||
!strcmp((char *)t->label, (char *)ref->label)) {
|
||||
reference_free(ref);
|
||||
return;
|
||||
}
|
||||
while (t) {
|
||||
if (t->hash == ref->hash && !strcmp((char *)t->label, (char *)ref->label)) {
|
||||
reference_free(ref);
|
||||
return;
|
||||
}
|
||||
|
||||
t = t->next;
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
|
||||
map->table[ref->hash % REFMAP_SIZE] = ref;
|
||||
map->table[ref->hash % REFMAP_SIZE] = ref;
|
||||
}
|
||||
|
||||
void cmark_reference_create(cmark_reference_map *map, cmark_chunk *label, cmark_chunk *url,
|
||||
cmark_chunk *title)
|
||||
{
|
||||
cmark_reference *ref;
|
||||
unsigned char *reflabel = normalize_reference(label);
|
||||
void cmark_reference_create(cmark_reference_map *map, cmark_chunk *label,
|
||||
cmark_chunk *url, cmark_chunk *title) {
|
||||
cmark_reference *ref;
|
||||
unsigned char *reflabel = normalize_reference(label);
|
||||
|
||||
/* empty reference name, or composed from only whitespace */
|
||||
if (reflabel == NULL)
|
||||
return;
|
||||
/* empty reference name, or composed from only whitespace */
|
||||
if (reflabel == NULL)
|
||||
return;
|
||||
|
||||
ref = (cmark_reference *)calloc(1, sizeof(*ref));
|
||||
if(ref != NULL) {
|
||||
ref->label = reflabel;
|
||||
ref->hash = refhash(ref->label);
|
||||
ref->url = cmark_clean_url(url);
|
||||
ref->title = cmark_clean_title(title);
|
||||
ref->next = NULL;
|
||||
ref = (cmark_reference *)calloc(1, sizeof(*ref));
|
||||
if (ref != NULL) {
|
||||
ref->label = reflabel;
|
||||
ref->hash = refhash(ref->label);
|
||||
ref->url = cmark_clean_url(url);
|
||||
ref->title = cmark_clean_title(title);
|
||||
ref->next = NULL;
|
||||
|
||||
add_reference(map, ref);
|
||||
}
|
||||
add_reference(map, ref);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns reference if refmap contains a reference with matching
|
||||
// label, otherwise NULL.
|
||||
cmark_reference* cmark_reference_lookup(cmark_reference_map *map, cmark_chunk *label)
|
||||
{
|
||||
cmark_reference *ref = NULL;
|
||||
unsigned char *norm;
|
||||
unsigned int hash;
|
||||
cmark_reference *cmark_reference_lookup(cmark_reference_map *map,
|
||||
cmark_chunk *label) {
|
||||
cmark_reference *ref = NULL;
|
||||
unsigned char *norm;
|
||||
unsigned int hash;
|
||||
|
||||
if (label->len > MAX_LINK_LABEL_LENGTH)
|
||||
return NULL;
|
||||
if (label->len > MAX_LINK_LABEL_LENGTH)
|
||||
return NULL;
|
||||
|
||||
if (map == NULL)
|
||||
return NULL;
|
||||
if (map == NULL)
|
||||
return NULL;
|
||||
|
||||
norm = normalize_reference(label);
|
||||
if (norm == NULL)
|
||||
return NULL;
|
||||
norm = normalize_reference(label);
|
||||
if (norm == NULL)
|
||||
return NULL;
|
||||
|
||||
hash = refhash(norm);
|
||||
ref = map->table[hash % REFMAP_SIZE];
|
||||
hash = refhash(norm);
|
||||
ref = map->table[hash % REFMAP_SIZE];
|
||||
|
||||
while (ref) {
|
||||
if (ref->hash == hash &&
|
||||
!strcmp((char *)ref->label, (char *)norm))
|
||||
break;
|
||||
ref = ref->next;
|
||||
}
|
||||
while (ref) {
|
||||
if (ref->hash == hash && !strcmp((char *)ref->label, (char *)norm))
|
||||
break;
|
||||
ref = ref->next;
|
||||
}
|
||||
|
||||
free(norm);
|
||||
return ref;
|
||||
free(norm);
|
||||
return ref;
|
||||
}
|
||||
|
||||
void cmark_reference_map_free(cmark_reference_map *map)
|
||||
{
|
||||
unsigned int i;
|
||||
void cmark_reference_map_free(cmark_reference_map *map) {
|
||||
unsigned int i;
|
||||
|
||||
if(map == NULL)
|
||||
return;
|
||||
if (map == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < REFMAP_SIZE; ++i) {
|
||||
cmark_reference *ref = map->table[i];
|
||||
cmark_reference *next;
|
||||
for (i = 0; i < REFMAP_SIZE; ++i) {
|
||||
cmark_reference *ref = map->table[i];
|
||||
cmark_reference *next;
|
||||
|
||||
while (ref) {
|
||||
next = ref->next;
|
||||
reference_free(ref);
|
||||
ref = next;
|
||||
}
|
||||
}
|
||||
while (ref) {
|
||||
next = ref->next;
|
||||
reference_free(ref);
|
||||
ref = next;
|
||||
}
|
||||
}
|
||||
|
||||
free(map);
|
||||
free(map);
|
||||
}
|
||||
|
||||
cmark_reference_map *cmark_reference_map_new(void)
|
||||
{
|
||||
return (cmark_reference_map *)calloc(1, sizeof(cmark_reference_map));
|
||||
cmark_reference_map *cmark_reference_map_new(void) {
|
||||
return (cmark_reference_map *)calloc(1, sizeof(cmark_reference_map));
|
||||
}
|
||||
|
|
|
@ -10,25 +10,27 @@ extern "C" {
|
|||
#define REFMAP_SIZE 16
|
||||
|
||||
struct cmark_reference {
|
||||
struct cmark_reference *next;
|
||||
unsigned char *label;
|
||||
cmark_chunk url;
|
||||
cmark_chunk title;
|
||||
unsigned int hash;
|
||||
struct cmark_reference *next;
|
||||
unsigned char *label;
|
||||
cmark_chunk url;
|
||||
cmark_chunk title;
|
||||
unsigned int hash;
|
||||
};
|
||||
|
||||
typedef struct cmark_reference cmark_reference;
|
||||
|
||||
struct cmark_reference_map {
|
||||
cmark_reference *table[REFMAP_SIZE];
|
||||
cmark_reference *table[REFMAP_SIZE];
|
||||
};
|
||||
|
||||
typedef struct cmark_reference_map cmark_reference_map;
|
||||
|
||||
cmark_reference_map *cmark_reference_map_new(void);
|
||||
void cmark_reference_map_free(cmark_reference_map *map);
|
||||
cmark_reference* cmark_reference_lookup(cmark_reference_map *map, cmark_chunk *label);
|
||||
extern void cmark_reference_create(cmark_reference_map *map, cmark_chunk *label, cmark_chunk *url, cmark_chunk *title);
|
||||
cmark_reference *cmark_reference_lookup(cmark_reference_map *map,
|
||||
cmark_chunk *label);
|
||||
extern void cmark_reference_create(cmark_reference_map *map, cmark_chunk *label,
|
||||
cmark_chunk *url, cmark_chunk *title);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
283
src/render.c
283
src/render.c
|
@ -5,182 +5,159 @@
|
|||
#include "utf8.h"
|
||||
#include "render.h"
|
||||
|
||||
static inline
|
||||
void S_cr(cmark_renderer *renderer)
|
||||
{
|
||||
if (renderer->need_cr < 1) {
|
||||
renderer->need_cr = 1;
|
||||
}
|
||||
static inline void S_cr(cmark_renderer *renderer) {
|
||||
if (renderer->need_cr < 1) {
|
||||
renderer->need_cr = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline
|
||||
void S_blankline(cmark_renderer *renderer)
|
||||
{
|
||||
if (renderer->need_cr < 2) {
|
||||
renderer->need_cr = 2;
|
||||
}
|
||||
static inline void S_blankline(cmark_renderer *renderer) {
|
||||
if (renderer->need_cr < 2) {
|
||||
renderer->need_cr = 2;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void S_out(cmark_renderer *renderer,
|
||||
const char *source,
|
||||
bool wrap,
|
||||
cmark_escaping escape)
|
||||
{
|
||||
int length = cmark_strbuf_safe_strlen(source);
|
||||
unsigned char nextc;
|
||||
int32_t c;
|
||||
int i = 0;
|
||||
int len;
|
||||
cmark_chunk remainder = cmark_chunk_literal("");
|
||||
int k = renderer->buffer->size - 1;
|
||||
static void S_out(cmark_renderer *renderer, const char *source, bool wrap,
|
||||
cmark_escaping escape) {
|
||||
int length = cmark_strbuf_safe_strlen(source);
|
||||
unsigned char nextc;
|
||||
int32_t c;
|
||||
int i = 0;
|
||||
int len;
|
||||
cmark_chunk remainder = cmark_chunk_literal("");
|
||||
int k = renderer->buffer->size - 1;
|
||||
|
||||
wrap = wrap && !renderer->no_wrap;
|
||||
wrap = wrap && !renderer->no_wrap;
|
||||
|
||||
if (renderer->in_tight_list_item && renderer->need_cr > 1) {
|
||||
renderer->need_cr = 1;
|
||||
}
|
||||
while (renderer->need_cr) {
|
||||
if (k < 0 || renderer->buffer->ptr[k] == '\n') {
|
||||
k -= 1;
|
||||
} else {
|
||||
cmark_strbuf_putc(renderer->buffer, '\n');
|
||||
if (renderer->need_cr > 1) {
|
||||
cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
|
||||
renderer->prefix->size);
|
||||
}
|
||||
}
|
||||
renderer->column = 0;
|
||||
renderer->begin_line = true;
|
||||
renderer->need_cr -= 1;
|
||||
}
|
||||
if (renderer->in_tight_list_item && renderer->need_cr > 1) {
|
||||
renderer->need_cr = 1;
|
||||
}
|
||||
while (renderer->need_cr) {
|
||||
if (k < 0 || renderer->buffer->ptr[k] == '\n') {
|
||||
k -= 1;
|
||||
} else {
|
||||
cmark_strbuf_putc(renderer->buffer, '\n');
|
||||
if (renderer->need_cr > 1) {
|
||||
cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
|
||||
renderer->prefix->size);
|
||||
}
|
||||
}
|
||||
renderer->column = 0;
|
||||
renderer->begin_line = true;
|
||||
renderer->need_cr -= 1;
|
||||
}
|
||||
|
||||
while (i < length) {
|
||||
if (renderer->begin_line) {
|
||||
cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
|
||||
renderer->prefix->size);
|
||||
// note: this assumes prefix is ascii:
|
||||
renderer->column = renderer->prefix->size;
|
||||
}
|
||||
while (i < length) {
|
||||
if (renderer->begin_line) {
|
||||
cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
|
||||
renderer->prefix->size);
|
||||
// note: this assumes prefix is ascii:
|
||||
renderer->column = renderer->prefix->size;
|
||||
}
|
||||
|
||||
len = utf8proc_iterate((const uint8_t *)source + i, length - i, &c);
|
||||
if (len == -1) { // error condition
|
||||
return; // return without rendering rest of string
|
||||
}
|
||||
nextc = source[i + len];
|
||||
if (c == 32 && wrap) {
|
||||
if (!renderer->begin_line) {
|
||||
cmark_strbuf_putc(renderer->buffer, ' ');
|
||||
renderer->column += 1;
|
||||
renderer->begin_line = false;
|
||||
renderer->last_breakable = renderer->buffer->size -
|
||||
1;
|
||||
// skip following spaces
|
||||
while (source[i + 1] == ' ') {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
len = utf8proc_iterate((const uint8_t *)source + i, length - i, &c);
|
||||
if (len == -1) { // error condition
|
||||
return; // return without rendering rest of string
|
||||
}
|
||||
nextc = source[i + len];
|
||||
if (c == 32 && wrap) {
|
||||
if (!renderer->begin_line) {
|
||||
cmark_strbuf_putc(renderer->buffer, ' ');
|
||||
renderer->column += 1;
|
||||
renderer->begin_line = false;
|
||||
renderer->last_breakable = renderer->buffer->size - 1;
|
||||
// skip following spaces
|
||||
while (source[i + 1] == ' ') {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (c == 10) {
|
||||
cmark_strbuf_putc(renderer->buffer, '\n');
|
||||
renderer->column = 0;
|
||||
renderer->begin_line = true;
|
||||
renderer->last_breakable = 0;
|
||||
} else if (escape == LITERAL) {
|
||||
cmark_render_code_point(renderer, c);
|
||||
renderer->begin_line = false;
|
||||
} else {
|
||||
(renderer->outc)(renderer, escape, c, nextc);
|
||||
renderer->begin_line = false;
|
||||
}
|
||||
} else if (c == 10) {
|
||||
cmark_strbuf_putc(renderer->buffer, '\n');
|
||||
renderer->column = 0;
|
||||
renderer->begin_line = true;
|
||||
renderer->last_breakable = 0;
|
||||
} else if (escape == LITERAL) {
|
||||
cmark_render_code_point(renderer, c);
|
||||
renderer->begin_line = false;
|
||||
} else {
|
||||
(renderer->outc)(renderer, escape, c, nextc);
|
||||
renderer->begin_line = false;
|
||||
}
|
||||
|
||||
// If adding the character went beyond width, look for an
|
||||
// earlier place where the line could be broken:
|
||||
if (renderer->width > 0 &&
|
||||
renderer->column > renderer->width &&
|
||||
!renderer->begin_line &&
|
||||
renderer->last_breakable > 0) {
|
||||
// If adding the character went beyond width, look for an
|
||||
// earlier place where the line could be broken:
|
||||
if (renderer->width > 0 && renderer->column > renderer->width &&
|
||||
!renderer->begin_line && renderer->last_breakable > 0) {
|
||||
|
||||
// copy from last_breakable to remainder
|
||||
cmark_chunk_set_cstr(&remainder, (char *) renderer->buffer->ptr + renderer->last_breakable + 1);
|
||||
// truncate at last_breakable
|
||||
cmark_strbuf_truncate(renderer->buffer, renderer->last_breakable);
|
||||
// add newline, prefix, and remainder
|
||||
cmark_strbuf_putc(renderer->buffer, '\n');
|
||||
cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
|
||||
renderer->prefix->size);
|
||||
cmark_strbuf_put(renderer->buffer, remainder.data, remainder.len);
|
||||
renderer->column = renderer->prefix->size + remainder.len;
|
||||
cmark_chunk_free(&remainder);
|
||||
renderer->last_breakable = 0;
|
||||
renderer->begin_line = false;
|
||||
}
|
||||
// copy from last_breakable to remainder
|
||||
cmark_chunk_set_cstr(&remainder, (char *)renderer->buffer->ptr +
|
||||
renderer->last_breakable + 1);
|
||||
// truncate at last_breakable
|
||||
cmark_strbuf_truncate(renderer->buffer, renderer->last_breakable);
|
||||
// add newline, prefix, and remainder
|
||||
cmark_strbuf_putc(renderer->buffer, '\n');
|
||||
cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
|
||||
renderer->prefix->size);
|
||||
cmark_strbuf_put(renderer->buffer, remainder.data, remainder.len);
|
||||
renderer->column = renderer->prefix->size + remainder.len;
|
||||
cmark_chunk_free(&remainder);
|
||||
renderer->last_breakable = 0;
|
||||
renderer->begin_line = false;
|
||||
}
|
||||
|
||||
i += len;
|
||||
}
|
||||
i += len;
|
||||
}
|
||||
}
|
||||
|
||||
// Assumes no newlines, assumes ascii content:
|
||||
void
|
||||
cmark_render_ascii(cmark_renderer* renderer, const char* s)
|
||||
{
|
||||
int origsize = renderer->buffer->size;
|
||||
cmark_strbuf_puts(renderer->buffer, s);
|
||||
renderer->column += renderer->buffer->size - origsize;
|
||||
void cmark_render_ascii(cmark_renderer *renderer, const char *s) {
|
||||
int origsize = renderer->buffer->size;
|
||||
cmark_strbuf_puts(renderer->buffer, s);
|
||||
renderer->column += renderer->buffer->size - origsize;
|
||||
}
|
||||
|
||||
void
|
||||
cmark_render_code_point(cmark_renderer *renderer, uint32_t c)
|
||||
{
|
||||
utf8proc_encode_char(c, renderer->buffer);
|
||||
renderer->column += 1;
|
||||
void cmark_render_code_point(cmark_renderer *renderer, uint32_t c) {
|
||||
utf8proc_encode_char(c, renderer->buffer);
|
||||
renderer->column += 1;
|
||||
}
|
||||
|
||||
char*
|
||||
cmark_render(cmark_node *root,
|
||||
int options,
|
||||
int width,
|
||||
void (*outc)(cmark_renderer*,
|
||||
cmark_escaping,
|
||||
int32_t,
|
||||
unsigned char),
|
||||
int (*render_node)(cmark_renderer *renderer,
|
||||
cmark_node *node,
|
||||
cmark_event_type ev_type,
|
||||
int options))
|
||||
{
|
||||
cmark_strbuf pref = GH_BUF_INIT;
|
||||
cmark_strbuf buf = GH_BUF_INIT;
|
||||
cmark_node *cur;
|
||||
cmark_event_type ev_type;
|
||||
char *result;
|
||||
cmark_iter *iter = cmark_iter_new(root);
|
||||
char *cmark_render(cmark_node *root, int options, int width,
|
||||
void (*outc)(cmark_renderer *, cmark_escaping, int32_t,
|
||||
unsigned char),
|
||||
int (*render_node)(cmark_renderer *renderer,
|
||||
cmark_node *node,
|
||||
cmark_event_type ev_type, int options)) {
|
||||
cmark_strbuf pref = GH_BUF_INIT;
|
||||
cmark_strbuf buf = GH_BUF_INIT;
|
||||
cmark_node *cur;
|
||||
cmark_event_type ev_type;
|
||||
char *result;
|
||||
cmark_iter *iter = cmark_iter_new(root);
|
||||
|
||||
cmark_renderer renderer = { &buf, &pref, 0, width,
|
||||
0, 0, true, false, false,
|
||||
outc, S_cr, S_blankline, S_out
|
||||
};
|
||||
cmark_renderer renderer = {&buf, &pref, 0, width, 0, 0, true,
|
||||
false, false, outc, S_cr, S_blankline, S_out};
|
||||
|
||||
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
||||
cur = cmark_iter_get_node(iter);
|
||||
if (!render_node(&renderer, cur, ev_type, options)) {
|
||||
// a false value causes us to skip processing
|
||||
// the node's contents. this is used for
|
||||
// autolinks.
|
||||
cmark_iter_reset(iter, cur, CMARK_EVENT_EXIT);
|
||||
}
|
||||
}
|
||||
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
||||
cur = cmark_iter_get_node(iter);
|
||||
if (!render_node(&renderer, cur, ev_type, options)) {
|
||||
// a false value causes us to skip processing
|
||||
// the node's contents. this is used for
|
||||
// autolinks.
|
||||
cmark_iter_reset(iter, cur, CMARK_EVENT_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
// ensure final newline
|
||||
if (renderer.buffer->ptr[renderer.buffer->size - 1] != '\n') {
|
||||
cmark_strbuf_putc(renderer.buffer, '\n');
|
||||
}
|
||||
// ensure final newline
|
||||
if (renderer.buffer->ptr[renderer.buffer->size - 1] != '\n') {
|
||||
cmark_strbuf_putc(renderer.buffer, '\n');
|
||||
}
|
||||
|
||||
result = (char *)cmark_strbuf_detach(renderer.buffer);
|
||||
result = (char *)cmark_strbuf_detach(renderer.buffer);
|
||||
|
||||
cmark_iter_free(iter);
|
||||
cmark_strbuf_free(renderer.prefix);
|
||||
cmark_strbuf_free(renderer.buffer);
|
||||
cmark_iter_free(iter);
|
||||
cmark_strbuf_free(renderer.prefix);
|
||||
cmark_strbuf_free(renderer.buffer);
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
|
63
src/render.h
63
src/render.h
|
@ -9,55 +9,36 @@ extern "C" {
|
|||
#include "buffer.h"
|
||||
#include "chunk.h"
|
||||
|
||||
typedef enum {
|
||||
LITERAL,
|
||||
NORMAL,
|
||||
TITLE,
|
||||
URL
|
||||
} cmark_escaping;
|
||||
typedef enum { LITERAL, NORMAL, TITLE, URL } cmark_escaping;
|
||||
|
||||
struct cmark_renderer {
|
||||
cmark_strbuf* buffer;
|
||||
cmark_strbuf* prefix;
|
||||
int column;
|
||||
int width;
|
||||
int need_cr;
|
||||
bufsize_t last_breakable;
|
||||
bool begin_line;
|
||||
bool no_wrap;
|
||||
bool in_tight_list_item;
|
||||
void (*outc)(struct cmark_renderer*,
|
||||
cmark_escaping,
|
||||
int32_t,
|
||||
unsigned char);
|
||||
void (*cr)(struct cmark_renderer*);
|
||||
void (*blankline)(struct cmark_renderer*);
|
||||
void (*out)(struct cmark_renderer*,
|
||||
const char *,
|
||||
bool,
|
||||
cmark_escaping);
|
||||
cmark_strbuf *buffer;
|
||||
cmark_strbuf *prefix;
|
||||
int column;
|
||||
int width;
|
||||
int need_cr;
|
||||
bufsize_t last_breakable;
|
||||
bool begin_line;
|
||||
bool no_wrap;
|
||||
bool in_tight_list_item;
|
||||
void (*outc)(struct cmark_renderer *, cmark_escaping, int32_t, unsigned char);
|
||||
void (*cr)(struct cmark_renderer *);
|
||||
void (*blankline)(struct cmark_renderer *);
|
||||
void (*out)(struct cmark_renderer *, const char *, bool, cmark_escaping);
|
||||
};
|
||||
|
||||
typedef struct cmark_renderer cmark_renderer;
|
||||
|
||||
void
|
||||
cmark_render_ascii(cmark_renderer *renderer, const char* s);
|
||||
void cmark_render_ascii(cmark_renderer *renderer, const char *s);
|
||||
|
||||
void
|
||||
cmark_render_code_point(cmark_renderer *renderer, uint32_t c);
|
||||
void cmark_render_code_point(cmark_renderer *renderer, uint32_t c);
|
||||
|
||||
char*
|
||||
cmark_render(cmark_node *root,
|
||||
int options,
|
||||
int width,
|
||||
void (*outc)(cmark_renderer*,
|
||||
cmark_escaping,
|
||||
int32_t,
|
||||
unsigned char),
|
||||
int (*render_node)(cmark_renderer *renderer,
|
||||
cmark_node *node,
|
||||
cmark_event_type ev_type,
|
||||
int options));
|
||||
char *cmark_render(cmark_node *root, int options, int width,
|
||||
void (*outc)(cmark_renderer *, cmark_escaping, int32_t,
|
||||
unsigned char),
|
||||
int (*render_node)(cmark_renderer *renderer,
|
||||
cmark_node *node,
|
||||
cmark_event_type ev_type, int options));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
48603
src/scanners.c
48603
src/scanners.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -5,7 +5,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
bufsize_t _scan_at(bufsize_t (*scanner)(const unsigned char *), cmark_chunk *c, bufsize_t offset);
|
||||
bufsize_t _scan_at(bufsize_t (*scanner)(const unsigned char *), cmark_chunk *c,
|
||||
bufsize_t offset);
|
||||
bufsize_t _scan_scheme(const unsigned char *p);
|
||||
bufsize_t _scan_autolink_uri(const unsigned char *p);
|
||||
bufsize_t _scan_autolink_email(const unsigned char *p);
|
||||
|
|
657
src/utf8.c
657
src/utf8.c
|
@ -6,452 +6,309 @@
|
|||
#include "utf8.h"
|
||||
|
||||
static const int8_t utf8proc_utf8class[256] = {
|
||||
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, 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, 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, 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,
|
||||
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,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 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, 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, 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, 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, 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,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
static void encode_unknown(cmark_strbuf *buf)
|
||||
{
|
||||
static const uint8_t repl[] = {239, 191, 189};
|
||||
cmark_strbuf_put(buf, repl, 3);
|
||||
static void encode_unknown(cmark_strbuf *buf) {
|
||||
static const uint8_t repl[] = {239, 191, 189};
|
||||
cmark_strbuf_put(buf, repl, 3);
|
||||
}
|
||||
|
||||
static int utf8proc_charlen(const uint8_t *str, bufsize_t str_len)
|
||||
{
|
||||
int length, i;
|
||||
static int utf8proc_charlen(const uint8_t *str, bufsize_t str_len) {
|
||||
int length, i;
|
||||
|
||||
if (!str_len)
|
||||
return 0;
|
||||
if (!str_len)
|
||||
return 0;
|
||||
|
||||
length = utf8proc_utf8class[str[0]];
|
||||
length = utf8proc_utf8class[str[0]];
|
||||
|
||||
if (!length)
|
||||
return -1;
|
||||
if (!length)
|
||||
return -1;
|
||||
|
||||
if (str_len >= 0 && (bufsize_t)length > str_len)
|
||||
return -str_len;
|
||||
if (str_len >= 0 && (bufsize_t)length > str_len)
|
||||
return -str_len;
|
||||
|
||||
for (i = 1; i < length; i++) {
|
||||
if ((str[i] & 0xC0) != 0x80)
|
||||
return -i;
|
||||
}
|
||||
for (i = 1; i < length; i++) {
|
||||
if ((str[i] & 0xC0) != 0x80)
|
||||
return -i;
|
||||
}
|
||||
|
||||
return length;
|
||||
return length;
|
||||
}
|
||||
|
||||
// Validate a single UTF-8 character according to RFC 3629.
|
||||
static int utf8proc_valid(const uint8_t *str, bufsize_t str_len)
|
||||
{
|
||||
int length = utf8proc_utf8class[str[0]];
|
||||
static int utf8proc_valid(const uint8_t *str, bufsize_t str_len) {
|
||||
int length = utf8proc_utf8class[str[0]];
|
||||
|
||||
if (!length)
|
||||
return -1;
|
||||
if (!length)
|
||||
return -1;
|
||||
|
||||
if ((bufsize_t)length > str_len)
|
||||
return -str_len;
|
||||
if ((bufsize_t)length > str_len)
|
||||
return -str_len;
|
||||
|
||||
switch (length) {
|
||||
case 2:
|
||||
if ((str[1] & 0xC0) != 0x80)
|
||||
return -1;
|
||||
if (str[0] < 0xC2) {
|
||||
// Overlong
|
||||
return -length;
|
||||
}
|
||||
break;
|
||||
switch (length) {
|
||||
case 2:
|
||||
if ((str[1] & 0xC0) != 0x80)
|
||||
return -1;
|
||||
if (str[0] < 0xC2) {
|
||||
// Overlong
|
||||
return -length;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if ((str[1] & 0xC0) != 0x80)
|
||||
return -1;
|
||||
if ((str[2] & 0xC0) != 0x80)
|
||||
return -2;
|
||||
if (str[0] == 0xE0) {
|
||||
if (str[1] < 0xA0) {
|
||||
// Overlong
|
||||
return -length;
|
||||
}
|
||||
} else if (str[0] == 0xED) {
|
||||
if (str[1] >= 0xA0) {
|
||||
// Surrogate
|
||||
return -length;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if ((str[1] & 0xC0) != 0x80)
|
||||
return -1;
|
||||
if ((str[2] & 0xC0) != 0x80)
|
||||
return -2;
|
||||
if (str[0] == 0xE0) {
|
||||
if (str[1] < 0xA0) {
|
||||
// Overlong
|
||||
return -length;
|
||||
}
|
||||
} else if (str[0] == 0xED) {
|
||||
if (str[1] >= 0xA0) {
|
||||
// Surrogate
|
||||
return -length;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ((str[1] & 0xC0) != 0x80)
|
||||
return -1;
|
||||
if ((str[2] & 0xC0) != 0x80)
|
||||
return -2;
|
||||
if ((str[3] & 0xC0) != 0x80)
|
||||
return -3;
|
||||
if (str[0] == 0xF0) {
|
||||
if (str[1] < 0x90) {
|
||||
// Overlong
|
||||
return -length;
|
||||
}
|
||||
} else if (str[0] >= 0xF4) {
|
||||
if (str[0] > 0xF4 || str[1] >= 0x90) {
|
||||
// Above 0x10FFFF
|
||||
return -length;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
if ((str[1] & 0xC0) != 0x80)
|
||||
return -1;
|
||||
if ((str[2] & 0xC0) != 0x80)
|
||||
return -2;
|
||||
if ((str[3] & 0xC0) != 0x80)
|
||||
return -3;
|
||||
if (str[0] == 0xF0) {
|
||||
if (str[1] < 0x90) {
|
||||
// Overlong
|
||||
return -length;
|
||||
}
|
||||
} else if (str[0] >= 0xF4) {
|
||||
if (str[0] > 0xF4 || str[1] >= 0x90) {
|
||||
// Above 0x10FFFF
|
||||
return -length;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return length;
|
||||
return length;
|
||||
}
|
||||
|
||||
void utf8proc_check(cmark_strbuf *ob, const uint8_t *line, bufsize_t size)
|
||||
{
|
||||
bufsize_t i = 0;
|
||||
void utf8proc_check(cmark_strbuf *ob, const uint8_t *line, bufsize_t size) {
|
||||
bufsize_t i = 0;
|
||||
|
||||
while (i < size) {
|
||||
bufsize_t org = i;
|
||||
int charlen = 0;
|
||||
while (i < size) {
|
||||
bufsize_t org = i;
|
||||
int charlen = 0;
|
||||
|
||||
while (i < size) {
|
||||
if (line[i] < 0x80 && line[i] != 0) {
|
||||
i++;
|
||||
} else if (line[i] >= 0x80) {
|
||||
charlen = utf8proc_valid(line + i, size - i);
|
||||
if (charlen < 0) {
|
||||
charlen = -charlen;
|
||||
break;
|
||||
}
|
||||
i += charlen;
|
||||
} else if (line[i] == 0) {
|
||||
// ASCII NUL is technically valid but rejected
|
||||
// for security reasons.
|
||||
charlen = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (i < size) {
|
||||
if (line[i] < 0x80 && line[i] != 0) {
|
||||
i++;
|
||||
} else if (line[i] >= 0x80) {
|
||||
charlen = utf8proc_valid(line + i, size - i);
|
||||
if (charlen < 0) {
|
||||
charlen = -charlen;
|
||||
break;
|
||||
}
|
||||
i += charlen;
|
||||
} else if (line[i] == 0) {
|
||||
// ASCII NUL is technically valid but rejected
|
||||
// for security reasons.
|
||||
charlen = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i > org) {
|
||||
cmark_strbuf_put(ob, line + org, i - org);
|
||||
}
|
||||
if (i > org) {
|
||||
cmark_strbuf_put(ob, line + org, i - org);
|
||||
}
|
||||
|
||||
if (i >= size) {
|
||||
break;
|
||||
} else {
|
||||
// Invalid UTF-8
|
||||
encode_unknown(ob);
|
||||
i += charlen;
|
||||
}
|
||||
}
|
||||
if (i >= size) {
|
||||
break;
|
||||
} else {
|
||||
// Invalid UTF-8
|
||||
encode_unknown(ob);
|
||||
i += charlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int utf8proc_iterate(const uint8_t *str, bufsize_t str_len, int32_t *dst)
|
||||
{
|
||||
int length;
|
||||
int32_t uc = -1;
|
||||
int utf8proc_iterate(const uint8_t *str, bufsize_t str_len, int32_t *dst) {
|
||||
int length;
|
||||
int32_t uc = -1;
|
||||
|
||||
*dst = -1;
|
||||
length = utf8proc_charlen(str, str_len);
|
||||
if (length < 0)
|
||||
return -1;
|
||||
*dst = -1;
|
||||
length = utf8proc_charlen(str, str_len);
|
||||
if (length < 0)
|
||||
return -1;
|
||||
|
||||
switch (length) {
|
||||
case 1:
|
||||
uc = str[0];
|
||||
break;
|
||||
case 2:
|
||||
uc = ((str[0] & 0x1F) << 6) + (str[1] & 0x3F);
|
||||
if (uc < 0x80) uc = -1;
|
||||
break;
|
||||
case 3:
|
||||
uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) << 6)
|
||||
+ (str[2] & 0x3F);
|
||||
if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000)) uc = -1;
|
||||
break;
|
||||
case 4:
|
||||
uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12)
|
||||
+ ((str[2] & 0x3F) << 6) + (str[3] & 0x3F);
|
||||
if (uc < 0x10000 || uc >= 0x110000) uc = -1;
|
||||
break;
|
||||
}
|
||||
switch (length) {
|
||||
case 1:
|
||||
uc = str[0];
|
||||
break;
|
||||
case 2:
|
||||
uc = ((str[0] & 0x1F) << 6) + (str[1] & 0x3F);
|
||||
if (uc < 0x80)
|
||||
uc = -1;
|
||||
break;
|
||||
case 3:
|
||||
uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) << 6) + (str[2] & 0x3F);
|
||||
if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000))
|
||||
uc = -1;
|
||||
break;
|
||||
case 4:
|
||||
uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12) +
|
||||
((str[2] & 0x3F) << 6) + (str[3] & 0x3F);
|
||||
if (uc < 0x10000 || uc >= 0x110000)
|
||||
uc = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (uc < 0)
|
||||
return -1;
|
||||
if (uc < 0)
|
||||
return -1;
|
||||
|
||||
*dst = uc;
|
||||
return length;
|
||||
*dst = uc;
|
||||
return length;
|
||||
}
|
||||
|
||||
void utf8proc_encode_char(int32_t uc, cmark_strbuf *buf)
|
||||
{
|
||||
uint8_t dst[4];
|
||||
bufsize_t len = 0;
|
||||
void utf8proc_encode_char(int32_t uc, cmark_strbuf *buf) {
|
||||
uint8_t dst[4];
|
||||
bufsize_t len = 0;
|
||||
|
||||
assert(uc >= 0);
|
||||
assert(uc >= 0);
|
||||
|
||||
if (uc < 0x80) {
|
||||
dst[0] = uc;
|
||||
len = 1;
|
||||
} else if (uc < 0x800) {
|
||||
dst[0] = 0xC0 + (uc >> 6);
|
||||
dst[1] = 0x80 + (uc & 0x3F);
|
||||
len = 2;
|
||||
} else if (uc == 0xFFFF) {
|
||||
dst[0] = 0xFF;
|
||||
len = 1;
|
||||
} else if (uc == 0xFFFE) {
|
||||
dst[0] = 0xFE;
|
||||
len = 1;
|
||||
} else if (uc < 0x10000) {
|
||||
dst[0] = 0xE0 + (uc >> 12);
|
||||
dst[1] = 0x80 + ((uc >> 6) & 0x3F);
|
||||
dst[2] = 0x80 + (uc & 0x3F);
|
||||
len = 3;
|
||||
} else if (uc < 0x110000) {
|
||||
dst[0] = 0xF0 + (uc >> 18);
|
||||
dst[1] = 0x80 + ((uc >> 12) & 0x3F);
|
||||
dst[2] = 0x80 + ((uc >> 6) & 0x3F);
|
||||
dst[3] = 0x80 + (uc & 0x3F);
|
||||
len = 4;
|
||||
} else {
|
||||
encode_unknown(buf);
|
||||
return;
|
||||
}
|
||||
if (uc < 0x80) {
|
||||
dst[0] = uc;
|
||||
len = 1;
|
||||
} else if (uc < 0x800) {
|
||||
dst[0] = 0xC0 + (uc >> 6);
|
||||
dst[1] = 0x80 + (uc & 0x3F);
|
||||
len = 2;
|
||||
} else if (uc == 0xFFFF) {
|
||||
dst[0] = 0xFF;
|
||||
len = 1;
|
||||
} else if (uc == 0xFFFE) {
|
||||
dst[0] = 0xFE;
|
||||
len = 1;
|
||||
} else if (uc < 0x10000) {
|
||||
dst[0] = 0xE0 + (uc >> 12);
|
||||
dst[1] = 0x80 + ((uc >> 6) & 0x3F);
|
||||
dst[2] = 0x80 + (uc & 0x3F);
|
||||
len = 3;
|
||||
} else if (uc < 0x110000) {
|
||||
dst[0] = 0xF0 + (uc >> 18);
|
||||
dst[1] = 0x80 + ((uc >> 12) & 0x3F);
|
||||
dst[2] = 0x80 + ((uc >> 6) & 0x3F);
|
||||
dst[3] = 0x80 + (uc & 0x3F);
|
||||
len = 4;
|
||||
} else {
|
||||
encode_unknown(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
cmark_strbuf_put(buf, dst, len);
|
||||
cmark_strbuf_put(buf, dst, len);
|
||||
}
|
||||
|
||||
void utf8proc_case_fold(cmark_strbuf *dest, const uint8_t *str, bufsize_t len)
|
||||
{
|
||||
int32_t c;
|
||||
void utf8proc_case_fold(cmark_strbuf *dest, const uint8_t *str, bufsize_t len) {
|
||||
int32_t c;
|
||||
|
||||
#define bufpush(x) \
|
||||
utf8proc_encode_char(x, dest)
|
||||
#define bufpush(x) utf8proc_encode_char(x, dest)
|
||||
|
||||
while (len > 0) {
|
||||
bufsize_t char_len = utf8proc_iterate(str, len, &c);
|
||||
while (len > 0) {
|
||||
bufsize_t char_len = utf8proc_iterate(str, len, &c);
|
||||
|
||||
if (char_len >= 0) {
|
||||
if (char_len >= 0) {
|
||||
#include "case_fold_switch.inc"
|
||||
} else {
|
||||
encode_unknown(dest);
|
||||
char_len = -char_len;
|
||||
}
|
||||
} else {
|
||||
encode_unknown(dest);
|
||||
char_len = -char_len;
|
||||
}
|
||||
|
||||
str += char_len;
|
||||
len -= char_len;
|
||||
}
|
||||
str += char_len;
|
||||
len -= char_len;
|
||||
}
|
||||
}
|
||||
|
||||
// matches anything in the Zs class, plus LF, CR, TAB, FF.
|
||||
int utf8proc_is_space(int32_t uc)
|
||||
{
|
||||
return (uc == 9 ||
|
||||
uc == 10 ||
|
||||
uc == 12 ||
|
||||
uc == 13 ||
|
||||
uc == 32 ||
|
||||
uc == 160 ||
|
||||
uc == 5760 ||
|
||||
(uc >= 8192 && uc <= 8202) ||
|
||||
uc == 8239 ||
|
||||
uc == 8287 ||
|
||||
uc == 12288);
|
||||
int utf8proc_is_space(int32_t uc) {
|
||||
return (uc == 9 || uc == 10 || uc == 12 || uc == 13 || uc == 32 ||
|
||||
uc == 160 || uc == 5760 || (uc >= 8192 && uc <= 8202) || uc == 8239 ||
|
||||
uc == 8287 || uc == 12288);
|
||||
}
|
||||
|
||||
// matches anything in the P[cdefios] classes.
|
||||
int utf8proc_is_punctuation(int32_t uc)
|
||||
{
|
||||
return ((uc < 128 && cmark_ispunct((char)uc)) ||
|
||||
uc == 161 ||
|
||||
uc == 167 ||
|
||||
uc == 171 ||
|
||||
uc == 182 ||
|
||||
uc == 183 ||
|
||||
uc == 187 ||
|
||||
uc == 191 ||
|
||||
uc == 894 ||
|
||||
uc == 903 ||
|
||||
(uc >= 1370 && uc <= 1375) ||
|
||||
uc == 1417 ||
|
||||
uc == 1418 ||
|
||||
uc == 1470 ||
|
||||
uc == 1472 ||
|
||||
uc == 1475 ||
|
||||
uc == 1478 ||
|
||||
uc == 1523 ||
|
||||
uc == 1524 ||
|
||||
uc == 1545 ||
|
||||
uc == 1546 ||
|
||||
uc == 1548 ||
|
||||
uc == 1549 ||
|
||||
uc == 1563 ||
|
||||
uc == 1566 ||
|
||||
uc == 1567 ||
|
||||
(uc >= 1642 && uc <= 1645) ||
|
||||
uc == 1748 ||
|
||||
(uc >= 1792 && uc <= 1805) ||
|
||||
(uc >= 2039 && uc <= 2041) ||
|
||||
(uc >= 2096 && uc <= 2110) ||
|
||||
uc == 2142 ||
|
||||
uc == 2404 ||
|
||||
uc == 2405 ||
|
||||
uc == 2416 ||
|
||||
uc == 2800 ||
|
||||
uc == 3572 ||
|
||||
uc == 3663 ||
|
||||
uc == 3674 ||
|
||||
uc == 3675 ||
|
||||
(uc >= 3844 && uc <= 3858) ||
|
||||
uc == 3860 ||
|
||||
(uc >= 3898 && uc <= 3901) ||
|
||||
uc == 3973 ||
|
||||
(uc >= 4048 && uc <= 4052) ||
|
||||
uc == 4057 ||
|
||||
uc == 4058 ||
|
||||
(uc >= 4170 && uc <= 4175) ||
|
||||
uc == 4347 ||
|
||||
(uc >= 4960 && uc <= 4968) ||
|
||||
uc == 5120 ||
|
||||
uc == 5741 ||
|
||||
uc == 5742 ||
|
||||
uc == 5787 ||
|
||||
uc == 5788 ||
|
||||
(uc >= 5867 && uc <= 5869) ||
|
||||
uc == 5941 ||
|
||||
uc == 5942 ||
|
||||
(uc >= 6100 && uc <= 6102) ||
|
||||
(uc >= 6104 && uc <= 6106) ||
|
||||
(uc >= 6144 && uc <= 6154) ||
|
||||
uc == 6468 ||
|
||||
uc == 6469 ||
|
||||
uc == 6686 ||
|
||||
uc == 6687 ||
|
||||
(uc >= 6816 && uc <= 6822) ||
|
||||
(uc >= 6824 && uc <= 6829) ||
|
||||
(uc >= 7002 && uc <= 7008) ||
|
||||
(uc >= 7164 && uc <= 7167) ||
|
||||
(uc >= 7227 && uc <= 7231) ||
|
||||
uc == 7294 ||
|
||||
uc == 7295 ||
|
||||
(uc >= 7360 && uc <= 7367) ||
|
||||
uc == 7379 ||
|
||||
(uc >= 8208 && uc <= 8231) ||
|
||||
(uc >= 8240 && uc <= 8259) ||
|
||||
(uc >= 8261 && uc <= 8273) ||
|
||||
(uc >= 8275 && uc <= 8286) ||
|
||||
uc == 8317 ||
|
||||
uc == 8318 ||
|
||||
uc == 8333 ||
|
||||
uc == 8334 ||
|
||||
(uc >= 8968 && uc <= 8971) ||
|
||||
uc == 9001 ||
|
||||
uc == 9002 ||
|
||||
(uc >= 10088 && uc <= 10101) ||
|
||||
uc == 10181 ||
|
||||
uc == 10182 ||
|
||||
(uc >= 10214 && uc <= 10223) ||
|
||||
(uc >= 10627 && uc <= 10648) ||
|
||||
(uc >= 10712 && uc <= 10715) ||
|
||||
uc == 10748 ||
|
||||
uc == 10749 ||
|
||||
(uc >= 11513 && uc <= 11516) ||
|
||||
uc == 11518 ||
|
||||
uc == 11519 ||
|
||||
uc == 11632 ||
|
||||
(uc >= 11776 && uc <= 11822) ||
|
||||
(uc >= 11824 && uc <= 11842) ||
|
||||
(uc >= 12289 && uc <= 12291) ||
|
||||
(uc >= 12296 && uc <= 12305) ||
|
||||
(uc >= 12308 && uc <= 12319) ||
|
||||
uc == 12336 ||
|
||||
uc == 12349 ||
|
||||
uc == 12448 ||
|
||||
uc == 12539 ||
|
||||
uc == 42238 ||
|
||||
uc == 42239 ||
|
||||
(uc >= 42509 && uc <= 42511) ||
|
||||
uc == 42611 ||
|
||||
uc == 42622 ||
|
||||
(uc >= 42738 && uc <= 42743) ||
|
||||
(uc >= 43124 && uc <= 43127) ||
|
||||
uc == 43214 ||
|
||||
uc == 43215 ||
|
||||
(uc >= 43256 && uc <= 43258) ||
|
||||
uc == 43310 ||
|
||||
uc == 43311 ||
|
||||
uc == 43359 ||
|
||||
(uc >= 43457 && uc <= 43469) ||
|
||||
uc == 43486 ||
|
||||
uc == 43487 ||
|
||||
(uc >= 43612 && uc <= 43615) ||
|
||||
uc == 43742 ||
|
||||
uc == 43743 ||
|
||||
uc == 43760 ||
|
||||
uc == 43761 ||
|
||||
uc == 44011 ||
|
||||
uc == 64830 ||
|
||||
uc == 64831 ||
|
||||
(uc >= 65040 && uc <= 65049) ||
|
||||
(uc >= 65072 && uc <= 65106) ||
|
||||
(uc >= 65108 && uc <= 65121) ||
|
||||
uc == 65123 ||
|
||||
uc == 65128 ||
|
||||
uc == 65130 ||
|
||||
uc == 65131 ||
|
||||
(uc >= 65281 && uc <= 65283) ||
|
||||
(uc >= 65285 && uc <= 65290) ||
|
||||
(uc >= 65292 && uc <= 65295) ||
|
||||
uc == 65306 ||
|
||||
uc == 65307 ||
|
||||
uc == 65311 ||
|
||||
uc == 65312 ||
|
||||
(uc >= 65339 && uc <= 65341) ||
|
||||
uc == 65343 ||
|
||||
uc == 65371 ||
|
||||
uc == 65373 ||
|
||||
(uc >= 65375 && uc <= 65381) ||
|
||||
(uc >= 65792 && uc <= 65794) ||
|
||||
uc == 66463 ||
|
||||
uc == 66512 ||
|
||||
uc == 66927 ||
|
||||
uc == 67671 ||
|
||||
uc == 67871 ||
|
||||
uc == 67903 ||
|
||||
(uc >= 68176 && uc <= 68184) ||
|
||||
uc == 68223 ||
|
||||
(uc >= 68336 && uc <= 68342) ||
|
||||
(uc >= 68409 && uc <= 68415) ||
|
||||
(uc >= 68505 && uc <= 68508) ||
|
||||
(uc >= 69703 && uc <= 69709) ||
|
||||
uc == 69819 ||
|
||||
uc == 69820 ||
|
||||
(uc >= 69822 && uc <= 69825) ||
|
||||
(uc >= 69952 && uc <= 69955) ||
|
||||
uc == 70004 ||
|
||||
uc == 70005 ||
|
||||
(uc >= 70085 && uc <= 70088) ||
|
||||
uc == 70093 ||
|
||||
(uc >= 70200 && uc <= 70205) ||
|
||||
uc == 70854 ||
|
||||
(uc >= 71105 && uc <= 71113) ||
|
||||
(uc >= 71233 && uc <= 71235) ||
|
||||
(uc >= 74864 && uc <= 74868) ||
|
||||
uc == 92782 ||
|
||||
uc == 92783 ||
|
||||
uc == 92917 ||
|
||||
(uc >= 92983 && uc <= 92987) ||
|
||||
uc == 92996 ||
|
||||
uc == 113823);
|
||||
int utf8proc_is_punctuation(int32_t uc) {
|
||||
return (
|
||||
(uc < 128 && cmark_ispunct((char)uc)) || uc == 161 || uc == 167 ||
|
||||
uc == 171 || uc == 182 || uc == 183 || uc == 187 || uc == 191 ||
|
||||
uc == 894 || uc == 903 || (uc >= 1370 && uc <= 1375) || uc == 1417 ||
|
||||
uc == 1418 || uc == 1470 || uc == 1472 || uc == 1475 || uc == 1478 ||
|
||||
uc == 1523 || uc == 1524 || uc == 1545 || uc == 1546 || uc == 1548 ||
|
||||
uc == 1549 || uc == 1563 || uc == 1566 || uc == 1567 ||
|
||||
(uc >= 1642 && uc <= 1645) || uc == 1748 || (uc >= 1792 && uc <= 1805) ||
|
||||
(uc >= 2039 && uc <= 2041) || (uc >= 2096 && uc <= 2110) || uc == 2142 ||
|
||||
uc == 2404 || uc == 2405 || uc == 2416 || uc == 2800 || uc == 3572 ||
|
||||
uc == 3663 || uc == 3674 || uc == 3675 || (uc >= 3844 && uc <= 3858) ||
|
||||
uc == 3860 || (uc >= 3898 && uc <= 3901) || uc == 3973 ||
|
||||
(uc >= 4048 && uc <= 4052) || uc == 4057 || uc == 4058 ||
|
||||
(uc >= 4170 && uc <= 4175) || uc == 4347 || (uc >= 4960 && uc <= 4968) ||
|
||||
uc == 5120 || uc == 5741 || uc == 5742 || uc == 5787 || uc == 5788 ||
|
||||
(uc >= 5867 && uc <= 5869) || uc == 5941 || uc == 5942 ||
|
||||
(uc >= 6100 && uc <= 6102) || (uc >= 6104 && uc <= 6106) ||
|
||||
(uc >= 6144 && uc <= 6154) || uc == 6468 || uc == 6469 || uc == 6686 ||
|
||||
uc == 6687 || (uc >= 6816 && uc <= 6822) || (uc >= 6824 && uc <= 6829) ||
|
||||
(uc >= 7002 && uc <= 7008) || (uc >= 7164 && uc <= 7167) ||
|
||||
(uc >= 7227 && uc <= 7231) || uc == 7294 || uc == 7295 ||
|
||||
(uc >= 7360 && uc <= 7367) || uc == 7379 || (uc >= 8208 && uc <= 8231) ||
|
||||
(uc >= 8240 && uc <= 8259) || (uc >= 8261 && uc <= 8273) ||
|
||||
(uc >= 8275 && uc <= 8286) || uc == 8317 || uc == 8318 || uc == 8333 ||
|
||||
uc == 8334 || (uc >= 8968 && uc <= 8971) || uc == 9001 || uc == 9002 ||
|
||||
(uc >= 10088 && uc <= 10101) || uc == 10181 || uc == 10182 ||
|
||||
(uc >= 10214 && uc <= 10223) || (uc >= 10627 && uc <= 10648) ||
|
||||
(uc >= 10712 && uc <= 10715) || uc == 10748 || uc == 10749 ||
|
||||
(uc >= 11513 && uc <= 11516) || uc == 11518 || uc == 11519 ||
|
||||
uc == 11632 || (uc >= 11776 && uc <= 11822) ||
|
||||
(uc >= 11824 && uc <= 11842) || (uc >= 12289 && uc <= 12291) ||
|
||||
(uc >= 12296 && uc <= 12305) || (uc >= 12308 && uc <= 12319) ||
|
||||
uc == 12336 || uc == 12349 || uc == 12448 || uc == 12539 || uc == 42238 ||
|
||||
uc == 42239 || (uc >= 42509 && uc <= 42511) || uc == 42611 ||
|
||||
uc == 42622 || (uc >= 42738 && uc <= 42743) ||
|
||||
(uc >= 43124 && uc <= 43127) || uc == 43214 || uc == 43215 ||
|
||||
(uc >= 43256 && uc <= 43258) || uc == 43310 || uc == 43311 ||
|
||||
uc == 43359 || (uc >= 43457 && uc <= 43469) || uc == 43486 ||
|
||||
uc == 43487 || (uc >= 43612 && uc <= 43615) || uc == 43742 ||
|
||||
uc == 43743 || uc == 43760 || uc == 43761 || uc == 44011 || uc == 64830 ||
|
||||
uc == 64831 || (uc >= 65040 && uc <= 65049) ||
|
||||
(uc >= 65072 && uc <= 65106) || (uc >= 65108 && uc <= 65121) ||
|
||||
uc == 65123 || uc == 65128 || uc == 65130 || uc == 65131 ||
|
||||
(uc >= 65281 && uc <= 65283) || (uc >= 65285 && uc <= 65290) ||
|
||||
(uc >= 65292 && uc <= 65295) || uc == 65306 || uc == 65307 ||
|
||||
uc == 65311 || uc == 65312 || (uc >= 65339 && uc <= 65341) ||
|
||||
uc == 65343 || uc == 65371 || uc == 65373 ||
|
||||
(uc >= 65375 && uc <= 65381) || (uc >= 65792 && uc <= 65794) ||
|
||||
uc == 66463 || uc == 66512 || uc == 66927 || uc == 67671 || uc == 67871 ||
|
||||
uc == 67903 || (uc >= 68176 && uc <= 68184) || uc == 68223 ||
|
||||
(uc >= 68336 && uc <= 68342) || (uc >= 68409 && uc <= 68415) ||
|
||||
(uc >= 68505 && uc <= 68508) || (uc >= 69703 && uc <= 69709) ||
|
||||
uc == 69819 || uc == 69820 || (uc >= 69822 && uc <= 69825) ||
|
||||
(uc >= 69952 && uc <= 69955) || uc == 70004 || uc == 70005 ||
|
||||
(uc >= 70085 && uc <= 70088) || uc == 70093 ||
|
||||
(uc >= 70200 && uc <= 70205) || uc == 70854 ||
|
||||
(uc >= 71105 && uc <= 71113) || (uc >= 71233 && uc <= 71235) ||
|
||||
(uc >= 74864 && uc <= 74868) || uc == 92782 || uc == 92783 ||
|
||||
uc == 92917 || (uc >= 92983 && uc <= 92987) || uc == 92996 ||
|
||||
uc == 113823);
|
||||
}
|
||||
|
|
261
src/xml.c
261
src/xml.c
|
@ -11,163 +11,142 @@
|
|||
|
||||
// Functions to convert cmark_nodes to XML strings.
|
||||
|
||||
static void escape_xml(cmark_strbuf *dest, const unsigned char *source, bufsize_t length)
|
||||
{
|
||||
houdini_escape_html0(dest, source, length, 0);
|
||||
static void escape_xml(cmark_strbuf *dest, const unsigned char *source,
|
||||
bufsize_t length) {
|
||||
houdini_escape_html0(dest, source, length, 0);
|
||||
}
|
||||
|
||||
struct render_state {
|
||||
cmark_strbuf* xml;
|
||||
int indent;
|
||||
cmark_strbuf *xml;
|
||||
int indent;
|
||||
};
|
||||
|
||||
static inline void indent(struct render_state *state)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < state->indent; i++) {
|
||||
cmark_strbuf_putc(state->xml, ' ');
|
||||
}
|
||||
static inline void indent(struct render_state *state) {
|
||||
int i;
|
||||
for (i = 0; i < state->indent; i++) {
|
||||
cmark_strbuf_putc(state->xml, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||
struct render_state *state, int options)
|
||||
{
|
||||
cmark_strbuf *xml = state->xml;
|
||||
bool literal = false;
|
||||
cmark_delim_type delim;
|
||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||
char buffer[100];
|
||||
static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||
struct render_state *state, int options) {
|
||||
cmark_strbuf *xml = state->xml;
|
||||
bool literal = false;
|
||||
cmark_delim_type delim;
|
||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||
char buffer[100];
|
||||
|
||||
if (entering) {
|
||||
indent(state);
|
||||
cmark_strbuf_putc(xml, '<');
|
||||
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
|
||||
if (entering) {
|
||||
indent(state);
|
||||
cmark_strbuf_putc(xml, '<');
|
||||
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
|
||||
|
||||
if (options & CMARK_OPT_SOURCEPOS && node->start_line != 0) {
|
||||
sprintf(buffer, " sourcepos=\"%d:%d-%d:%d\"",
|
||||
node->start_line,
|
||||
node->start_column,
|
||||
node->end_line,
|
||||
node->end_column);
|
||||
cmark_strbuf_puts(xml, buffer);
|
||||
}
|
||||
if (options & CMARK_OPT_SOURCEPOS && node->start_line != 0) {
|
||||
sprintf(buffer, " sourcepos=\"%d:%d-%d:%d\"", node->start_line,
|
||||
node->start_column, node->end_line, node->end_column);
|
||||
cmark_strbuf_puts(xml, buffer);
|
||||
}
|
||||
|
||||
literal = false;
|
||||
literal = false;
|
||||
|
||||
switch (node->type) {
|
||||
case CMARK_NODE_TEXT:
|
||||
case CMARK_NODE_CODE:
|
||||
case CMARK_NODE_HTML:
|
||||
case CMARK_NODE_INLINE_HTML:
|
||||
cmark_strbuf_puts(xml, ">");
|
||||
escape_xml(xml, node->as.literal.data,
|
||||
node->as.literal.len);
|
||||
cmark_strbuf_puts(xml, "</");
|
||||
cmark_strbuf_puts(xml,
|
||||
cmark_node_get_type_string(node));
|
||||
literal = true;
|
||||
break;
|
||||
case CMARK_NODE_LIST:
|
||||
switch (cmark_node_get_list_type(node)) {
|
||||
case CMARK_ORDERED_LIST:
|
||||
cmark_strbuf_puts(xml, " type=\"ordered\"");
|
||||
sprintf(buffer," start=\"%d\"",
|
||||
cmark_node_get_list_start(node));
|
||||
cmark_strbuf_puts(xml, buffer);
|
||||
delim = cmark_node_get_list_delim(node);
|
||||
if (delim == CMARK_PAREN_DELIM) {
|
||||
cmark_strbuf_puts(xml,
|
||||
" delim=\"paren\"");
|
||||
} else if (delim == CMARK_PERIOD_DELIM) {
|
||||
cmark_strbuf_puts(xml,
|
||||
" delim=\"period\"");
|
||||
}
|
||||
break;
|
||||
case CMARK_BULLET_LIST:
|
||||
cmark_strbuf_puts(xml, " type=\"bullet\"");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sprintf(buffer, " tight=\"%s\"",
|
||||
(cmark_node_get_list_tight(node) ?
|
||||
"true" : "false"));
|
||||
cmark_strbuf_puts(xml, buffer);
|
||||
break;
|
||||
case CMARK_NODE_HEADER:
|
||||
sprintf(buffer, " level=\"%d\"",
|
||||
node->as.header.level);
|
||||
cmark_strbuf_puts(xml, buffer);
|
||||
break;
|
||||
case CMARK_NODE_CODE_BLOCK:
|
||||
if (node->as.code.info.len > 0) {
|
||||
cmark_strbuf_puts(xml, " info=\"");
|
||||
escape_xml(xml, node->as.code.info.data,
|
||||
node->as.code.info.len);
|
||||
cmark_strbuf_putc(xml, '"');
|
||||
}
|
||||
cmark_strbuf_puts(xml, ">");
|
||||
escape_xml(xml, node->as.code.literal.data,
|
||||
node->as.code.literal.len);
|
||||
cmark_strbuf_puts(xml, "</");
|
||||
cmark_strbuf_puts(xml,
|
||||
cmark_node_get_type_string(node));
|
||||
literal = true;
|
||||
break;
|
||||
case CMARK_NODE_LINK:
|
||||
case CMARK_NODE_IMAGE:
|
||||
cmark_strbuf_puts(xml, " destination=\"");
|
||||
escape_xml(xml, node->as.link.url.data,
|
||||
node->as.link.url.len);
|
||||
cmark_strbuf_putc(xml, '"');
|
||||
cmark_strbuf_puts(xml, " title=\"");
|
||||
escape_xml(xml, node->as.link.title.data,
|
||||
node->as.link.title.len);
|
||||
cmark_strbuf_putc(xml, '"');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (node->first_child) {
|
||||
state->indent += 2;
|
||||
} else if (!literal) {
|
||||
cmark_strbuf_puts(xml, " /");
|
||||
}
|
||||
cmark_strbuf_puts(xml, ">\n");
|
||||
switch (node->type) {
|
||||
case CMARK_NODE_TEXT:
|
||||
case CMARK_NODE_CODE:
|
||||
case CMARK_NODE_HTML:
|
||||
case CMARK_NODE_INLINE_HTML:
|
||||
cmark_strbuf_puts(xml, ">");
|
||||
escape_xml(xml, node->as.literal.data, node->as.literal.len);
|
||||
cmark_strbuf_puts(xml, "</");
|
||||
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
|
||||
literal = true;
|
||||
break;
|
||||
case CMARK_NODE_LIST:
|
||||
switch (cmark_node_get_list_type(node)) {
|
||||
case CMARK_ORDERED_LIST:
|
||||
cmark_strbuf_puts(xml, " type=\"ordered\"");
|
||||
sprintf(buffer, " start=\"%d\"", cmark_node_get_list_start(node));
|
||||
cmark_strbuf_puts(xml, buffer);
|
||||
delim = cmark_node_get_list_delim(node);
|
||||
if (delim == CMARK_PAREN_DELIM) {
|
||||
cmark_strbuf_puts(xml, " delim=\"paren\"");
|
||||
} else if (delim == CMARK_PERIOD_DELIM) {
|
||||
cmark_strbuf_puts(xml, " delim=\"period\"");
|
||||
}
|
||||
break;
|
||||
case CMARK_BULLET_LIST:
|
||||
cmark_strbuf_puts(xml, " type=\"bullet\"");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sprintf(buffer, " tight=\"%s\"",
|
||||
(cmark_node_get_list_tight(node) ? "true" : "false"));
|
||||
cmark_strbuf_puts(xml, buffer);
|
||||
break;
|
||||
case CMARK_NODE_HEADER:
|
||||
sprintf(buffer, " level=\"%d\"", node->as.header.level);
|
||||
cmark_strbuf_puts(xml, buffer);
|
||||
break;
|
||||
case CMARK_NODE_CODE_BLOCK:
|
||||
if (node->as.code.info.len > 0) {
|
||||
cmark_strbuf_puts(xml, " info=\"");
|
||||
escape_xml(xml, node->as.code.info.data, node->as.code.info.len);
|
||||
cmark_strbuf_putc(xml, '"');
|
||||
}
|
||||
cmark_strbuf_puts(xml, ">");
|
||||
escape_xml(xml, node->as.code.literal.data, node->as.code.literal.len);
|
||||
cmark_strbuf_puts(xml, "</");
|
||||
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
|
||||
literal = true;
|
||||
break;
|
||||
case CMARK_NODE_LINK:
|
||||
case CMARK_NODE_IMAGE:
|
||||
cmark_strbuf_puts(xml, " destination=\"");
|
||||
escape_xml(xml, node->as.link.url.data, node->as.link.url.len);
|
||||
cmark_strbuf_putc(xml, '"');
|
||||
cmark_strbuf_puts(xml, " title=\"");
|
||||
escape_xml(xml, node->as.link.title.data, node->as.link.title.len);
|
||||
cmark_strbuf_putc(xml, '"');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (node->first_child) {
|
||||
state->indent += 2;
|
||||
} else if (!literal) {
|
||||
cmark_strbuf_puts(xml, " /");
|
||||
}
|
||||
cmark_strbuf_puts(xml, ">\n");
|
||||
|
||||
} else if (node->first_child) {
|
||||
state->indent -= 2;
|
||||
indent(state);
|
||||
cmark_strbuf_puts(xml, "</");
|
||||
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
|
||||
cmark_strbuf_puts(xml, ">\n");
|
||||
}
|
||||
|
||||
} else if (node->first_child) {
|
||||
state->indent -= 2;
|
||||
indent(state);
|
||||
cmark_strbuf_puts(xml, "</");
|
||||
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
|
||||
cmark_strbuf_puts(xml, ">\n");
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *cmark_render_xml(cmark_node *root, int options)
|
||||
{
|
||||
char *result;
|
||||
cmark_strbuf xml = GH_BUF_INIT;
|
||||
cmark_event_type ev_type;
|
||||
cmark_node *cur;
|
||||
struct render_state state = { &xml, 0 };
|
||||
char *cmark_render_xml(cmark_node *root, int options) {
|
||||
char *result;
|
||||
cmark_strbuf xml = GH_BUF_INIT;
|
||||
cmark_event_type ev_type;
|
||||
cmark_node *cur;
|
||||
struct render_state state = {&xml, 0};
|
||||
|
||||
cmark_iter *iter = cmark_iter_new(root);
|
||||
cmark_iter *iter = cmark_iter_new(root);
|
||||
|
||||
cmark_strbuf_puts(state.xml,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
cmark_strbuf_puts(state.xml,
|
||||
"<!DOCTYPE CommonMark SYSTEM \"CommonMark.dtd\">\n");
|
||||
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
||||
cur = cmark_iter_get_node(iter);
|
||||
S_render_node(cur, ev_type, &state, options);
|
||||
}
|
||||
result = (char *)cmark_strbuf_detach(&xml);
|
||||
cmark_strbuf_puts(state.xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
cmark_strbuf_puts(state.xml,
|
||||
"<!DOCTYPE CommonMark SYSTEM \"CommonMark.dtd\">\n");
|
||||
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
||||
cur = cmark_iter_get_node(iter);
|
||||
S_render_node(cur, ev_type, &state, options);
|
||||
}
|
||||
result = (char *)cmark_strbuf_detach(&xml);
|
||||
|
||||
cmark_iter_free(iter);
|
||||
return result;
|
||||
cmark_iter_free(iter);
|
||||
return result;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче