tests
This commit is contained in:
parent
4eef1c9252
commit
d81f4ee30b
18
LICENSE
18
LICENSE
@ -1,9 +1,13 @@
|
|||||||
MIT License
|
Copyright (c) 2012-2018 Craig Barnes
|
||||||
|
|
||||||
Copyright (c) 2025 Datenlabor
|
Permission to use, copy, modify, and/or 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.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
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.
|
||||||
|
|||||||
30
Makefile
Normal file
30
Makefile
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# This makefile is used for testing purposes and makes no attempt
|
||||||
|
# to be portable. Use "luarocks make" to build and install.
|
||||||
|
|
||||||
|
CC ?= gcc
|
||||||
|
CFLAGS = -g -O2
|
||||||
|
XCFLAGS += -std=c99 -pedantic-errors -fPIC
|
||||||
|
CWARNS = -Wall -Wextra -Wshadow -Wundef -Wconversion -Wc90-c99-compat
|
||||||
|
LUA = lua
|
||||||
|
|
||||||
|
default:
|
||||||
|
@echo 'The Makefile is for development only.' >&2
|
||||||
|
@echo 'Use "luarocks make" to install.' >&2
|
||||||
|
|
||||||
|
all: discount3.so
|
||||||
|
|
||||||
|
discount3.so: discount3.o
|
||||||
|
$(CC) $(LDFLAGS) -fPIC -shared -o $@ $^ -lmarkdown
|
||||||
|
|
||||||
|
discount3.o: discount3.c
|
||||||
|
$(CC) $(XCFLAGS) $(CPPFLAGS) $(CFLAGS) $(CWARNS) -c -o $@ $<
|
||||||
|
|
||||||
|
check: all
|
||||||
|
$(LUA) test.lua
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f discount3.so discount3.o
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: default all check clean
|
||||||
|
.DELETE_ON_ERROR:
|
||||||
47
README.md
47
README.md
@ -1,3 +1,46 @@
|
|||||||
# discount3
|
# lua-discount3 Markdown
|
||||||
|
|
||||||
Discount v3 lua binding
|
|
||||||
|
[Lua] bindings for the [Discount] [Markdown] library version >3.0.
|
||||||
|
|
||||||
|
Fork of Craig Barnes archive: https://github.com/craigbarnes/lua-discount
|
||||||
|
|
||||||
|
Jessica (ex- David) L. Parsons wrote (https://www.pell.portland.or.us/~orc/Code/discount/downloads.html):
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
I ran out of slots in the original bitmap flags structure, so I dumped it and replaced it with a new flag blob accessed through a flag pointer. This broke the entire published interface and required the update to version 3 (this is why it took me over 3 years to implement it; I needed to test the code to within an inch of it’s life and between that and transitioning it just ate up time like you wouldn’t believe!)
|
||||||
|
Because I changed the mkd_flag_t structure and replaced it with a blob, the old flags are now a pointer and using the mkd_flag_isset(), mkd_set_flag(), and mkd_clr_flag() functions I introduced during the end of the run for version 2.x.x is now mandatory unless you’re fond of core dumps.
|
||||||
|
The way I’d originally implemented HTML5 (if that’s even a thing anymore?) support was to have a global structure that I allocated once and then you were stuck with it forever (and had to deallocate the structure whenever you stopped using the library otherwise it would leak memory), so I fixed that for v3.0.0 by moving the html5 details inside the MMIOT (activated by setting the flag MKD_HTML5) so it will automatically be deallocated when you are done with a document without affecting other MMIOTs.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is the implementation of bindings for discount v3 API.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
luarocks install discount3
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
|
||||||
|
If you get a compilation error during installation, it's because discount isn't installed as a shared library. See the solution here: https://gitlabor.ru/Datenlabor/discount
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
ISC [License][] (SPDX: [`ISC`]).
|
||||||
|
|
||||||
|
|
||||||
|
[Lua]: https://www.lua.org/
|
||||||
|
[Discount]: http://www.pell.portland.or.us/~orc/Code/discount/
|
||||||
|
[Markdown]: https://en.wikipedia.org/wiki/Markdown
|
||||||
|
[License]: LICENSE
|
||||||
|
[`ISC`]: https://spdx.org/licenses/ISC.html
|
||||||
|
|||||||
31
compat.h
Normal file
31
compat.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef LUA_VERSION_NUM
|
||||||
|
# error Lua >= 5.1 is required.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __has_attribute
|
||||||
|
# define HAS_ATTRIBUTE(x) __has_attribute(x)
|
||||||
|
#else
|
||||||
|
# define HAS_ATTRIBUTE(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __has_builtin
|
||||||
|
# define HAS_BUILTIN(x) __has_builtin(x)
|
||||||
|
#else
|
||||||
|
# define HAS_BUILTIN(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || HAS_ATTRIBUTE(visibility)
|
||||||
|
# define EXPORT __attribute__((__visibility__("default")))
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
# define EXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
# define EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__GNUC__) || HAS_BUILTIN(__builtin_expect)) && defined(__OPTIMIZE__)
|
||||||
|
# define likely(x) __builtin_expect(!!(x), 1)
|
||||||
|
# define unlikely(x) __builtin_expect(!!(x), 0)
|
||||||
|
#else
|
||||||
|
# define likely(x) (x)
|
||||||
|
# define unlikely(x) (x)
|
||||||
|
#endif
|
||||||
36
discount3-1.0-1.rockspec
Normal file
36
discount3-1.0-1.rockspec
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package = "discount3"
|
||||||
|
version = "1.0-1"
|
||||||
|
|
||||||
|
description = {
|
||||||
|
summary = "Lua bindings for the Discount Markdown library V3",
|
||||||
|
detailed = [[
|
||||||
|
Supports all tags.
|
||||||
|
]],
|
||||||
|
homepage = "https://gitlabor.ru/Datenlabor/discount3",
|
||||||
|
license = "ISC"
|
||||||
|
}
|
||||||
|
|
||||||
|
source = {
|
||||||
|
url = "https://gitlabor.ru/Datenlabor/discount3/tags/v1.0-0.tar.gz"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
external_dependencies = {
|
||||||
|
DISCOUNT = {
|
||||||
|
header = "mkdio.h",
|
||||||
|
library = "markdown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
modules = {
|
||||||
|
discount3 = {
|
||||||
|
sources = {"discount3.c"},
|
||||||
|
libraries = {"markdown"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
121
discount3.c
Normal file
121
discount3.c
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
Lua bindings for the Discount Markdown library.
|
||||||
|
Copyright (c) 2012-2018 Craig Barnes
|
||||||
|
Copyright (c) 2025 datenlabor.ru
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or 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 <limits.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
#include <mkdio.h>
|
||||||
|
#include "compat.h"
|
||||||
|
|
||||||
|
static const char *const options[] = {
|
||||||
|
"nolinks", "noimages", "nopants", "nohtml", "strict",
|
||||||
|
"tagtext", "noext", "cdata", "nosuperscript",
|
||||||
|
"notables", "nostrikethrough", "toc", "compat", "autolink",
|
||||||
|
"safelink", "noheader", "tabstop", "nodivquote",
|
||||||
|
"noalphalist", "extrafootnote", "nostyle",
|
||||||
|
"dlextra", "fencedcode", "idanchor",
|
||||||
|
"githubtags", "urlencodedanchor", "latex", "html5",
|
||||||
|
"normallist", "explicitlist", "dldiscount",
|
||||||
|
"altastitle", "extendedattr", NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned int option_codes[] = {
|
||||||
|
MKD_NOLINKS, MKD_NOIMAGE, MKD_NOPANTS, MKD_NOHTML, MKD_STRICT,
|
||||||
|
MKD_TAGTEXT, MKD_NO_EXT, MKD_CDATA, MKD_NOSUPERSCRIPT,
|
||||||
|
MKD_NOTABLES, MKD_NOSTRIKETHROUGH, MKD_TOC, MKD_1_COMPAT, MKD_AUTOLINK,
|
||||||
|
MKD_SAFELINK, MKD_NOHEADER, MKD_TABSTOP, MKD_NODIVQUOTE,
|
||||||
|
MKD_NOALPHALIST, MKD_EXTRA_FOOTNOTE, MKD_NOSTYLE,
|
||||||
|
MKD_DLEXTRA, MKD_FENCEDCODE, MKD_IDANCHOR,
|
||||||
|
MKD_GITHUBTAGS, MKD_URLENCODEDANCHOR, MKD_LATEX, MKD_HTML5,
|
||||||
|
MKD_NORMAL_LISTITEM, MKD_EXPLICITLIST, MKD_DLDISCOUNT,
|
||||||
|
MKD_ALT_AS_TITLE, MKD_EXTENDED_ATTR
|
||||||
|
};
|
||||||
|
|
||||||
|
static void add_field(lua_State *L, const char *k, const char *v) {
|
||||||
|
lua_pushstring(L, v);
|
||||||
|
lua_setfield(L, -2, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_lfield(lua_State *L, const char *k, const char *v, size_t n) {
|
||||||
|
lua_pushlstring(L, v, n);
|
||||||
|
lua_setfield(L, -2, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compile(lua_State *L) {
|
||||||
|
MMIOT *doc;
|
||||||
|
mkd_flag_t *flags = mkd_flags();
|
||||||
|
char *body = NULL, *toc = NULL, *css = NULL;
|
||||||
|
int body_size, toc_size, css_size, i, argc;
|
||||||
|
|
||||||
|
size_t input_size;
|
||||||
|
const char *input = luaL_checklstring(L, 1, &input_size);
|
||||||
|
luaL_argcheck(L, input_size < INT_MAX, 1, "string too long");
|
||||||
|
|
||||||
|
for (i = 2, argc = lua_gettop(L); i <= argc; i++) {
|
||||||
|
mkd_set_flag_num(flags, option_codes[luaL_checkoption(L, i, NULL, options)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
doc = mkd_string(input, (int) input_size, flags);
|
||||||
|
if (unlikely(doc == NULL)) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "mkd_string() returned NULL");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(mkd_compile(doc, flags) != 1)) {
|
||||||
|
mkd_cleanup(doc);
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "mkd_compile() failed");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
body_size = mkd_document(doc, &body);
|
||||||
|
if (unlikely(body == NULL || body_size < 0)) {
|
||||||
|
mkd_cleanup(doc);
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "mkd_document() failed");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_createtable(L, 0, 6);
|
||||||
|
add_lfield(L, "body", body, (size_t) body_size);
|
||||||
|
add_field(L, "title", mkd_doc_title(doc));
|
||||||
|
add_field(L, "author", mkd_doc_author(doc));
|
||||||
|
add_field(L, "date", mkd_doc_date(doc));
|
||||||
|
|
||||||
|
if ((css_size = mkd_css(doc, &css)) > 0 && css) {
|
||||||
|
add_lfield(L, "css", css, (size_t) css_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mkd_flag_isset(flags, MKD_TOC)) && (toc_size = mkd_toc(doc, &toc)) > 0 && toc) {
|
||||||
|
add_lfield(L, "index", toc, (size_t) toc_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
mkd_cleanup(doc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT int luaopen_discount3(lua_State *L) {
|
||||||
|
lua_createtable(L, 0, 2);
|
||||||
|
lua_pushcfunction(L, compile);
|
||||||
|
lua_setfield(L, -2, "compile");
|
||||||
|
lua_pushstring(L, markdown_version);
|
||||||
|
lua_setfield(L, -2, "_libmarkdown_version");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
BIN
discount3.o
Normal file
BIN
discount3.o
Normal file
Binary file not shown.
BIN
discount3.so
Executable file
BIN
discount3.so
Executable file
Binary file not shown.
40
test.lua
Normal file
40
test.lua
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package.path = ''
|
||||||
|
package.cpath = './?.so'
|
||||||
|
local discount = require "discount3"
|
||||||
|
local compile = assert(discount.compile)
|
||||||
|
|
||||||
|
do
|
||||||
|
local libver = assert(discount._libmarkdown_version)
|
||||||
|
assert(libver:match("^[0-9]"))
|
||||||
|
print(libver)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local doc = assert(compile "%Title ::\n%Author ::\n%Date ::\n*Text*\n")
|
||||||
|
assert(doc.title == "Title ::")
|
||||||
|
assert(doc.author == "Author ::")
|
||||||
|
assert(doc.date == "Date ::")
|
||||||
|
assert(doc.body == "<p><em>Text</em></p>")
|
||||||
|
print(doc.title)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local doc = assert(compile "<style>a {color: red}</style>Text")
|
||||||
|
--assert(doc.css == "<style>a {color: red}</style>\n")
|
||||||
|
print(doc.css)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local doc = assert(compile("", "toc"))
|
||||||
|
assert(doc.body == "")
|
||||||
|
assert(not doc.index)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local doc = assert(compile("# Heading", "toc"))
|
||||||
|
assert(doc.body)
|
||||||
|
assert(doc.index)
|
||||||
|
print(doc.index)
|
||||||
|
end
|
||||||
|
|
||||||
|
io.stderr:write("\27[1;32mAll tests passed\27[0m\n")
|
||||||
Loading…
x
Reference in New Issue
Block a user