Skip to content

Commit

Permalink
Initial revision
Browse files Browse the repository at this point in the history
  • Loading branch information
eklausme committed Feb 24, 2024
0 parents commit 5f94bd5
Show file tree
Hide file tree
Showing 5 changed files with 269 additions and 0 deletions.
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.libs
Makefile
Makefile.fragments
Makefile.objects
autom4te.cache
build/
config.h
config.h.in
config.log
config.nice
config.status
configure
configure.ac
core
include
libtool
modules
run-tests.php
*.a
*.dep
*.o
*.la
*.lo

3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

See [MD4C PHP Extension](https://eklausmeier.goip.de/blog/2024/02-24-md4c-php-extension).

40 changes: 40 additions & 0 deletions config.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
dnl config.m4 for php-md4c extension

PHP_ARG_WITH(md4c, [whether to enable MD4C support],
[ --with-md4c[[=DIR]] Enable MD4C support.
DIR is the path to MD4C install prefix])

if test "$PHP_YAML" != "no"; then

AC_MSG_CHECKING([for md4c headers])
for i in "$PHP_MD4C" "$prefix" /usr /usr/local; do
if test -r "$i/include/md4c-html.h"; then
PHP_MD4C_DIR=$i
AC_MSG_RESULT([found in $i])
break
fi
done
if test -z "$PHP_MD4C_DIR"; then
AC_MSG_RESULT([not found])
AC_MSG_ERROR([Please install md4c])
fi

PHP_ADD_INCLUDE($PHP_MD4C_DIR/include)
dnl recommended flags for compilation with gcc
dnl CFLAGS="$CFLAGS -Wall -fno-strict-aliasing"

export OLD_CPPFLAGS="$CPPFLAGS"
export CPPFLAGS="$CPPFLAGS $INCLUDES -DHAVE_MD4C"
AC_CHECK_HEADERS([md4c.h md4c-html.h], [], AC_MSG_ERROR(['md4c.h' header not found]))
#AC_CHECK_HEADER([md4c-html.h], [], AC_MSG_ERROR(['md4c-html.h' header not found]))
PHP_SUBST(MD4C_SHARED_LIBADD)

PHP_ADD_LIBRARY_WITH_PATH(md4c, $PHP_MD4C_DIR/$PHP_LIBDIR, MD4C_SHARED_LIBADD)
PHP_ADD_LIBRARY_WITH_PATH(md4c-html, $PHP_MD4C_DIR/$PHP_LIBDIR, MD4C_SHARED_LIBADD)
export CPPFLAGS="$OLD_CPPFLAGS"

PHP_SUBST(MD4C_SHARED_LIBADD)
AC_DEFINE(HAVE_MD4C, 1, [ ])
PHP_NEW_EXTENSION(md4c, md4c.c, $ext_shared)
fi

2 changes: 2 additions & 0 deletions config.w32
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ARG_ENABLE('php-md4c', 'test support', 'no');

200 changes: 200 additions & 0 deletions md4c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/* MD4C extension for PHP: Markdown to HTML conversion
Info on PHP extension writing:
1. Sara Golemon: Extending and Embedding PHP, Sams Publishing, 2006, xx+410 p.
2. https://www.phpinternalsbook.com/php7/extensions_design/zend_extensions.html
3. https://github.com/dstogov/php-extension
Elmar Klausmeier, 19-Feb-2024: Started with FFI C module and converted memory allocation
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <php.h>
#include <ext/standard/info.h>
#include <md4c-html.h>


//ZEND_DECLARE_MODULE_GLOBALS(php_md4c) // no globals


/* {{{ void md4c_test()
*/
PHP_FUNCTION(md4c_test) {
ZEND_PARSE_PARAMETERS_NONE();

php_printf("The extension %s is loaded and working!\r\n", "md4c");
}
/* }}} */



struct membuffer {
char* data;
size_t asize; // allocated size = max usable size
size_t size; // current size
};



static void membuf_init(struct membuffer* buf, MD_SIZE new_asize) {
buf->size = 0;
buf->asize = new_asize;
if ((buf->data = safe_pemalloc(buf->asize,sizeof(char),0,1)) == NULL)
php_error_docref(NULL, E_ERROR, "php-md4c.c: membuf_init: safe_pemalloc() failed with asize=%ld.\n",(long)buf->asize);
}



static void membuf_grow(struct membuffer* buf, size_t new_asize) {
buf->data = safe_perealloc(buf->data, sizeof(char*), new_asize, 0, 1);
if (buf->data == NULL)
php_error_docref(NULL, E_ERROR, "php-md4c.c: membuf_grow: realloc() failed, new_asize=%ld.\n",(long)new_asize);
buf->asize = new_asize;
}



static void membuf_append(struct membuffer* buf, const char* data, MD_SIZE size) {
if (buf->asize < buf->size + size)
membuf_grow(buf, buf->size + buf->size / 2 + size);
memcpy(buf->data + buf->size, data, size);
buf->size += size;
}



static void process_output(const MD_CHAR* text, MD_SIZE size, void* userdata) {
membuf_append((struct membuffer*) userdata, text, size);
}



static struct membuffer mbuf = { NULL, 0, 0 };



/* {{{ string md4c_toHtml( string $markdown, [ int $flag ] )
*/
PHP_FUNCTION(md4c_toHtml) { // return HTML string
char *markdown;
size_t markdown_len;
int ret;
long flag = MD_DIALECT_GITHUB | MD_FLAG_NOINDENTEDCODEBLOCKS;

ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STRING(markdown, markdown_len)
Z_PARAM_OPTIONAL Z_PARAM_LONG(flag)
ZEND_PARSE_PARAMETERS_END();

if (mbuf.asize == 0) membuf_init(&mbuf,16777216); // =16MB

mbuf.size = 0; // prepare for next call
ret = md_html(markdown, markdown_len, process_output,
&mbuf, (MD_SIZE)flag, 0);
membuf_append(&mbuf,"\0",1); // make it a null-terminated C string, so PHP can deduce length
if (ret < 0) {
RETVAL_STRINGL("<br>- - - Error in Markdown - - -<br>\n",sizeof("<br>- - - Error in Markdown - - -<br>\n"));
} else {
RETVAL_STRING(estrndup(mbuf.data,mbuf.size));
}
}
/* }}}*/



//static PHP_GINIT_FUNCTION(md4c) {
//#if defined(COMPILE_DL_BCMATH) && defined(ZTS)
// ZEND_TSRMLS_CACHE_UPDATE();
//#endif
// do absolutely nothing
//}



/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(md4c) { // module initialization
//REGISTER_INI_ENTRIES();
//php_printf("In PHP_MINIT_FUNCTION(md4c): module initialization\n");

return SUCCESS;
}
/* }}} */



/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
PHP_MSHUTDOWN_FUNCTION(md4c) { // module shutdown
if (mbuf.data) pefree(mbuf.data,1);
return SUCCESS;
}
/* }}} */



/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(md4c) {
php_info_print_table_start();
php_info_print_table_row(2, "MD4C", "enabled");
php_info_print_table_row(2, "PHP-MD4C version", "1.0");
php_info_print_table_row(2, "MD4C version", "0.5.2");
php_info_print_table_end();
}
/* }}} */



/* {{{ arginfo
*/
ZEND_BEGIN_ARG_INFO(arginfo_md4c_test, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_md4c_toHtml, 1)
ZEND_ARG_INFO(0, str)
ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, flag, "MD_DIALECT_GITHUB | MD_FLAG_NOINDENTEDCODEBLOCKS")
ZEND_END_ARG_INFO()
/* }}} */



/* {{{ test_functions[]
*/
static const zend_function_entry php_md4c_functions[] = {
PHP_FE(md4c_test, arginfo_md4c_test)
PHP_FE(md4c_toHtml, arginfo_md4c_toHtml)
PHP_FE_END
};
/* }}} */



/* {{{ md4c_module_entry
*/
zend_module_entry md4c_module_entry = {
STANDARD_MODULE_HEADER,
"md4c", // Extension name
php_md4c_functions, // zend_function_entry
NULL, //PHP_MINIT(md4c), // PHP_MINIT - Module initialization
PHP_MSHUTDOWN(md4c), // PHP_MSHUTDOWN - Module shutdown
NULL, // PHP_RINIT - Request initialization
NULL, // PHP_RSHUTDOWN - Request shutdown
PHP_MINFO(md4c), // PHP_MINFO - Module info
"1.0", // Version
STANDARD_MODULE_PROPERTIES
};
/* }}} */



#ifdef COMPILE_DL_TEST
# ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
# endif
#endif
ZEND_GET_MODULE(md4c)

0 comments on commit 5f94bd5

Please sign in to comment.