packages feed

sundown 0.1.2 → 0.2

raw patch · 15 files changed

+944/−1049 lines, 15 files

Files

− cbits/array.c
@@ -1,300 +0,0 @@-/* array.c - automatic dynamic array for pointers */--/*- * Copyright (c) 2008, Natacha Porté- *- * Permission to use, copy, modify, and distribute this software for any- * purpose with or without fee is hereby granted, provided that the above- * copyright notice and this permission notice appear in all copies.- *- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.- */--#include "array.h"--#include <string.h>---/***************************- * STATIC HELPER FUNCTIONS *- ***************************/--/* arr_realloc • realloc memory of a struct array */-static int-arr_realloc(struct array* arr, int neosz) {-	void* neo;-	neo = realloc(arr->base, neosz * arr->unit);-	if (neo == 0) return 0;-	arr->base = neo;-	arr->asize = neosz;-	if (arr->size > neosz) arr->size = neosz;-	return 1; }---/* parr_realloc • realloc memory of a struct parray */-static int-parr_realloc(struct parray* arr, int neosz) {-	void* neo;-	neo = realloc(arr->item, neosz * sizeof (void*));-	if (neo == 0) return 0;-	arr->item = neo;-	arr->asize = neosz;-	if (arr->size > neosz) arr->size = neosz;-	return 1; }----/***************************- * GENERIC ARRAY FUNCTIONS *- ***************************/--/* arr_adjust • shrink the allocated memory to fit exactly the needs */-int-arr_adjust(struct array *arr) {-	return arr_realloc(arr, arr->size); }---/* arr_free • frees the structure contents (buf NOT the struct itself) */-void-arr_free(struct array *arr) {-	if (!arr) return;-	free(arr->base);-	arr->base = 0;-	arr->size = arr->asize = 0; }---/* arr_grow • increases the array size to fit the given number of elements */-int-arr_grow(struct array *arr, int need) {-	if (arr->asize >= need) return 1;-	else return arr_realloc(arr, need); }---/* arr_init • initialization of the contents of the struct */-void-arr_init(struct array *arr, size_t unit) {-	arr->base = 0;-	arr->size = arr->asize = 0;-	arr->unit = unit; }---/* arr_insert • inserting nb elements before the nth one */-int-arr_insert(struct array *arr, int nb, int n) {-	char *src, *dst;-	size_t len;-	if (!arr || nb <= 0 || n < 0-	|| !arr_grow(arr, arr->size + nb))-		return 0;-	if (n < arr->size) {-		src = arr->base;-		src += n * arr->unit;-		dst = src + nb * arr->unit;-		len = (arr->size - n) * arr->unit;-		memmove(dst, src, len); }-	arr->size += nb;-	return 1; }---/* arr_item • returns a pointer to the n-th element */-void *-arr_item(struct array *arr, int no) {-	char *ptr;-	if (!arr || no < 0 || no >= arr->size) return 0;-	ptr = arr->base;-	ptr += no * arr->unit;-	return ptr; }---/* arr_newitem • returns the index of a new element appended to the array */-int-arr_newitem(struct array *arr) {-	if (!arr_grow(arr, arr->size + 1)) return -1;-	arr->size += 1;-	return arr->size - 1; }---/* arr_remove • removes the n-th elements of the array */-void-arr_remove(struct array *arr, int idx) {-	if (!arr || idx < 0 || idx >= arr->size) return;-	arr->size -= 1;-	if (idx < arr->size) {-		char *dst = arr->base;-		char *src;-		dst += idx * arr->unit;-		src = dst + arr->unit;-		memmove(dst, src, (arr->size - idx) * arr->unit); } }---/* arr_sorted_find • O(log n) search in a sorted array, returning entry */-void *-arr_sorted_find(struct array *arr, void *key, array_cmp_fn cmp) {-	int mi, ma, cu, ret;-	char *ptr = arr->base;-	mi = -1;-	ma = arr->size;-	while (mi < ma - 1) {-		cu = mi + (ma - mi) / 2;-		ret = cmp(key, ptr + cu * arr->unit);-		if (ret == 0) return ptr + cu * arr->unit;-		else if (ret < 0) ma = cu;-		else /* if (ret > 0) */ mi = cu; }-	return 0; }---/* arr_sorted_find_i • O(log n) search in a sorted array,- *      returning index of the smallest element larger than the key */-int-arr_sorted_find_i(struct array *arr, void *key, array_cmp_fn cmp) {-	int mi, ma, cu, ret;-	char *ptr = arr->base;-	mi = -1;-	ma = arr->size;-	while (mi < ma - 1) {-		cu = mi + (ma - mi) / 2;-		ret = cmp(key, ptr + cu * arr->unit);-		if (ret == 0) {-			while (cu < arr->size && ret == 0) {-				cu += 1;-				ret = cmp(key, ptr + cu * arr->unit); }-			return cu; }-		else if (ret < 0) ma = cu;-		else /* if (ret > 0) */ mi = cu; }-	return ma; }----/***************************- * POINTER ARRAY FUNCTIONS *- ***************************/--/* parr_adjust • shrinks the allocated memory to fit exactly the needs */-int-parr_adjust(struct parray* arr) {-	return parr_realloc (arr, arr->size); }---/* parr_free • frees the structure contents (buf NOT the struct itself) */-void-parr_free(struct parray *arr) {-	if (!arr) return;-	free (arr->item);-	arr->item = 0;-	arr->size = 0;-	arr->asize = 0; }---/* parr_grow • increases the array size to fit the given number of elements */-int-parr_grow(struct parray *arr, int need) {-	if (arr->asize >= need) return 1;-	else return parr_realloc (arr, need); }---/* parr_init • initialization of the struct (which is equivalent to zero) */-void-parr_init(struct parray *arr) {-	arr->item = 0;-	arr->size = 0;-	arr->asize = 0; }---/* parr_insert • inserting nb elements before the nth one */-int-parr_insert(struct parray *parr, int nb, int n) {-	char *src, *dst;-	size_t len, i;-	if (!parr || nb <= 0 || n < 0-	|| !parr_grow(parr, parr->size + nb))-		return 0;-	if (n < parr->size) {-		src = (void *)parr->item;-		src += n * sizeof (void *);-		dst = src + nb * sizeof (void *);-		len = (parr->size - n) * sizeof (void *);-		memmove(dst, src, len);-		for (i = 0; i < (size_t)nb; ++i)-			parr->item[n + i] = 0; }-	parr->size += nb;-	return 1; }---/* parr_pop • pops the last item of the array and returns it */-void *-parr_pop(struct parray *arr) {-	if (arr->size <= 0) return 0;-	arr->size -= 1;-	return arr->item[arr->size]; }---/* parr_push • pushes a pointer at the end of the array (= append) */-int-parr_push(struct parray *arr, void *i) {-	if (!parr_grow(arr, arr->size + 1)) return 0;-	arr->item[arr->size] = i;-	arr->size += 1;-	return 1; }---/* parr_remove • removes the n-th element of the array and returns it */-void *-parr_remove(struct parray *arr, int idx) {-	void* ret;-	int i;-	if (!arr || idx < 0 || idx >= arr->size) return 0;-	ret = arr->item[idx];-	for (i = idx+1; i < arr->size; ++i)-		arr->item[i - 1] = arr->item[i];-	arr->size -= 1;-	return ret; }---/* parr_sorted_find • O(log n) search in a sorted array, returning entry */-void *-parr_sorted_find(struct parray *arr, void *key, array_cmp_fn cmp) {-	int mi, ma, cu, ret;-	mi = -1;-	ma = arr->size;-	while (mi < ma - 1) {-		cu = mi + (ma - mi) / 2;-		ret = cmp(key, arr->item[cu]);-		if (ret == 0) return arr->item[cu];-		else if (ret < 0) ma = cu;-		else /* if (ret > 0) */ mi = cu; }-	return 0; }---/* parr_sorted_find_i • O(log n) search in a sorted array,- *      returning index of the smallest element larger than the key */-int-parr_sorted_find_i(struct parray *arr, void *key, array_cmp_fn cmp) {-	int mi, ma, cu, ret;-	mi = -1;-	ma = arr->size;-	while (mi < ma - 1) {-		cu = mi + (ma - mi) / 2;-		ret = cmp(key, arr->item[cu]);-		if (ret == 0) {-			while (cu < arr->size && ret == 0) {-				cu += 1;-				ret = cmp(key, arr->item[cu]); }-			return cu; }-		else if (ret < 0) ma = cu;-		else /* if (ret > 0) */ mi = cu; }-	return ma; }---/* parr_top • returns the top the stack (i.e. the last element of the array) */-void *-parr_top(struct parray *arr) {-	if (arr == 0 || arr->size <= 0) return 0;-	else return arr->item[arr->size - 1]; }--/* vim: set filetype=c: */
− cbits/array.h
@@ -1,147 +0,0 @@-/* array.h - automatic dynamic array for pointers */--/*- * Copyright (c) 2008, Natacha Porté- *- * Permission to use, copy, modify, and distribute this software for any- * purpose with or without fee is hereby granted, provided that the above- * copyright notice and this permission notice appear in all copies.- *- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.- */--#ifndef LITHIUM_ARRAY_H-#define LITHIUM_ARRAY_H--#include <stdlib.h>--/********************- * TYPE DEFINITIONS *- ********************/--/* struct array • generic linear array */-struct array {-	void*	base;-	int	size;-	int	asize;-	size_t	unit; };---/* struct parray • array of pointers */-struct parray {-	void **	item;-	int	size;-	int	asize; };---/* array_cmp_fn • comparison functions for sorted arrays */-typedef int (*array_cmp_fn)(void *key, void *array_entry);----/***************************- * GENERIC ARRAY FUNCTIONS *- ***************************/--/* arr_adjust • shrink the allocated memory to fit exactly the needs */-int-arr_adjust(struct array *);--/* arr_free • frees the structure contents (buf NOT the struct itself) */-void-arr_free(struct array *);--/* arr_grow • increases the array size to fit the given number of elements */-int-arr_grow(struct array *, int);--/* arr_init • initialization of the contents of the struct */-void-arr_init(struct array *, size_t);--/* arr_insert • inserting elements nb before the nth one */-int-arr_insert(struct array *, int nb, int n);--/* arr_item • returns a pointer to the n-th element */-void *-arr_item(struct array *, int);--/* arr_newitem • returns the index of a new element appended to the array */-int-arr_newitem(struct array *);--/* arr_remove • removes the n-th elements of the array */-void-arr_remove(struct array *, int);--/* arr_sorted_find • O(log n) search in a sorted array, returning entry */-/* equivalent to bsearch(key, arr->base, arr->size, arr->unit, cmp) */-void *-arr_sorted_find(struct array *, void *key, array_cmp_fn cmp);--/* arr_sorted_find_i • O(log n) search in a sorted array,- *      returning index of the smallest element larger than the key */-int-arr_sorted_find_i(struct array *, void *key, array_cmp_fn cmp);---/***************************- * POINTER ARRAY FUNCTIONS *- ***************************/--/* parr_adjust • shrinks the allocated memory to fit exactly the needs */-int-parr_adjust(struct parray *);--/* parr_free • frees the structure contents (buf NOT the struct itself) */-void-parr_free(struct parray *);--/* parr_grow • increases the array size to fit the given number of elements */-int-parr_grow(struct parray *, int);--/* parr_init • initialization of the struct (which is equivalent to zero) */-void-parr_init(struct parray *);--/* parr_insert • inserting nb elements before the nth one */-int-parr_insert(struct parray *, int nb, int n);--/* parr_pop • pops the last item of the array and returns it */-void *-parr_pop(struct parray *);--/* parr_push • pushes a pointer at the end of the array (= append) */-int-parr_push(struct parray *, void *);--/* parr_remove • removes the n-th element of the array and returns it */-void *-parr_remove(struct parray *, int);--/* parr_sorted_find • O(log n) search in a sorted array, returning entry */-void *-parr_sorted_find(struct parray *, void *key, array_cmp_fn cmp);--/* parr_sorted_find_i • O(log n) search in a sorted array,- *      returning index of the smallest element larger than the key */-int-parr_sorted_find_i(struct parray *, void *key, array_cmp_fn cmp);--/* parr_top • returns the top the stack (i.e. the last element of the array) */-void *-parr_top(struct parray *);---#endif /* ndef LITHIUM_ARRAY_H */--/* vim: set filetype=c: */
cbits/autolink.c view
@@ -154,7 +154,7 @@ 	if (offset > 0 && !ispunct(data[-1]) && !isspace(data[-1])) 		return 0; -	if (size < 4 || memcmp(data, "www.", STRLEN("www.")) != 0)+	if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0) 		return 0;  	link_end = check_domain(data, size);@@ -238,7 +238,7 @@  	if (!sd_autolink_issafe(data - rewind, size + rewind)) 		return 0;-	link_end = STRLEN("://");+	link_end = strlen("://");  	domain_len = check_domain(data + link_end, size - link_end); 	if (domain_len == 0)
cbits/buffer.c view
@@ -1,7 +1,6 @@-/* buffer.c - automatic buffer structure */- /*  * Copyright (c) 2008, Natacha Porté+ * Copyright (c) 2011, Vicent Martí  *  * Permission to use, copy, modify, and distribute this software for any  * purpose with or without fee is hereby granted, provided that the above@@ -16,13 +15,6 @@  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  */ -/*- * COMPILE TIME OPTIONS- *- * BUFFER_STATS • if defined, stats are kept about memory usage- */--#define BUFFER_STDARG #define BUFFER_MAX_ALLOC_SIZE (1024 * 1024 * 16) //16mb  #include "buffer.h"@@ -31,77 +23,64 @@ #include <stdlib.h> #include <string.h> --/********************- * GLOBAL VARIABLES *- ********************/--#ifdef BUFFER_STATS-long buffer_stat_nb = 0;-size_t buffer_stat_alloc_bytes = 0;+/* MSVC compat */+#if defined(_MSC_VER)+#	define _buf_vsnprintf _vsnprintf+#else+#	define _buf_vsnprintf vsnprintf #endif --/***************************- * STATIC HELPER FUNCTIONS *- ***************************/--/* lower • retruns the lower-case variant of the input char */-static char-lower(char c) {-	return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c; }+/* bufcmp: buffer comparison */+int+bufcmp(const struct buf *a, const struct buf *b)+{+	size_t i = 0;+	size_t cmplen; +	if (a == b)+		return 0; +	if (!a)+		return -1; -/********************- * BUFFER FUNCTIONS *- ********************/+	if (!b)+		return 1; -/* bufcasecmp • case-insensitive buffer comparison */-int-bufcasecmp(const struct buf *a, const struct buf *b) {-	size_t i = 0;-	size_t cmplen;-	if (a == b) return 0;-	if (!a) return -1; else if (!b) return 1; 	cmplen = (a->size < b->size) ? a->size : b->size;-	while (i < cmplen && lower(a->data[i]) == lower(b->data[i])) ++i;-	if (i < a->size) {-		if (i < b->size)  return lower(a->data[i]) - lower(b->data[i]);-		else		  return 1; }-	else {	if (i < b->size)  return -1;-		else		  return 0; } } +	while (i < cmplen && a->data[i] == b->data[i])+		++i; -/* bufcmp • case-sensitive buffer comparison */-int-bufcmp(const struct buf *a, const struct buf *b) {-	size_t i = 0;-	size_t cmplen;-	if (a == b) return 0;-	if (!a) return -1; else if (!b) return 1;-	cmplen = (a->size < b->size) ? a->size : b->size;-	while (i < cmplen && a->data[i] == b->data[i]) ++i; 	if (i < a->size) {-		if (i < b->size)	return a->data[i] - b->data[i];-		else			return 1; }-	else {	if (i < b->size)	return -1;-		else			return 0; } }-+		if (i < b->size) return a->data[i] - b->data[i];+		return 1;+	} else {+		if (i < b->size) return -1;+		return 0;+	}+} -/* bufcmps • case-sensitive comparison of a string to a buffer */+/* bufcmps: comparison of a string to a buffer */ int-bufcmps(const struct buf *a, const char *b) {+bufcmps(const struct buf *a, const char *b)+{ 	const size_t len = strlen(b); 	size_t cmplen = len; 	int r;-	if (!a || !a->size) return b ? 0 : -1;-	if (len < a->size) cmplen = a->size;++	if (!a || !a->size)+		return b ? 0 : -1;++	if (len < a->size)+		cmplen = a->size;+ 	r = strncmp(a->data, b, cmplen);+ 	if (r) return r; 	else if (a->size == len) return 0; 	else if (a->size < len) return -1;-	else return 1; }+	else return 1;+}  int bufprefix(const struct buf *buf, const char *prefix)@@ -120,199 +99,231 @@ }  -/* bufdup • buffer duplication */+/* bufdup: buffer duplication */ struct buf *-bufdup(const struct buf *src, size_t dupunit) {+bufdup(const struct buf *src, size_t dupunit)+{ 	size_t blocks; 	struct buf *ret;-	if (src == 0) return 0;+	if (src == 0)+		return 0;+ 	ret = malloc(sizeof (struct buf));-	if (ret == 0) return 0;+	if (ret == 0)+		return 0;+ 	ret->unit = dupunit; 	ret->size = src->size; 	ret->ref = 1; 	if (!src->size) { 		ret->asize = 0; 		ret->data = 0;-		return ret; }+		return ret;+	}+ 	blocks = (src->size + dupunit - 1) / dupunit; 	ret->asize = blocks * dupunit; 	ret->data = malloc(ret->asize);+ 	if (ret->data == 0) { 		free(ret);-		return 0; }+		return 0;+	}+ 	memcpy(ret->data, src->data, src->size);-#ifdef BUFFER_STATS-	buffer_stat_nb += 1;-	buffer_stat_alloc_bytes += ret->asize;-#endif-	return ret; }+	return ret;+} -/* bufgrow • increasing the allocated size to the given value */+/* bufgrow: increasing the allocated size to the given value */ int-bufgrow(struct buf *buf, size_t neosz) {+bufgrow(struct buf *buf, size_t neosz)+{ 	size_t neoasz; 	void *neodata;-	if (!buf || !buf->unit || neosz > BUFFER_MAX_ALLOC_SIZE) return 0;-	if (buf->asize >= neosz) return 1;+	if (!buf || !buf->unit || neosz > BUFFER_MAX_ALLOC_SIZE)+		return BUF_ENOMEM;++	if (buf->asize >= neosz)+		return BUF_OK;+ 	neoasz = buf->asize + buf->unit;-	while (neoasz < neosz) neoasz += buf->unit;+	while (neoasz < neosz)+		neoasz += buf->unit;+ 	neodata = realloc(buf->data, neoasz);-	if (!neodata) return 0;-#ifdef BUFFER_STATS-	buffer_stat_alloc_bytes += (neoasz - buf->asize);-#endif+	if (!neodata)+		return BUF_ENOMEM;+ 	buf->data = neodata; 	buf->asize = neoasz;-	return 1; }+	return BUF_OK;+}  -/* bufnew • allocation of a new buffer */+/* bufnew: allocation of a new buffer */ struct buf *-bufnew(size_t unit) {+bufnew(size_t unit)+{ 	struct buf *ret; 	ret = malloc(sizeof (struct buf));+ 	if (ret) {-#ifdef BUFFER_STATS-		buffer_stat_nb += 1;-#endif 		ret->data = 0; 		ret->size = ret->asize = 0; 		ret->ref = 1;-		ret->unit = unit; }-	return ret; }+		ret->unit = unit;+	}+	return ret;+} +/* bufnullterm: NULL-termination of the string array */+const char *+bufcstr(struct buf *buf)+{+	if (!buf || !buf->unit)+		return NULL; -/* bufnullterm • NUL-termination of the string array (making a C-string) */-void-bufnullterm(struct buf *buf) {-	if (!buf || !buf->unit) return;-	if (buf->size < buf->asize && buf->data[buf->size] == 0) return;-	if (buf->size + 1 <= buf->asize || bufgrow(buf, buf->size + 1))-		buf->data[buf->size] = 0; }+	if (buf->size < buf->asize && buf->data[buf->size] == 0)+		return buf->data; +	if (buf->size + 1 <= buf->asize || bufgrow(buf, buf->size + 1) == 0) {+		buf->data[buf->size] = 0;+		return buf->data;+	} -/* bufprintf • formatted printing to a buffer */+	return NULL;+}++/* bufprintf: formatted printing to a buffer */ void-bufprintf(struct buf *buf, const char *fmt, ...) {+bufprintf(struct buf *buf, const char *fmt, ...)+{ 	va_list ap;-	if (!buf || !buf->unit) return;+	if (!buf || !buf->unit)+		return;+ 	va_start(ap, fmt); 	vbufprintf(buf, fmt, ap);-	va_end(ap); }-+	va_end(ap);+} -/* bufput • appends raw data to a buffer */+/* bufput: appends raw data to a buffer */ void-bufput(struct buf *buf, const void *data, size_t len) {-	if (!buf) return;-	if (buf->size + len > buf->asize && !bufgrow(buf, buf->size + len))+bufput(struct buf *buf, const void *data, size_t len)+{+	if (!buf) 		return;-	memcpy(buf->data + buf->size, data, len);-	buf->size += len; } +	if (buf->size + len > buf->asize && bufgrow(buf, buf->size + len) < 0)+		return; -/* bufputs • appends a NUL-terminated string to a buffer */+	memcpy(buf->data + buf->size, data, len);+	buf->size += len;+}++/* bufputs: appends a NUL-terminated string to a buffer */ void-bufputs(struct buf *buf, const char *str) {-	bufput(buf, str, strlen (str)); }+bufputs(struct buf *buf, const char *str)+{+	bufput(buf, str, strlen(str));+}  -/* bufputc • appends a single char to a buffer */+/* bufputc: appends a single char to a buffer */ void-bufputc(struct buf *buf, char c) {-	if (!buf) return;-	if (buf->size + 1 > buf->asize && !bufgrow(buf, buf->size + 1))+bufputc(struct buf *buf, char c)+{+	if (!buf) 		return;-	buf->data[buf->size] = c;-	buf->size += 1; } +	if (buf->size + 1 > buf->asize && bufgrow(buf, buf->size + 1) < 0)+		return; -/* bufrelease • decrease the reference count and free the buffer if needed */+	buf->data[buf->size] = c;+	buf->size += 1;+}++/* bufrelease: decrease the reference count and free the buffer if needed */ void-bufrelease(struct buf *buf) {-	if (!buf) return;-	buf->ref -= 1;-	if (buf->ref == 0) {-#ifdef BUFFER_STATS-		buffer_stat_nb -= 1;-		buffer_stat_alloc_bytes -= buf->asize;-#endif+bufrelease(struct buf *buf)+{+	if (!buf)+		return;++	if (--buf->ref == 0) { 		free(buf->data);-		free(buf); } }+		free(buf);+	}+}  -/* bufreset • frees internal data of the buffer */+/* bufreset: frees internal data of the buffer */ void-bufreset(struct buf *buf) {-	if (!buf) return;-#ifdef BUFFER_STATS-	buffer_stat_alloc_bytes -= buf->asize;-#endif+bufreset(struct buf *buf)+{+	if (!buf)+		return;+ 	free(buf->data);-	buf->data = 0;-	buf->size = buf->asize = 0; }+	buf->data = NULL;+	buf->size = buf->asize = 0;+}  -/* bufset • safely assigns a buffer to another */+/* bufset: safely assigns a buffer to another */ void-bufset(struct buf **dest, struct buf *src) {+bufset(struct buf **dest, struct buf *src)+{ 	if (src) { 		if (!src->asize) src = bufdup(src, 1);-		else src->ref += 1; }-	bufrelease(*dest);-	*dest = src; }+		else src->ref += 1;+	} +	bufrelease(*dest);+	*dest = src;+} -/* bufslurp • removes a given number of bytes from the head of the array */+/* bufslurp: removes a given number of bytes from the head of the array */ void-bufslurp(struct buf *buf, size_t len) {-	if (!buf || !buf->unit || len <= 0) return;+bufslurp(struct buf *buf, size_t len)+{+	if (!buf || !buf->unit || len <= 0)+		return;+ 	if (len >= buf->size) { 		buf->size = 0;-		return; }-	buf->size -= len;-	memmove(buf->data, buf->data + len, buf->size); }---/* buftoi • converts the numbers at the beginning of the buf into an int */-int-buftoi(struct buf *buf, size_t offset_i, size_t *offset_o) {-	int r = 0, neg = 0;-	size_t i = offset_i;-	if (!buf || !buf->size) return 0;-	if (buf->data[i] == '+') i += 1;-	else if (buf->data[i] == '-') {-		neg = 1;-		i += 1; }-	while (i < buf->size && buf->data[i] >= '0' && buf->data[i] <= '9') {-		r = (r * 10) + buf->data[i] - '0';-		i += 1; }-	if (offset_o) *offset_o = i;-	return neg ? -r : r; }-+		return;+	} +	buf->size -= len;+	memmove(buf->data, buf->data + len, buf->size);+} -/* vbufprintf • stdarg variant of formatted printing into a buffer */+/* vbufprintf: stdarg variant of formatted printing into a buffer */ void-vbufprintf(struct buf *buf, const char *fmt, va_list ap) {+vbufprintf(struct buf *buf, const char *fmt, va_list ap)+{ 	int n;-	va_list ap_save;-	if (buf == 0-	|| (buf->size >= buf->asize && !bufgrow (buf, buf->size + 1)))++	if (buf == 0 || (buf->size >= buf->asize && bufgrow(buf, buf->size + 1)) < 0) 		return; -	va_copy(ap_save, ap);-	n = vsnprintf(buf->data + buf->size, buf->asize - buf->size, fmt, ap);+	n = _buf_vsnprintf(buf->data + buf->size, buf->asize - buf->size, fmt, ap); -	if (n < 0 || (size_t)n >= buf->asize - buf->size) {-		size_t new_size = (n > 0) ? n : buf->size;-		if (!bufgrow (buf, buf->size + new_size + 1))+	if (n < 0) {+#ifdef _MSC_VER+		n = _vscprintf(fmt, ap);+#else+		return;+#endif+	}++	if ((size_t)n >= buf->asize - buf->size) {+		if (bufgrow(buf, buf->size + n + 1) < 0) 			return; -		n = vsnprintf(buf->data + buf->size, buf->asize - buf->size, fmt, ap_save);+		n = _buf_vsnprintf(buf->data + buf->size, buf->asize - buf->size, fmt, ap); 	}-	va_end(ap_save);  	if (n < 0) 		return;@@ -320,4 +331,3 @@ 	buf->size += n; } -/* vim: set filetype=c: */
cbits/buffer.h view
@@ -1,7 +1,6 @@-/* buffer.h - automatic buffer structure */- /*  * Copyright (c) 2008, Natacha Porté+ * Copyright (c) 2011, Vicent Martí  *  * Permission to use, copy, modify, and distribute this software for any  * purpose with or without fee is hereby granted, provided that the above@@ -16,139 +15,89 @@  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  */ -#ifndef LITHIUM_BUFFER_H-#define LITHIUM_BUFFER_H+#ifndef __GEN_BUFFER_H__+#define __GEN_BUFFER_H__  #include <stddef.h>+#include <stdarg.h>  #if defined(_MSC_VER) #define __attribute__(x) #define inline-#define strncasecmp _strnicmp-#define snprintf _snprintf-#define va_copy(d,s) ((d) = (s)) #endif -/********************- * TYPE DEFINITIONS *- ********************/+typedef enum {+	BUF_OK = 0,+	BUF_ENOMEM = -1,+} buferror_t; -/* struct buf • character array buffer */+/* struct buf: character array buffer */ struct buf {-	char *	data;	/* actual character data */-	size_t	size;	/* size of the string */-	size_t	asize;	/* allocated size (0 = volatile buffer) */-	size_t	unit;	/* reallocation unit size (0 = read-only buffer) */-	int	ref; };	/* reference count */--/**********- * MACROS *- **********/--#define STRLEN(x) (sizeof(x) - 1)--/* CONST_BUF • global buffer from a string litteral */-#define CONST_BUF(name, string) \-	static struct buf name = { string, sizeof string -1, sizeof string }-+	char *data;		/* actual character data */+	size_t size;	/* size of the string */+	size_t asize;	/* allocated size (0 = volatile buffer) */+	size_t unit;	/* reallocation unit size (0 = read-only buffer) */+	int	ref;		/* reference count */+};	 -/* VOLATILE_BUF • macro for creating a volatile buffer on the stack */-#define VOLATILE_BUF(name, strname) \-	struct buf name = { strname, strlen(strname) }+/* CONST_BUF: global buffer from a string litteral */+#define BUF_STATIC(string) \+	{ string, sizeof string -1, sizeof string, 0, 0 } +/* VOLATILE_BUF: macro for creating a volatile buffer on the stack */+#define BUF_VOLATILE(strname) \+	{ strname, strlen(strname), 0, 0, 0 } -/* BUFPUTSL • optimized bufputs of a string litteral */+/* BUFPUTSL: optimized bufputs of a string litteral */ #define BUFPUTSL(output, litteral) \ 	bufput(output, litteral, sizeof litteral - 1) ---/********************- * BUFFER FUNCTIONS *- ********************/--/* bufcasecmp • case-insensitive buffer comparison */-int-bufcasecmp(const struct buf *, const struct buf *);--/* bufcmp • case-sensitive buffer comparison */-int-bufcmp(const struct buf *, const struct buf *);--/* bufcmps • case-sensitive comparison of a string to a buffer */-int-bufcmps(const struct buf *, const char *);--/* bufprefix * compare the beginning of a buffer with a string */-int-bufprefix(const struct buf *buf, const char *prefix);--/* bufdup • buffer duplication */-struct buf *-bufdup(const struct buf *, size_t)-	__attribute__ ((malloc));--/* bufgrow • increasing the allocated size to the given value */-int-bufgrow(struct buf *, size_t);--/* bufnew • allocation of a new buffer */-struct buf *-bufnew(size_t)-	__attribute__ ((malloc));--/* bufnullterm • NUL-termination of the string array (making a C-string) */-void-bufnullterm(struct buf *);+/* bufcmp: case-sensitive buffer comparison */+int bufcmp(const struct buf *, const struct buf *); -/* bufprintf • formatted printing to a buffer */-void-bufprintf(struct buf *, const char *, ...)-	__attribute__ ((format (printf, 2, 3)));+/* bufcmps: case-sensitive comparison of a string to a buffer */+int bufcmps(const struct buf *, const char *);  -/* bufput • appends raw data to a buffer */-void-bufput(struct buf *, const void*, size_t);+/* bufprefix: compare the beginning of a buffer with a string */+int bufprefix(const struct buf *buf, const char *prefix);  -/* bufputs • appends a NUL-terminated string to a buffer */-void-bufputs(struct buf *, const char*);+/* bufdup: buffer duplication */+struct buf *bufdup(const struct buf *, size_t) __attribute__ ((malloc)); -/* bufputc • appends a single char to a buffer */-void-bufputc(struct buf *, char);+/* bufgrow: increasing the allocated size to the given value */+int bufgrow(struct buf *, size_t); -/* bufrelease • decrease the reference count and free the buffer if needed */-void-bufrelease(struct buf *);+/* bufnew: allocation of a new buffer */+struct buf *bufnew(size_t) __attribute__ ((malloc)); -/* bufreset • frees internal data of the buffer */-void-bufreset(struct buf *);+/* bufnullterm: NUL-termination of the string array (making a C-string) */+const char *bufcstr(struct buf *); -/* bufset • safely assigns a buffer to another */-void-bufset(struct buf **, struct buf *);+/* bufprintf: formatted printing to a buffer */+void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf, 2, 3))); -/* bufslurp • removes a given number of bytes from the head of the array */-void-bufslurp(struct buf *, size_t);+/* bufput: appends raw data to a buffer */+void bufput(struct buf *, const void*, size_t); -/* buftoi • converts the numbers at the beginning of the buf into an int */-int-buftoi(struct buf *, size_t, size_t *);+/* bufputs: appends a NUL-terminated string to a buffer */+void bufputs(struct buf *, const char*); +/* bufputc: appends a single char to a buffer */+void bufputc(struct buf *, char); +/* bufrelease: decrease the reference count and free the buffer if needed */+void bufrelease(struct buf *); -#ifdef BUFFER_STDARG-#include <stdarg.h>+/* bufreset: frees internal data of the buffer */+void bufreset(struct buf *); -/* vbufprintf • stdarg variant of formatted printing into a buffer */-void-vbufprintf(struct buf *, const char*, va_list);+/* bufset: safely assigns a buffer to another */+void bufset(struct buf **, struct buf *); -#endif /* def BUFFER_STDARG */+/* bufslurp: removes a given number of bytes from the head of the array */+void bufslurp(struct buf *, size_t); -#endif /* ndef LITHIUM_BUFFER_H */+/* vbufprintf: stdarg variant of formatted printing into a buffer */+void vbufprintf(struct buf *, const char*, va_list); -/* vim: set filetype=c: */+#endif
cbits/html.c view
@@ -541,24 +541,26 @@ { 	struct html_renderopt *options = opaque; -	while (level > options->toc_data.current_level) {-		if (options->toc_data.current_level > 0)-			BUFPUTSL(ob, "<li>");-		BUFPUTSL(ob, "<ul>\n");-		options->toc_data.current_level++;-	}--	while (level < options->toc_data.current_level) {-		BUFPUTSL(ob, "</ul>");-		if (options->toc_data.current_level > 1)-			BUFPUTSL(ob, "</li>\n");-		options->toc_data.current_level--;+	if (level > options->toc_data.current_level) {+		while (level > options->toc_data.current_level) {+			BUFPUTSL(ob, "<ul>\n<li>\n");+			options->toc_data.current_level++;+		}+	} else if (level < options->toc_data.current_level) {+		BUFPUTSL(ob, "</li>\n");+		while (level < options->toc_data.current_level) {+			BUFPUTSL(ob, "</ul>\n</li>\n");+			options->toc_data.current_level--;+		}+		BUFPUTSL(ob,"<li>\n");+	} else {+		BUFPUTSL(ob,"</li>\n<li>\n"); 	} -	bufprintf(ob, "<li><a href=\"#toc_%d\">", options->toc_data.header_count++);+	bufprintf(ob, "<a href=\"#toc_%d\">", options->toc_data.header_count++); 	if (text) 		bufput(ob, text->data, text->size);-	BUFPUTSL(ob, "</a></li>\n");+	BUFPUTSL(ob, "</a>\n"); }  static void@@ -566,13 +568,10 @@ { 	struct html_renderopt *options = opaque; -	while (options->toc_data.current_level > 1) {-		BUFPUTSL(ob, "</ul></li>\n");+	while (options->toc_data.current_level > 0) {+		BUFPUTSL(ob, "</li>\n</ul>\n"); 		options->toc_data.current_level--; 	}--	if (options->toc_data.current_level)-		BUFPUTSL(ob, "</ul>\n"); }  void
+ cbits/html_blocks.h view
@@ -0,0 +1,205 @@+/* C code produced by gperf version 3.0.3 */+/* Command-line: gperf -N find_block_tag -H hash_block_tag -C -c -E --ignore-case html_block_names.txt  */+/* Computed positions: -k'1-2' */++#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))+/* The character set is not based on ISO-646.  */+error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."+#endif++/* maximum key range = 37, duplicates = 0 */++#ifndef GPERF_DOWNCASE+#define GPERF_DOWNCASE 1+static unsigned char gperf_downcase[256] =+  {+      0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,+     15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,+     30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,+     45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,+     60,  61,  62,  63,  64,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106,+    107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,+    122,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104,+    105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,+    120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,+    135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,+    150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,+    165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,+    180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,+    195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,+    210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,+    225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,+    240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,+    255+  };+#endif++#ifndef GPERF_CASE_STRNCMP+#define GPERF_CASE_STRNCMP 1+static int+gperf_case_strncmp (s1, s2, n)+     register const char *s1;+     register const char *s2;+     register unsigned int n;+{+  for (; n > 0;)+    {+      unsigned char c1 = gperf_downcase[(unsigned char)*s1++];+      unsigned char c2 = gperf_downcase[(unsigned char)*s2++];+      if (c1 != 0 && c1 == c2)+        {+          n--;+          continue;+        }+      return (int)c1 - (int)c2;+    }+  return 0;+}+#endif++#ifdef __GNUC__+__inline+#else+#ifdef __cplusplus+inline+#endif+#endif+static unsigned int+hash_block_tag (str, len)+     register const char *str;+     register unsigned int len;+{+  static const unsigned char asso_values[] =+    {+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+       8, 30, 25, 20, 15, 10, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38,  0, 38,  0, 38,+       5,  5,  5, 15,  0, 38, 38,  0, 15, 10,+       0, 38, 38, 15,  0,  5, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38,  0, 38,+       0, 38,  5,  5,  5, 15,  0, 38, 38,  0,+      15, 10,  0, 38, 38, 15,  0,  5, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38, 38, 38, 38,+      38, 38, 38, 38, 38, 38, 38+    };+  register int hval = len;++  switch (hval)+    {+      default:+        hval += asso_values[(unsigned char)str[1]+1];+      /*FALLTHROUGH*/+      case 1:+        hval += asso_values[(unsigned char)str[0]];+        break;+    }+  return hval;+}++#ifdef __GNUC__+__inline+#ifdef __GNUC_STDC_INLINE__+__attribute__ ((__gnu_inline__))+#endif+#endif+const char *+find_block_tag (str, len)+     register const char *str;+     register unsigned int len;+{+  enum+    {+      TOTAL_KEYWORDS = 23,+      MIN_WORD_LENGTH = 1,+      MAX_WORD_LENGTH = 10,+      MIN_HASH_VALUE = 1,+      MAX_HASH_VALUE = 37+    };++  static const char * const wordlist[] =+    {+      "",+      "p",+      "dl",+      "div",+      "math",+      "table",+      "",+      "ul",+      "del",+      "form",+      "blockquote",+      "figure",+      "ol",+      "fieldset",+      "",+      "h1",+      "",+      "h6",+      "pre",+      "", "",+      "script",+      "h5",+      "noscript",+      "", "",+      "iframe",+      "h4",+      "ins",+      "", "", "",+      "h3",+      "", "", "", "",+      "h2"+    };++  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)+    {+      register int key = hash_block_tag (str, len);++      if (key <= MAX_HASH_VALUE && key >= 0)+        {+          register const char *s = wordlist[key];++          if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0')+            return s;+        }+    }+  return 0;+}
cbits/markdown.c view
@@ -18,49 +18,58 @@  */  #include "markdown.h"-#include "array.h"+#include "stack.h"  #include <assert.h> #include <string.h>-//#include <strings.h> /* for strncasecmp */ #include <ctype.h> #include <stdio.h> +#define REF_TABLE_SIZE 8+ #define BUFFER_BLOCK 0 #define BUFFER_SPAN 1  #define MKD_LI_END 8	/* internal list flag */ +#define gperf_case_strncmp(s1, s2, n) strncasecmp(s1, s2, n)+#define GPERF_DOWNCASE 1+#define GPERF_CASE_STRNCMP 1+#include "html_blocks.h"+ /***************  * LOCAL TYPES *  ***************/ -/* link_ref • reference to a link */+/* link_ref: reference to a link */ struct link_ref {-	struct buf *id;-	struct buf *link;-	struct buf *title;+	unsigned int id;++	struct buf link;+	struct buf title;++	struct link_ref *next; }; -/* char_trigger • function pointer to render active chars */+/* char_trigger: function pointer to render active chars */ /*   returns the number of chars taken care of */ /*   data is the pointer of the beginning of the span */ /*   offset is the number of valid chars before data */-struct render;+struct sd_markdown; typedef size_t-(*char_trigger)(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);+(*char_trigger)(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size); -static size_t char_emphasis(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);-static size_t char_linebreak(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);-static size_t char_codespan(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);-static size_t char_escape(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);-static size_t char_entity(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);-static size_t char_langle_tag(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);-static size_t char_autolink_url(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);-static size_t char_autolink_email(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);-static size_t char_autolink_www(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);-static size_t char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);-static size_t char_superscript(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);+static size_t char_emphasis(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size);+static size_t char_linebreak(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size);+static size_t char_codespan(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size);+static size_t char_escape(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size);+static size_t char_entity(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size);+static size_t char_langle_tag(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size);+static size_t char_autolink_url(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size);+static size_t char_autolink_email(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size);+static size_t char_autolink_www(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size);+static size_t char_link(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size);+static size_t char_superscript(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size);  enum markdown_char_t { 	MD_CHAR_NONE = 0,@@ -93,84 +102,46 @@ };  /* render • structure containing one particular render */-struct render {+struct sd_markdown { 	struct sd_callbacks	cb; 	void *opaque; -	struct array refs;+	struct link_ref *refs[REF_TABLE_SIZE]; 	char active_char[256];-	struct parray work_bufs[2];+	struct stack work_bufs[2]; 	unsigned int ext_flags; 	size_t max_nesting; }; -/* html_tag • structure for quick HTML tag search (inspired from discount) */-struct html_tag {-	const char *text;-	size_t size;-};+/***************************+ * HELPER FUNCTIONS *+ ***************************/  static inline struct buf *-rndr_newbuf(struct render *rndr, int type)+rndr_newbuf(struct sd_markdown *rndr, int type) { 	static const size_t buf_size[2] = {256, 64}; 	struct buf *work = NULL;-	struct parray *queue = &rndr->work_bufs[type];+	struct stack *pool = &rndr->work_bufs[type]; -	if (queue->size < queue->asize) {-		work = queue->item[queue->size++];+	if (pool->size < pool->asize &&+		pool->item[pool->size] != NULL) {+		work = pool->item[pool->size++]; 		work->size = 0; 	} else { 		work = bufnew(buf_size[type]);-		parr_push(queue, work);+		stack_push(pool, work); 	}  	return work; }  static inline void-rndr_popbuf(struct render *rndr, int type)+rndr_popbuf(struct sd_markdown *rndr, int type) { 	rndr->work_bufs[type].size--; } -/********************- * GLOBAL VARIABLES *- ********************/--/* block_tags • recognised block tags, sorted by cmp_html_tag */-static struct html_tag block_tags[] = {-/*0*/	{ "p",		1 },-	{ "dl",		2 },-	{ "h1",		2 },-	{ "h2",		2 },-	{ "h3",		2 },-	{ "h4",		2 },-	{ "h5",		2 },-	{ "h6",		2 },-	{ "ol",		2 },-	{ "ul",		2 },-	{ "del",	3 }, /* 10 */-	{ "div",	3 },-	{ "ins",	3 }, /* 12 */-	{ "pre",	3 },-	{ "form",	4 },-	{ "math",	4 },-	{ "table",	5 },-	{ "figure",	6 },-	{ "iframe",	6 },-	{ "script",	6 },-	{ "fieldset",	8 },-	{ "noscript",	8 },-	{ "blockquote",	10 }-};--#define INS_TAG (block_tags + 12)-#define DEL_TAG (block_tags + 10)--/***************************- * HELPER FUNCTIONS *- ***************************/ static void unscape_text(struct buf *ob, struct buf *src) {@@ -191,54 +162,72 @@ 	} } -/* cmp_link_ref • comparison function for link_ref sorted arrays */-static int-cmp_link_ref(void *key, void *array_entry)+static unsigned int+hash_link_ref(char *link_ref, size_t length) {-	struct link_ref *lr = array_entry;-	return bufcasecmp(key, lr->id);+	size_t i;+	unsigned int hash = 0;++	for (i = 0; i < length; ++i)+		hash = tolower(link_ref[i]) + (hash << 6) + (hash << 16) - hash;++	return hash; } -/* cmp_link_ref_sort • comparison function for link_ref qsort */-static int-cmp_link_ref_sort(const void *a, const void *b)+static void add_link_ref(+	struct link_ref **references,+	char *name, size_t name_size,+	char *link, size_t link_size,+	char *title, size_t title_size) {-	const struct link_ref *lra = a;-	const struct link_ref *lrb = b;-	return bufcasecmp(lra->id, lrb->id);+	struct link_ref *ref = calloc(1, sizeof(struct link_ref));++	if (!ref)+		return;++	ref->id = hash_link_ref(name, name_size);+	ref->next = references[ref->id % REF_TABLE_SIZE];++	ref->link.data = link;+	ref->link.size = link_size;++	ref->title.data = title;+	ref->title.size = title_size;++	references[ref->id % REF_TABLE_SIZE] = ref; } -/* cmp_html_tag • comparison function for bsearch() (stolen from discount) */-static int-cmp_html_tag(const void *a, const void *b)+static struct link_ref *+find_link_ref(struct link_ref **references, char *name, size_t length) {-	const struct html_tag *hta = a;-	const struct html_tag *htb = b;-	if (hta->size != htb->size) return (int)(hta->size - htb->size);-	return strncasecmp(hta->text, htb->text, hta->size);-}+	unsigned int hash = hash_link_ref(name, length);+	struct link_ref *ref = NULL; +	ref = references[hash % REF_TABLE_SIZE]; -/* find_block_tag • returns the current block tag */-static struct html_tag *-find_block_tag(char *data, size_t size)+	while (ref != NULL) {+		if (ref->id == hash)+			return ref;++		ref = ref->next;+	}++	return NULL;+}++static void+free_link_refs(struct link_ref **references) {-	size_t i = 0;-	struct html_tag key;+	size_t i; -	/* looking for the word end */-	while (i < size && ((data[i] >= '0' && data[i] <= '9')-				|| (data[i] >= 'A' && data[i] <= 'Z')-				|| (data[i] >= 'a' && data[i] <= 'z')))-		i++;-	if (i >= size) return 0;+	for (i = 0; i < REF_TABLE_SIZE; ++i) {+		struct link_ref *r = references[i];+		struct link_ref *next; -	/* binary search of the tag */-	key.text = data;-	key.size = i;-	return bsearch(&key, block_tags,-				sizeof block_tags / sizeof block_tags[0],-				sizeof block_tags[0], cmp_html_tag);+		while (r) {+			next = r->next; free(r); r = next;+		}+	} }  /****************************@@ -340,7 +329,7 @@  /* parse_inline • parses inline markdown elements */ static void-parse_inline(struct buf *ob, struct render *rndr, char *data, size_t size)+parse_inline(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size) { 	size_t i = 0, end = 0; 	char action = 0;@@ -371,10 +360,10 @@ 		end = markdown_char_ptrs[(int)action](ob, rndr, data + i, i, size - i); 		if (!end) /* no action from the callback */ 			end = i + 1;-		else { +		else { 			i += end; 			end = i;-		} +		} 	} } @@ -440,12 +429,20 @@ 			if (i >= size) 				return tmp_i; -			if (data[i] != '[' && data[i] != '(') { /* not a link*/-				if (tmp_i) return tmp_i;-				else continue;+			switch (data[i]) {+			case '[':+				cc = ']'; break;++			case '(':+				cc = ')'; break;++			default:+				if (tmp_i)+					return tmp_i;+				else+					continue; 			} -			cc = data[i]; 			i++; 			while (i < size && data[i] != cc) { 				if (!tmp_i && data[i] == c) tmp_i = i;@@ -465,7 +462,7 @@ /* parse_emph1 • parsing single emphase */ /* closed by a symbol not preceded by whitespace and not followed by symbol */ static size_t-parse_emph1(struct buf *ob, struct render *rndr, char *data, size_t size, char c)+parse_emph1(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size, char c) { 	size_t i = 0, len; 	struct buf *work = 0;@@ -482,11 +479,6 @@ 		i += len; 		if (i >= size) return 0; -		if (i + 1 < size && data[i + 1] == c) {-			i++;-			continue;-		}- 		if (data[i] == c && !isspace(data[i - 1])) {  			if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) {@@ -507,7 +499,7 @@  /* parse_emph2 • parsing single emphase */ static size_t-parse_emph2(struct buf *ob, struct render *rndr, char *data, size_t size, char c)+parse_emph2(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size, char c) { 	int (*render_method)(struct buf *ob, struct buf *text, void *opaque); 	size_t i = 0, len;@@ -518,7 +510,7 @@  	if (!render_method) 		return 0;-	+ 	while (i < size) { 		len = find_emph_char(data + i, size - i, c); 		if (!len) return 0;@@ -539,7 +531,7 @@ /* parse_emph3 • parsing single emphase */ /* finds the first closing tag, and delegates to the other emph */ static size_t-parse_emph3(struct buf *ob, struct render *rndr, char *data, size_t size, char c)+parse_emph3(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size, char c) { 	size_t i = 0, len; 	int r;@@ -575,12 +567,12 @@ 			else return len - 1; 		} 	}-	return 0; +	return 0; }  /* char_emphasis • single and double emphasis parsing */ static size_t-char_emphasis(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)+char_emphasis(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size) { 	char c = data[0]; 	size_t ret;@@ -608,13 +600,13 @@ 		return ret + 3; 	} -	return 0; +	return 0; }   /* char_linebreak • '\n' preceded by two spaces (assuming linebreak != 0) */ static size_t-char_linebreak(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)+char_linebreak(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size) { 	if (offset < 2 || data[-1] != ' ' || data[-2] != ' ') 		return 0;@@ -629,7 +621,7 @@  /* char_codespan • '`' parsing a code span (assuming codespan != 0) */ static size_t-char_codespan(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)+char_codespan(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size) { 	size_t end, nb = 0, i, f_begin, f_end; @@ -672,7 +664,7 @@  /* char_escape • '\\' backslash escape */ static size_t-char_escape(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)+char_escape(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size) { 	static const char *escape_chars = "\\`*_{}[]()#+-.!:|&<>"; 	struct buf work = { 0, 0, 0, 0, 0 };@@ -695,7 +687,7 @@ /* char_entity • '&' escaped when it doesn't belong to an entity */ /* valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; */ static size_t-char_entity(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)+char_entity(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size) { 	size_t end = 1; 	struct buf work;@@ -723,7 +715,7 @@  /* char_langle_tag • '<' when tags or autolinks are allowed */ static size_t-char_langle_tag(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)+char_langle_tag(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size) { 	enum mkd_autolink altype = MKDA_NOT_AUTOLINK; 	size_t end = tag_length(data, size, &altype);@@ -748,7 +740,7 @@ }  static size_t-char_autolink_www(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)+char_autolink_www(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size) { 	struct buf *link, *link_url; 	size_t link_len, rewind;@@ -773,7 +765,7 @@ }  static size_t-char_autolink_email(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)+char_autolink_email(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size) { 	struct buf *link; 	size_t link_len, rewind;@@ -793,7 +785,7 @@ }  static size_t-char_autolink_url(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)+char_autolink_url(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size) { 	struct buf *link; 	size_t link_len, rewind;@@ -814,7 +806,7 @@  /* char_link • '[': parsing a link or an image */ static size_t-char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)+char_link(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size) { 	int is_img = (offset && data[-1] == '!'), level; 	size_t i = 1, txt_e, link_b = 0, link_e = 0, title_b = 0, title_e = 0;@@ -961,12 +953,14 @@ 			id.size = link_e - link_b; 		} -		lr = arr_sorted_find(&rndr->refs, &id, cmp_link_ref);-		if (!lr) goto cleanup;+		lr = find_link_ref(rndr->refs, id.data, id.size);+		if (!lr)+			goto cleanup;  		/* keeping link and title from link_ref */-		link = lr->link;-		title = lr->title;+		link = &lr->link;+		if (lr->title.size)+			title = &lr->title; 		i++; 	} @@ -995,12 +989,14 @@ 		}  		/* finding the link_ref */-		lr = arr_sorted_find(&rndr->refs, &id, cmp_link_ref);-		if (!lr) goto cleanup;+		lr = find_link_ref(rndr->refs, id.data, id.size);+		if (!lr)+			goto cleanup;  		/* keeping link and title from link_ref */-		link = lr->link;-		title = lr->title;+		link = &lr->link;+		if (lr->title.size)+			title = &lr->title;  		/* rewinding the whitespace */ 		i = txt_e + 1;@@ -1035,7 +1031,7 @@ }  static size_t-char_superscript(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)+char_superscript(struct buf *ob, struct sd_markdown *rndr, char *data, size_t offset, size_t size) { 	size_t sup_start, sup_len; 	struct buf *sup;@@ -1191,7 +1187,7 @@  /* is_atxheader • returns whether the line is a hash-prefixed header */ static int-is_atxheader(struct render *rndr, char *data, size_t size)+is_atxheader(struct sd_markdown *rndr, char *data, size_t size) { 	if (data[0] != '#') 		return 0;@@ -1230,6 +1226,20 @@ 	return 0; } +static int+is_next_headerline(char *data, size_t size)+{+	size_t i = 0;+	+	while (i < size && data[i] != '\n')+		i++;++	if (++i >= size)+		return 0;++	return is_headerline(data + i, size - i);+}+ /* prefix_quote • returns blockquote prefix length */ static size_t prefix_quote(char *data, size_t size)@@ -1260,13 +1270,25 @@ prefix_oli(char *data, size_t size) { 	size_t i = 0;+ 	if (i < size && data[i] == ' ') i++; 	if (i < size && data[i] == ' ') i++; 	if (i < size && data[i] == ' ') i++;-	if (i >= size || data[i] < '0' || data[i] > '9') return 0;-	while (i < size && data[i] >= '0' && data[i] <= '9') i++;-	if (i + 1 >= size || data[i] != '.'-	|| (data[i + 1] != ' ' && data[i + 1] != '\t')) return 0;++	if (i >= size || data[i] < '0' || data[i] > '9')+		return 0;++	while (i < size && data[i] >= '0' && data[i] <= '9')+		i++;++	if (i + 1 >= size ||+		data[i] != '.' ||+		(data[i + 1] != ' ' && data[i + 1] != '\t'))+		return 0;++	if (is_next_headerline(data + i, size - i))+		return 0;+ 	return i + 2; } @@ -1275,25 +1297,31 @@ prefix_uli(char *data, size_t size) { 	size_t i = 0;+ 	if (i < size && data[i] == ' ') i++; 	if (i < size && data[i] == ' ') i++; 	if (i < size && data[i] == ' ') i++;-	if (i + 1 >= size-	|| (data[i] != '*' && data[i] != '+' && data[i] != '-')-	|| (data[i + 1] != ' ' && data[i + 1] != '\t'))++	if (i + 1 >= size || +		(data[i] != '*' && data[i] != '+' && data[i] != '-') ||+		(data[i + 1] != ' ' && data[i + 1] != '\t')) 		return 0;++	if (is_next_headerline(data + i, size - i))+		return 0;+ 	return i + 2; }   /* parse_block • parsing of one block, returning next char to parse */-static void parse_block(struct buf *ob, struct render *rndr,+static void parse_block(struct buf *ob, struct sd_markdown *rndr, 			char *data, size_t size);   /* parse_blockquote • handles parsing of a blockquote fragment */ static size_t-parse_blockquote(struct buf *ob, struct render *rndr, char *data, size_t size)+parse_blockquote(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size) { 	size_t beg, end = 0, pre, work_size = 0; 	char *work_data = 0;@@ -1334,11 +1362,11 @@ }  static size_t-parse_htmlblock(struct buf *ob, struct render *rndr, char *data, size_t size, int do_render);+parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size, int do_render);  /* parse_blockquote • handles parsing of a regular paragraph */ static size_t-parse_paragraph(struct buf *ob, struct render *rndr, char *data, size_t size)+parse_paragraph(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size) { 	size_t i = 0, end = 0; 	int level = 0;@@ -1418,7 +1446,7 @@  /* parse_fencedcode • handles parsing of a block-level code fragment */ static size_t-parse_fencedcode(struct buf *ob, struct render *rndr, char *data, size_t size)+parse_fencedcode(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size) { 	size_t beg, end; 	struct buf *work = 0;@@ -1461,7 +1489,7 @@ }  static size_t-parse_blockcode(struct buf *ob, struct render *rndr, char *data, size_t size)+parse_blockcode(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size) { 	size_t beg, end, pre; 	struct buf *work = 0;@@ -1504,7 +1532,7 @@ /* parse_listitem • parsing of a single list item */ /*	assuming initial prefix is already removed */ static size_t-parse_listitem(struct buf *ob, struct render *rndr, char *data, size_t size, int *flags)+parse_listitem(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size, int *flags) { 	struct buf *work = 0, *inter = 0; 	size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;@@ -1594,7 +1622,7 @@ 		/* intermediate render of block li */ 		if (sublist && sublist < work->size) { 			parse_block(inter, rndr, work->data, sublist);-			parse_block(inter, rndr, work->data + sublist, work->size - sublist); +			parse_block(inter, rndr, work->data + sublist, work->size - sublist); 		} 		else 			parse_block(inter, rndr, work->data, work->size);@@ -1620,7 +1648,7 @@  /* parse_list • parsing ordered or unordered list block */ static size_t-parse_list(struct buf *ob, struct render *rndr, char *data, size_t size, int flags)+parse_list(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size, int flags) { 	struct buf *work = 0; 	size_t i = 0, j;@@ -1643,7 +1671,7 @@  /* parse_atxheader • parsing of atx-style headers */ static size_t-parse_atxheader(struct buf *ob, struct render *rndr, char *data, size_t size)+parse_atxheader(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size) { 	size_t level = 0; 	size_t i, end, skip;@@ -1680,20 +1708,18 @@ /* htmlblock_end • checking end of HTML block : </tag>[ \t]*\n[ \t*]\n */ /*	returns the length on match, 0 otherwise */ static size_t-htmlblock_end(struct html_tag *tag, struct render *rndr, char *data, size_t size)+htmlblock_end(const char *tag, size_t tag_len, struct sd_markdown *rndr, char *data, size_t size) { 	size_t i, w; -	/* assuming data[0] == '<' && data[1] == '/' already tested */- 	/* checking if tag is a match */-	if (tag->size + 3 >= size-	|| strncasecmp(data + 2, tag->text, tag->size)-	|| data[tag->size + 2] != '>')+	if (tag_len + 3 >= size ||+		strncasecmp(data + 2, tag, tag_len) != 0 ||+		data[tag_len + 2] != '>') 		return 0;  	/* checking white lines */-	i = tag->size + 3;+	i = tag_len + 3; 	w = 0; 	if (i < size && (w = is_empty(data + i, size - i)) == 0) 		return 0; /* non-blank after tag */@@ -1714,10 +1740,10 @@  /* parse_htmlblock • parsing of inline HTML block */ static size_t-parse_htmlblock(struct buf *ob, struct render *rndr, char *data, size_t size, int do_render)+parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size, int do_render) { 	size_t i, j = 0;-	struct html_tag *curtag;+	const char *curtag; 	int found; 	struct buf work = { data, 0, 0, 0, 0 }; @@ -1745,7 +1771,7 @@ 				if (do_render && rndr->cb.blockhtml) 					rndr->cb.blockhtml(ob, &work, rndr->opaque); 				return work.size;-			} +			} 		}  		/* HR, which is the only self-closing block tag considered */@@ -1763,7 +1789,7 @@ 						rndr->cb.blockhtml(ob, &work, rndr->opaque); 					return work.size; 				}-			} +			} 		}  		/* no special case recognised */@@ -1777,24 +1803,25 @@  	/* if not found, trying a second pass looking for indented match */ 	/* but not if tag is "ins" or "del" (following original Markdown.pl) */-	if (curtag != INS_TAG && curtag != DEL_TAG) {+	if (strcmp(curtag, "ins") != 0 && strcmp(curtag, "del") != 0) {+		size_t tag_size = strlen(curtag); 		i = 1; 		while (i < size) { 			i++; 			while (i < size && !(data[i - 1] == '<' && data[i] == '/')) 				i++; -			if (i + 2 + curtag->size >= size)+			if (i + 2 + tag_size >= size) 				break; -			j = htmlblock_end(curtag, rndr, data + i - 1, size - i + 1);+			j = htmlblock_end(curtag, tag_size, rndr, data + i - 1, size - i + 1);  			if (j) { 				i += j - 1; 				found = 1; 				break; 			}-		} +		} 	}  	if (!found) return 0;@@ -1808,7 +1835,7 @@ }  static void-parse_table_row(struct buf *ob, struct render *rndr, char *data, size_t size, size_t columns, int *col_data)+parse_table_row(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size, size_t columns, int *col_data) { 	size_t i = 0, col; 	struct buf *row_work = 0;@@ -1858,7 +1885,7 @@ }  static size_t-parse_table_header(struct buf *ob, struct render *rndr, char *data, size_t size, size_t *columns, int **column_data)+parse_table_header(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size, size_t *columns, int **column_data) { 	int pipes; 	size_t i = 0, col, header_end, under_end;@@ -1933,7 +1960,7 @@ }  static size_t-parse_table(struct buf *ob, struct render *rndr, char *data, size_t size)+parse_table(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size) { 	size_t i; @@ -1980,7 +2007,7 @@  /* parse_block • parsing of one block, returning next char to parse */ static void-parse_block(struct buf *ob, struct render *rndr, char *data, size_t size)+parse_block(struct buf *ob, struct sd_markdown *rndr, char *data, size_t size) { 	size_t beg, end, i; 	char *txt_data;@@ -2047,7 +2074,7 @@  /* is_ref • returns whether a line is a reference or not */ static int-is_ref(char *data, size_t beg, size_t end, size_t *last, struct array *refs)+is_ref(char *data, size_t beg, size_t end, size_t *last, struct link_ref **refs) { /*	int n; */ 	size_t i = 0;@@ -2055,8 +2082,6 @@ 	size_t link_offset, link_end; 	size_t title_offset, title_end; 	size_t line_end;-	struct link_ref *lr;-/*	struct buf id = { 0, 0, 0, 0, 0 }; / * volatile buf for id search */  	/* up to 3 optional leading spaces */ 	if (beg + 3 >= end) return 0;@@ -2130,22 +2155,33 @@ 		&& (data[i] == '\'' || data[i] == '"' || data[i] == ')')) { 			line_end = title_end; 			title_end = i; } }-	if (!line_end) return 0; /* garbage after the link */ +	if (!line_end)+		return 0; /* garbage after the link */+ 	/* a valid ref has been found, filling-in return structures */-	if (last) *last = line_end;-	if (!refs) return 1;-	lr = arr_item(refs, arr_newitem(refs));-	lr->id = bufnew(id_end - id_offset);-	bufput(lr->id, data + id_offset, id_end - id_offset);-	lr->link = bufnew(link_end - link_offset);-	bufput(lr->link, data + link_offset, link_end - link_offset);-	if (title_end > title_offset) {-		lr->title = bufnew(title_end - title_offset);-		bufput(lr->title, data + title_offset,-					title_end - title_offset); }-	else lr->title = 0;-	return 1; +	if (last)+		*last = line_end;++	if (refs) {+		char *title_str = NULL;+		size_t title_size = 0;++		if (title_end > title_offset) {+			title_str = data + title_offset;+			title_size = title_end - title_offset;+		}++		add_link_ref( refs,+			data + id_offset, /* identifier */+			id_end - id_offset,+			data + link_offset, /* link url */+			link_end - link_offset,+			title_str, /* title (optional) */+			title_size);+	}++	return 1; }  static void expand_tabs(struct buf *ob, const char *line, size_t size)@@ -2177,80 +2213,87 @@  * EXPORTED FUNCTIONS *  **********************/ -/* markdown • parses the input buffer and renders it into the output buffer */-void-sd_markdown(struct buf *ob,-	const struct buf *ib,+struct sd_markdown *+sd_markdown_new( 	unsigned int extensions,+	size_t max_nesting, 	const struct sd_callbacks *callbacks,-	void *opaque) {--	static const float MARKDOWN_GROW_FACTOR = 1.4f;--	struct link_ref *lr;-	struct buf *text;-	size_t i, beg, end;-	struct render rndr;--	/* filling the render structure */-	if (!callbacks)-		return;+	void *opaque)+{+	struct sd_markdown *md = NULL; -	text = bufnew(64);-	if (!text)-		return;+	assert(max_nesting > 0 && callbacks); -	/* Preallocate enough space for our buffer to avoid expanding while copying */-	bufgrow(text, ib->size);+	md = malloc(sizeof(struct sd_markdown));+	if (!md)+		return NULL; -	memcpy(&rndr.cb, callbacks, sizeof(struct sd_callbacks));-	arr_init(&rndr.refs, sizeof (struct link_ref));-	parr_init(&rndr.work_bufs[BUFFER_BLOCK]);-	parr_init(&rndr.work_bufs[BUFFER_SPAN]);+	memcpy(&md->cb, callbacks, sizeof(struct sd_callbacks)); -/*	for (i = 0; i < 256; i++)-		rndr.active_char[i] = 0; */+	stack_init(&md->work_bufs[BUFFER_BLOCK], 4);+	stack_init(&md->work_bufs[BUFFER_SPAN], 8); -	memset(rndr.active_char, 0x0, 256);+	memset(md->active_char, 0x0, 256); -	if (rndr.cb.emphasis || rndr.cb.double_emphasis || rndr.cb.triple_emphasis) {-		rndr.active_char['*'] = MD_CHAR_EMPHASIS;-		rndr.active_char['_'] = MD_CHAR_EMPHASIS;+	if (md->cb.emphasis || md->cb.double_emphasis || md->cb.triple_emphasis) {+		md->active_char['*'] = MD_CHAR_EMPHASIS;+		md->active_char['_'] = MD_CHAR_EMPHASIS; 		if (extensions & MKDEXT_STRIKETHROUGH)-			rndr.active_char['~'] = MD_CHAR_EMPHASIS;+			md->active_char['~'] = MD_CHAR_EMPHASIS; 	} -	if (rndr.cb.codespan)-		rndr.active_char['`'] = MD_CHAR_CODESPAN;+	if (md->cb.codespan)+		md->active_char['`'] = MD_CHAR_CODESPAN; -	if (rndr.cb.linebreak)-		rndr.active_char['\n'] = MD_CHAR_LINEBREAK;+	if (md->cb.linebreak)+		md->active_char['\n'] = MD_CHAR_LINEBREAK; -	if (rndr.cb.image || rndr.cb.link)-		rndr.active_char['['] = MD_CHAR_LINK;+	if (md->cb.image || md->cb.link)+		md->active_char['['] = MD_CHAR_LINK; -	rndr.active_char['<'] = MD_CHAR_LANGLE;-	rndr.active_char['\\'] = MD_CHAR_ESCAPE;-	rndr.active_char['&'] = MD_CHAR_ENTITITY;+	md->active_char['<'] = MD_CHAR_LANGLE;+	md->active_char['\\'] = MD_CHAR_ESCAPE;+	md->active_char['&'] = MD_CHAR_ENTITITY;  	if (extensions & MKDEXT_AUTOLINK) {-		rndr.active_char[':'] = MD_CHAR_AUTOLINK_URL;-		rndr.active_char['@'] = MD_CHAR_AUTOLINK_EMAIL;-		rndr.active_char['w'] = MD_CHAR_AUTOLINK_WWW;+		md->active_char[':'] = MD_CHAR_AUTOLINK_URL;+		md->active_char['@'] = MD_CHAR_AUTOLINK_EMAIL;+		md->active_char['w'] = MD_CHAR_AUTOLINK_WWW; 	}  	if (extensions & MKDEXT_SUPERSCRIPT)-		rndr.active_char['^'] = MD_CHAR_SUPERSCRIPT;+		md->active_char['^'] = MD_CHAR_SUPERSCRIPT;  	/* Extension data */-	rndr.ext_flags = extensions;-	rndr.opaque = opaque;-	rndr.max_nesting = 16;+	md->ext_flags = extensions;+	md->opaque = opaque;+	md->max_nesting = max_nesting; +	return md;+}++void+sd_markdown_render(struct buf *ob, const struct buf *ib, struct sd_markdown *md)+{+	static const float MARKDOWN_GROW_FACTOR = 1.4f;++	struct buf *text;+	size_t beg, end;++	text = bufnew(64);+	if (!text)+		return;++	/* Preallocate enough space for our buffer to avoid expanding while copying */+	bufgrow(text, ib->size);++	/* reset the references table */+	memset(&md->refs, 0x0, REF_TABLE_SIZE * sizeof(void *));+ 	/* first pass: looking for references, copying everything else */ 	beg = 0; 	while (beg < ib->size) /* iterating over lines */-		if (is_ref(ib->data, beg, ib->size, &end, &rndr.refs))+		if (is_ref(ib->data, beg, ib->size, &end, md->refs)) 			beg = end; 		else { /* skipping to the next line */ 			end = beg;@@ -2271,50 +2314,47 @@ 			beg = end; 		} -	/* sorting the reference array */-	if (rndr.refs.size)-		qsort(rndr.refs.base, rndr.refs.size, rndr.refs.unit, cmp_link_ref_sort);- 	/* pre-grow the output buffer to minimize allocations */ 	bufgrow(ob, text->size * MARKDOWN_GROW_FACTOR);  	/* second pass: actual rendering */-	if (rndr.cb.doc_header)-		rndr.cb.doc_header(ob, rndr.opaque);+	if (md->cb.doc_header)+		md->cb.doc_header(ob, md->opaque);  	if (text->size) { 		/* adding a final newline if not already present */ 		if (text->data[text->size - 1] != '\n' &&  text->data[text->size - 1] != '\r') 			bufputc(text, '\n'); -		parse_block(ob, &rndr, text->data, text->size);+		parse_block(ob, md, text->data, text->size); 	} -	if (rndr.cb.doc_footer)-		rndr.cb.doc_footer(ob, rndr.opaque);+	if (md->cb.doc_footer)+		md->cb.doc_footer(ob, md->opaque);  	/* clean-up */ 	bufrelease(text);-	lr = rndr.refs.base;-	for (i = 0; i < (size_t)rndr.refs.size; i++) {-		bufrelease(lr[i].id);-		bufrelease(lr[i].link);-		bufrelease(lr[i].title);-	}+	free_link_refs(md->refs); -	arr_free(&rndr.refs);+	assert(md->work_bufs[BUFFER_SPAN].size == 0);+	assert(md->work_bufs[BUFFER_BLOCK].size == 0);+} -	assert(rndr.work_bufs[BUFFER_SPAN].size == 0);-	assert(rndr.work_bufs[BUFFER_BLOCK].size == 0);+void+sd_markdown_free(struct sd_markdown *md)+{+	size_t i; -	for (i = 0; i < (size_t)rndr.work_bufs[BUFFER_SPAN].asize; ++i)-		bufrelease(rndr.work_bufs[BUFFER_SPAN].item[i]);+	for (i = 0; i < (size_t)md->work_bufs[BUFFER_SPAN].asize; ++i)+		bufrelease(md->work_bufs[BUFFER_SPAN].item[i]); -	for (i = 0; i < (size_t)rndr.work_bufs[BUFFER_BLOCK].asize; ++i)-		bufrelease(rndr.work_bufs[BUFFER_BLOCK].item[i]);+	for (i = 0; i < (size_t)md->work_bufs[BUFFER_BLOCK].asize; ++i)+		bufrelease(md->work_bufs[BUFFER_BLOCK].item[i]); -	parr_free(&rndr.work_bufs[BUFFER_SPAN]);-	parr_free(&rndr.work_bufs[BUFFER_BLOCK]);+	stack_free(&md->work_bufs[BUFFER_SPAN]);+	stack_free(&md->work_bufs[BUFFER_BLOCK]);++	free(md); }  void
cbits/markdown.h view
@@ -95,6 +95,8 @@ 	void (*doc_footer)(struct buf *ob, void *opaque); }; +struct sd_markdown;+ /*********  * FLAGS *  *********/@@ -107,11 +109,19 @@  * EXPORTED FUNCTIONS *  **********************/ -/* sd_markdown * parses the input buffer and renders it into the output buffer */+extern struct sd_markdown *+sd_markdown_new(+	unsigned int extensions,+	size_t max_nesting,+	const struct sd_callbacks *callbacks,+	void *opaque); + extern void-sd_markdown(struct buf *ob, const struct buf *ib, unsigned int extensions, const struct sd_callbacks *rndr, void *opaque);+sd_markdown_render(struct buf *ob, const struct buf *ib, struct sd_markdown *md); -/* sd_version * returns the library version as major.minor.rev */+extern void+sd_markdown_free(struct sd_markdown *md);+ extern void sd_version(int *major, int *minor, int *revision); 
+ cbits/stack.c view
@@ -0,0 +1,78 @@+#include "stack.h"+#include <string.h>++int+stack_grow(struct stack *st, size_t new_size)+{+	void *new_st;++	if (st->asize >= new_size)+		return 0;++	new_st = realloc(st->item, new_size * sizeof(void *));+	if (new_st == NULL)+		return -1;++	st->item = new_st;+	st->asize = new_size;++	if (st->size > new_size)+		st->size = new_size;++	return 0;+}++void+stack_free(struct stack *st)+{+	if (!st)+		return;++	free(st->item);++	st->item = NULL;+	st->size = 0;+	st->asize = 0;+}++int+stack_init(struct stack *st, size_t initial_size)+{+	st->item = NULL;+	st->size = 0;+	st->asize = 0;++	if (!initial_size)+		initial_size = 8;++	return stack_grow(st, initial_size);+}++void *+stack_pop(struct stack *st)+{+	if (!st->size)+		return NULL;++	return st->item[st->size--];+}++int+stack_push(struct stack *st, void *item)+{+	if (stack_grow(st, st->size * 2) < 0)+		return -1;++	st->item[st->size++] = item;+	return 0;+}++void *+stack_top(struct stack *st)+{+	if (!st->size)+		return NULL;++	return st->item[st->size - 1];+}+
+ cbits/stack.h view
@@ -0,0 +1,21 @@+#ifndef __CR_STACK_H__+#define __CR_STACK_H__++#include <stdlib.h>++struct stack {+	void **item;+	size_t size;+	size_t asize;+};++void stack_free(struct stack *);+int stack_grow(struct stack *, size_t);+int stack_init(struct stack *, size_t);++int stack_push(struct stack *, void *);++void *stack_pop(struct stack *);+void *stack_top(struct stack *);++#endif
src/Text/Sundown.hs view
@@ -15,7 +15,7 @@ > main :: IO () > main = do >   input <- liftM (!! 0) getArgs >>= BS.readFile->   putStrLn $ UTF8.toString $ renderHtml input allExtensions noHtmlModes+>   putStrLn $ UTF8.toString $ renderHtml input allExtensions noHtmlModes Nothing  -} 
src/Text/Sundown/Markdown/Foreign.hsc view
@@ -3,7 +3,9 @@ module Text.Sundown.Markdown.Foreign        ( Callbacks        , Extensions (..)-       , c_sd_markdown+       , c_sd_markdown_new+       , c_sd_markdown_render+       , c_sd_markdown_free        ) where  import Foreign@@ -14,8 +16,6 @@  #include "markdown.h" -data Callbacks- -- | A set of switches to enable or disable markdown features. data Extensions = Extensions { extNoIntraEmphasis :: Bool                              , extTables          :: Bool@@ -35,14 +35,30 @@                      ]  +data Callbacks  instance Storable Callbacks where-    sizeOf _ = (#size struct sd_callbacks)-    alignment _ = alignment (undefined :: Ptr ())-    peek _ = error "Callbacks.peek is not implemented"-    poke _ _ = error "Callbacks.poke is not implemented"+  sizeOf _ = (#size struct sd_callbacks)+  alignment _ = alignment (undefined :: Ptr ())+  peek _ = error "Callbacks.peek is not implemented"+  poke _ _ = error "Callbacks.poke is not implemented" -c_sd_markdown :: Ptr Buffer -> Ptr Buffer -> Extensions -> Ptr Callbacks -> Ptr () -> IO ()-c_sd_markdown ob ib exts rndr opaque = c_sd_markdown' ob ib (toCUInt exts) rndr opaque-foreign import ccall "markdown.h sd_markdown"-  c_sd_markdown' :: Ptr Buffer -> Ptr Buffer -> CUInt -> Ptr Callbacks -> Ptr () -> IO ()+data Markdown++instance Storable Markdown where+  sizeOf _ = error "Markdown.sizeOf is not implemented"+  alignment _ = alignment (undefined :: Ptr ())+  peek _ = error "Markdown.peek is not implemented"+  poke _ = error "Markdown.poke is not implemented"++c_sd_markdown_new :: Extensions -> CSize -> Ptr Callbacks -> Ptr () -> IO (Ptr Markdown)+c_sd_markdown_new extensions max_nesting callbacks opaque =+  c_sd_markdown_new' (toCUInt extensions) max_nesting callbacks opaque+foreign import ccall "markdown.h sd_markdown_new"+  c_sd_markdown_new' :: CUInt -> CSize -> Ptr Callbacks -> Ptr () -> IO (Ptr Markdown)++foreign import ccall "markdown.h sd_markdown_render"+  c_sd_markdown_render :: Ptr Buffer -> Ptr Buffer -> Ptr Markdown -> IO ()++foreign import ccall "markdown.h sd_markdown_free"+  c_sd_markdown_free :: Ptr Markdown -> IO ()
src/Text/Sundown/Renderers/Html.hs view
@@ -13,18 +13,27 @@  import Data.ByteString (ByteString) import qualified Data.ByteString as BS+import Data.Maybe (fromMaybe)  import Text.Sundown.Markdown.Foreign import Text.Sundown.Buffer.Foreign import Text.Sundown.Renderers.Html.Foreign +defaultMaxNesting :: Int+defaultMaxNesting = 16+ -- | Parses a 'ByteString' containing the markdown, returns the Html -- code. {-# NOINLINE renderHtml #-}-renderHtml :: ByteString -> Extensions -> HtmlRenderMode -> ByteString-renderHtml input exts mode =+renderHtml :: ByteString+           -> Extensions+           -> HtmlRenderMode+           -> Maybe Int -- ^ The maximum nesting of the HTML. If Nothing, a default value (16)+                       -- will be used.+           -> ByteString+renderHtml input exts mode maxNestingM =   unsafePerformIO $-  alloca $ \renderer ->+  alloca $ \callbacks ->   alloca $ \options -> do     -- Allocate buffers     ob <- c_bufnew 64@@ -34,8 +43,11 @@     c_bufputs ib input          -- Do the markdown-    c_sdhtml_renderer renderer options mode-    c_sd_markdown ob ib exts renderer (castPtr options)+    c_sdhtml_renderer callbacks options mode+    let maxNesting = fromIntegral $ fromMaybe defaultMaxNesting maxNestingM+    markdown <- c_sd_markdown_new exts maxNesting callbacks (castPtr options)+    c_sd_markdown_render ob ib markdown+    c_sd_markdown_free markdown          -- Get the result     Buffer {bufData = output} <- peek ob
sundown.cabal view
@@ -1,6 +1,6 @@ Cabal-version:          >= 1.6 Name:                   sundown-Version:                0.1.2+Version:                0.2 Author:                 Francesco Mazzoli (f@mazzo.li) Maintainer:             Francesco Mazzoli (f@mazzo.li) Build-Type:             Simple@@ -35,13 +35,15 @@                       , Text.Sundown.Renderers.Html.Foreign                       , Text.Sundown.Flag                       , Text.Sundown.Markdown.Foreign-  -  C-Sources:            cbits/array.c, cbits/buffer.c, cbits/markdown.c,-                        cbits/html.c, cbits/html_smartypants.c,-                        cbits/autolink.c++  C-Sources:            cbits/autolink.c, cbits/buffer.c, cbits/html.c,+                        cbits/html_smartypants.c, cbits/markdown.c,+                        cbits/stack.c      Include-Dirs:         cbits   -  Includes:             array.h, autolink.h, buffer.h, markdown.h, html.h-  -  Install-includes:     array.h, autolink.h, buffer.h, markdown.h, html.h+  Includes:             autolink.h, buffer.h, html.h, html_blocks.h, markdown.h,+                        stack.h++  Install-includes:     autolink.h, buffer.h, html.h, html_blocks.h, markdown.h,+                        stack.h