Răsfoiți Sursa

Add two new extensions for hunspell and libtre

mingodad 8 ani în urmă
părinte
comite
3d528c78f3
3 a modificat fișierele cu 1110 adăugiri și 0 ștergeri
  1. 378 0
      SquiLu-ext/sq_hunspell.cpp
  2. 724 0
      SquiLu-ext/sq_tre.cpp
  3. 8 0
      SquiLu/sq/sq.c

+ 378 - 0
SquiLu-ext/sq_hunspell.cpp

@@ -0,0 +1,378 @@
+#if defined(SQ_USE_HUNSPELL) || defined(SQ_USE_HUNSPELL_STATIC)
+
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "squirrel.h"
+#include "sqstdblobimpl.h"
+
+#include "hunspell.h"
+
+////////
+#include "dynamic_library.h"
+
+/*SquiLu
+
+local library_functions = [
+    ["Hunhandle*", "Hunspell_create_key", "const char* affpath, const char* dpath, const char* key"],
+    ["void", "Hunspell_destroy", "Hunhandle* pHunspell"],
+    ["int", "Hunspell_add_dic", "Hunhandle* pHunspell, const char* dpath"],
+    ["int", "Hunspell_spell", "Hunhandle* pHunspell, const char*"],
+    ["char *", "Hunspell_get_dic_encoding", "Hunhandle* pHunspell"],
+    ["int", "Hunspell_suggest", "Hunhandle* pHunspell, char*** slst, const char* word"],
+    ["int", "Hunspell_analyze", "Hunhandle* pHunspell, char*** slst, const char* word"],
+    ["int", "Hunspell_stem", "Hunhandle* pHunspell, char*** slst, const char* word"],
+    ["int", "Hunspell_generate", "Hunhandle* pHunspell, char*** slst, const char* word, const char* word2"],
+    ["int", "Hunspell_generate2", "Hunhandle* pHunspell, char*** slst, const char* word, char** desc, int n"],
+    ["int", "Hunspell_add", "Hunhandle* pHunspell, const char* word"],
+    ["int", "Hunspell_add_with_affix", "Hunhandle* pHunspell, const char* word, const char* example"],
+    ["int", "Hunspell_remove", "Hunhandle* pHunspell, const char* word"],
+
+    //next entry should be the last one
+    //to make valid the test made on load_library function
+    ["void", "Hunspell_free_list", "Hunhandle* pHunspell, char*** slst, int n"],
+];
+
+function write_library_functions_declaration(){
+    foreach(k,v in library_functions) {
+        putsnl("typedef " + v[0] + " (*" + v[1] + "_t)(" + v[2] + ");");
+        putsnl("static " + v[1] + "_t dl" + v[1] + " = 0;");
+    }
+}
+
+function write_library_functions_load(){
+    foreach(k,v in library_functions){
+        putsnl("dl" + v[1] + " = (" + v[1] + "_t) libdyn.dlsym(\"" + v[1] + "\");");
+        putsnl("if(!dl" + v[1] + ") return false;");
+    }
+}
+
+function write_library_functions_static_defines(){
+    foreach(k,v in library_functions){
+        putsnl("#define dl" + v[1] + " " + v[1]);
+    }
+}
+SquiLu*/
+
+#ifdef SQ_USE_HUNSPELL_STATIC
+
+#define load_library(x) true
+
+//@write_library_functions_static_defines()
+// generated-code:begin
+#define dlHunspell_create_key Hunspell_create_key
+#define dlHunspell_destroy Hunspell_destroy
+#define dlHunspell_add_dic Hunspell_add_dic
+#define dlHunspell_spell Hunspell_spell
+#define dlHunspell_get_dic_encoding Hunspell_get_dic_encoding
+#define dlHunspell_suggest Hunspell_suggest
+#define dlHunspell_analyze Hunspell_analyze
+#define dlHunspell_stem Hunspell_stem
+#define dlHunspell_generate Hunspell_generate
+#define dlHunspell_generate2 Hunspell_generate2
+#define dlHunspell_add Hunspell_add
+#define dlHunspell_add_with_affix Hunspell_add_with_affix
+#define dlHunspell_remove Hunspell_remove
+#define dlHunspell_free_list Hunspell_free_list
+// generated-code:end
+
+#else
+
+static DynamicLibrary libdyn;
+
+//@write_library_functions_declaration();
+// generated-code:begin
+typedef Hunhandle* (*Hunspell_create_key_t)(const char* affpath, const char* dpath, const char* key);
+static Hunspell_create_key_t dlHunspell_create_key = 0;
+typedef void (*Hunspell_destroy_t)(Hunhandle* pHunspell);
+static Hunspell_destroy_t dlHunspell_destroy = 0;
+typedef int (*Hunspell_add_dic_t)(Hunhandle* pHunspell, const char* dpath);
+static Hunspell_add_dic_t dlHunspell_add_dic = 0;
+typedef int (*Hunspell_spell_t)(Hunhandle* pHunspell, const char*);
+static Hunspell_spell_t dlHunspell_spell = 0;
+typedef char * (*Hunspell_get_dic_encoding_t)(Hunhandle* pHunspell);
+static Hunspell_get_dic_encoding_t dlHunspell_get_dic_encoding = 0;
+typedef int (*Hunspell_suggest_t)(Hunhandle* pHunspell, char*** slst, const char* word);
+static Hunspell_suggest_t dlHunspell_suggest = 0;
+typedef int (*Hunspell_analyze_t)(Hunhandle* pHunspell, char*** slst, const char* word);
+static Hunspell_analyze_t dlHunspell_analyze = 0;
+typedef int (*Hunspell_stem_t)(Hunhandle* pHunspell, char*** slst, const char* word);
+static Hunspell_stem_t dlHunspell_stem = 0;
+typedef int (*Hunspell_generate_t)(Hunhandle* pHunspell, char*** slst, const char* word, const char* word2);
+static Hunspell_generate_t dlHunspell_generate = 0;
+typedef int (*Hunspell_generate2_t)(Hunhandle* pHunspell, char*** slst, const char* word, char** desc, int n);
+static Hunspell_generate2_t dlHunspell_generate2 = 0;
+typedef int (*Hunspell_add_t)(Hunhandle* pHunspell, const char* word);
+static Hunspell_add_t dlHunspell_add = 0;
+typedef int (*Hunspell_add_with_affix_t)(Hunhandle* pHunspell, const char* word, const char* example);
+static Hunspell_add_with_affix_t dlHunspell_add_with_affix = 0;
+typedef int (*Hunspell_remove_t)(Hunhandle* pHunspell, const char* word);
+static Hunspell_remove_t dlHunspell_remove = 0;
+typedef void (*Hunspell_free_list_t)(Hunhandle* pHunspell, char*** slst, int n);
+static Hunspell_free_list_t dlHunspell_free_list = 0;
+// generated-code:end
+
+static const char *dynamicLibName = DYNLIB_FOR_OS(libhunspell-1.6);
+
+static bool load_library(const char *libname)
+{
+    if(dlHunspell_free_list) return true;
+    if(libdyn.open(libname))
+    {
+        //@write_library_functions_load();
+// generated-code:begin
+dlHunspell_create_key = (Hunspell_create_key_t) libdyn.dlsym("Hunspell_create_key");
+if(!dlHunspell_create_key) return false;
+dlHunspell_destroy = (Hunspell_destroy_t) libdyn.dlsym("Hunspell_destroy");
+if(!dlHunspell_destroy) return false;
+dlHunspell_add_dic = (Hunspell_add_dic_t) libdyn.dlsym("Hunspell_add_dic");
+if(!dlHunspell_add_dic) return false;
+dlHunspell_spell = (Hunspell_spell_t) libdyn.dlsym("Hunspell_spell");
+if(!dlHunspell_spell) return false;
+dlHunspell_get_dic_encoding = (Hunspell_get_dic_encoding_t) libdyn.dlsym("Hunspell_get_dic_encoding");
+if(!dlHunspell_get_dic_encoding) return false;
+dlHunspell_suggest = (Hunspell_suggest_t) libdyn.dlsym("Hunspell_suggest");
+if(!dlHunspell_suggest) return false;
+dlHunspell_analyze = (Hunspell_analyze_t) libdyn.dlsym("Hunspell_analyze");
+if(!dlHunspell_analyze) return false;
+dlHunspell_stem = (Hunspell_stem_t) libdyn.dlsym("Hunspell_stem");
+if(!dlHunspell_stem) return false;
+dlHunspell_generate = (Hunspell_generate_t) libdyn.dlsym("Hunspell_generate");
+if(!dlHunspell_generate) return false;
+dlHunspell_generate2 = (Hunspell_generate2_t) libdyn.dlsym("Hunspell_generate2");
+if(!dlHunspell_generate2) return false;
+dlHunspell_add = (Hunspell_add_t) libdyn.dlsym("Hunspell_add");
+if(!dlHunspell_add) return false;
+dlHunspell_add_with_affix = (Hunspell_add_with_affix_t) libdyn.dlsym("Hunspell_add_with_affix");
+if(!dlHunspell_add_with_affix) return false;
+dlHunspell_remove = (Hunspell_remove_t) libdyn.dlsym("Hunspell_remove");
+if(!dlHunspell_remove) return false;
+dlHunspell_free_list = (Hunspell_free_list_t) libdyn.dlsym("Hunspell_free_list");
+if(!dlHunspell_free_list) return false;
+// generated-code:end
+
+        return true;
+    }
+    return false;
+}
+
+#endif // SQ_USE_HUNSPELL_STATIC
+
+SQ_OPT_STRING_STRLEN();
+
+static const SQChar HUNSPELL_Tag[]   = _SC("sqhunspell");
+#define GET_hunspell_INSTANCE() SQ_GET_INSTANCE(v, 1, Hunhandle, HUNSPELL_Tag) \
+	if(self == NULL) return sq_throwerror(v, _SC("sqhunspell object already closed"));
+
+static SQRESULT sq_hunspell_releasehook(SQUserPointer p, SQInteger /*size*/, void */*ep*/)
+{
+	Hunhandle *self = ((Hunhandle *)p);
+	if(self)
+    {
+        dlHunspell_destroy(self);
+    }
+	return 1;
+}
+
+static SQRESULT sq_hunspell_constructor(HSQUIRRELVM v)
+{
+    if(!load_library(dynamicLibName)) return sq_throwerror(v, _SC("Failed to load libhunspell !"));
+	SQ_FUNC_VARS(v);
+	SQ_GET_STRING(v, 2, aff);
+	SQ_GET_STRING(v, 3, dic);
+	SQ_OPT_STRING(v, 4, key, NULL);
+
+    Hunhandle *self = dlHunspell_create_key(aff, dic, key);
+
+	sq_setinstanceup(v,1,self);
+	sq_setreleasehook(v,1,sq_hunspell_releasehook);
+	return 0;
+}
+
+static SQRESULT sq_hunspell_add_dic(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_hunspell_INSTANCE();
+	SQ_GET_STRING(v, 2, dpath);
+	sq_pushinteger(v, dlHunspell_add_dic(self, dpath));
+	return 1;
+}
+
+static SQRESULT sq_hunspell_list(HSQUIRRELVM v, Hunhandle* pHunspell, int nelms, char **list)
+{
+    sq_newarray(v, nelms);
+    for (int i = 0; i < nelms; i++)
+    {
+        sq_pushstring(v, list[i], -1);
+        sq_arrayset(v, -2, i);
+    }
+    dlHunspell_free_list(pHunspell, &list, nelms);
+    return 1;
+}
+
+static SQRESULT sq_hunspell_analyze(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_hunspell_INSTANCE();
+	SQ_GET_STRING(v, 2, word);
+	char **list = NULL;
+
+	int nelms = dlHunspell_analyze(self, &list, word);
+	return sq_hunspell_list(v, self, nelms, list);
+}
+
+static SQRESULT sq_hunspell_generate(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_hunspell_INSTANCE();
+	SQ_GET_STRING(v, 2, word);
+    char **list;
+    const SQChar *str;
+    int nelms;
+
+	switch(sq_gettype(v, 3))
+	{
+    case OT_STRING:
+        {
+            SQ_GET_STRING(v, 3, example);
+            nelms = dlHunspell_generate(self, &list, word, example);
+            return sq_hunspell_list(v, self, nelms, list);
+        }
+        break;
+    case OT_ARRAY:
+        {
+            int howmany = sq_getsize(v, 3);
+            char **desc = (char**)sq_getscratchpad(v, howmany);
+            for (int i=0; i<howmany; i++) {
+                sq_arrayget(v, 3, i);
+                if(sq_gettype(v, -1) != OT_STRING) return sq_throwerror(v, _SC("only strings are allowed in the supplied array"));
+                sq_getstring(v, -1, &str);
+                desc[i] = (char*)str; // nasty
+                sq_poptop(v);
+            }
+            nelms = dlHunspell_generate2(self, &list, word, desc, howmany);
+            return sq_hunspell_list(v, self, nelms, list);
+        }
+        break;
+    default:
+        return sq_throwerror(v, _SC("string or array expected"));
+	}
+	return 0;
+}
+
+static SQRESULT sq_hunspell_spell(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_hunspell_INSTANCE();
+	SQ_GET_STRING(v, 2, word);
+	int ret = dlHunspell_spell(self, word);
+	sq_pushbool(v, ret);
+	return 1;
+}
+
+static SQRESULT sq_hunspell_stem(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_hunspell_INSTANCE();
+	SQ_GET_STRING(v, 2, word);
+	char **list;
+
+	int nelms = dlHunspell_stem(self, &list, word);
+	return sq_hunspell_list(v, self, nelms, list);
+}
+
+static SQRESULT sq_hunspell_suggest(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_hunspell_INSTANCE();
+	SQ_GET_STRING(v, 2, word);
+	char **list;
+
+	int nelms = dlHunspell_suggest(self, &list, word);
+	return sq_hunspell_list(v, self, nelms, list);
+}
+
+static SQRESULT sq_hunspell_add_word(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_hunspell_INSTANCE();
+	SQ_GET_STRING(v, 2, word);
+	sq_pushinteger(v, dlHunspell_add(self, word));
+	return 1;
+}
+
+static SQRESULT sq_hunspell_remove_word(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_hunspell_INSTANCE();
+	SQ_GET_STRING(v, 2, word);
+	sq_pushinteger(v, dlHunspell_remove(self, word));
+	return 1;
+}
+
+static SQRESULT sq_hunspell_get_dic_encoding(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_hunspell_INSTANCE();
+	char* encoding = dlHunspell_get_dic_encoding(self);
+	sq_pushstring(v, encoding, -1);
+	return 1;
+}
+
+static SQRESULT sq_hunspell__typeof(HSQUIRRELVM v)
+{
+	sq_pushstring(v,_SC(HUNSPELL_Tag),-1);
+	return 1;
+}
+
+
+static SQRESULT sq_hunspell_loadlib(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    SQ_GET_STRING(v, 2, libname);
+    sq_pushbool(v, load_library(libname));
+	return 1;
+}
+
+#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),sq_hunspell_##name,nparams,tycheck}
+static SQRegFunction sq_hunspell_methods[] =
+{
+	_DECL_FUNC(constructor,-3,_SC(".sss")),
+	_DECL_FUNC(add_dic,2,_SC("xs")),
+	_DECL_FUNC(analyze,2,_SC("xs")),
+	_DECL_FUNC(generate,-2,_SC("x s|a")),
+	_DECL_FUNC(spell,2,_SC("xs")),
+	_DECL_FUNC(stem,2,_SC("xs")),
+	_DECL_FUNC(suggest,2,_SC("xs")),
+	_DECL_FUNC(add_word,2,_SC("xs")),
+	_DECL_FUNC(remove_word,2,_SC("xs")),
+    _DECL_FUNC(get_dic_encoding,1,_SC("x")),
+	_DECL_FUNC(_typeof,1,_SC("x")),
+    _DECL_FUNC(loadlib,2,_SC(".s")),
+    {0,0}
+};
+#undef _DECL_FUNC
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SQRESULT sqext_register_hunspell(HSQUIRRELVM v)
+{
+    sq_pushstring(v,HUNSPELL_Tag,-1);
+    sq_newclass(v,SQFalse);
+    sq_settypetag(v,-1,(void*)HUNSPELL_Tag);
+    sq_insert_reg_funcs(v, sq_hunspell_methods);
+    sq_newslot(v,-3,SQTrue);
+
+    return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //SQ_USE_HUNSPELL
+
+

+ 724 - 0
SquiLu-ext/sq_tre.cpp

@@ -0,0 +1,724 @@
+#if defined(SQ_USE_TRE) || defined(SQ_USE_TRE_STATIC)
+
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "squirrel.h"
+#include "sqstdblobimpl.h"
+
+#include "tre/tre.h"
+
+////////
+#include "dynamic_library.h"
+
+/*SquiLu
+
+local library_functions = [
+    ["int", "tre_regncomp", "regex_t *preg, const char *regex, size_t len, int cflags"],
+    //["int", "tre_regwncomp", "regex_t *preg, const wchar_t *regex, size_t len, int cflags"],
+    ["int", "tre_regnexec", "const regex_t *preg, const char *string, size_t len, size_t nmatch, regmatch_t pmatch[], int eflags"],
+    ["int", "tre_reganexec", "const regex_t *preg, const char *string, size_t len, regamatch_t *match, regaparams_t params, int eflags"],
+    //["int", "tre_regwnexec", "const regex_t *preg, const wchar_t *string, size_t len, size_t nmatch, regmatch_t pmatch[], int eflags"],
+    //["int", "tre_regawnexec", "const regex_t *preg, const wchar_t *string, size_t len, regamatch_t *match, regaparams_t params, int eflags"],
+    ["void", "tre_regaparams_default", "regaparams_t *params"],
+    ["int", "tre_config", "int query, void *result"],
+    ["int", "tre_have_backrefs", "const regex_t *preg"],
+    ["int", "tre_have_approx", "const regex_t *preg"],
+    //["int", "tre_reguexec", "const regex_t *preg, const tre_str_source *string, size_t nmatch, regmatch_t pmatch[], int eflags"],
+    ["size_t", "tre_regerror", "int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size"],
+    ["void", "tre_regfree", "regex_t *preg"],
+
+    //next entry should be the last one
+    //to make valid the test made on load_library function
+    ["char *", "tre_version", "void"],
+];
+
+function write_library_functions_declaration(){
+    foreach(k,v in library_functions) {
+        putsnl("typedef " + v[0] + " (*" + v[1] + "_t)(" + v[2] + ");");
+        putsnl("static " + v[1] + "_t dl" + v[1] + " = 0;");
+    }
+}
+
+function write_library_functions_load(){
+    foreach(k,v in library_functions){
+        putsnl("dl" + v[1] + " = (" + v[1] + "_t) libdyn.dlsym(\"" + v[1] + "\");");
+        putsnl("if(!dl" + v[1] + ") return false;");
+    }
+}
+
+function write_library_functions_static_defines(){
+    foreach(k,v in library_functions){
+        putsnl("#define dl" + v[1] + " " + v[1]);
+    }
+}
+SquiLu*/
+
+#ifdef SQ_USE_TRE_STATIC
+
+#define load_library(x) true
+
+//@write_library_functions_static_defines()
+// generated-code:begin
+#define dltre_regncomp tre_regncomp
+#define dltre_regnexec tre_regnexec
+#define dltre_reganexec tre_reganexec
+#define dltre_regaparams_default tre_regaparams_default
+#define dltre_config tre_config
+#define dltre_have_backrefs tre_have_backrefs
+#define dltre_have_approx tre_have_approx
+#define dltre_regerror tre_regerror
+#define dltre_regfree tre_regfree
+#define dltre_version tre_version
+// generated-code:end
+
+#else
+
+static DynamicLibrary libdyn;
+
+//@write_library_functions_declaration();
+// generated-code:begin
+typedef int (*tre_regncomp_t)(regex_t *preg, const char *regex, size_t len, int cflags);
+static tre_regncomp_t dltre_regncomp = 0;
+typedef int (*tre_regnexec_t)(const regex_t *preg, const char *string, size_t len, size_t nmatch, regmatch_t pmatch[], int eflags);
+static tre_regnexec_t dltre_regnexec = 0;
+typedef int (*tre_reganexec_t)(const regex_t *preg, const char *string, size_t len, regamatch_t *match, regaparams_t params, int eflags);
+static tre_reganexec_t dltre_reganexec = 0;
+typedef void (*tre_regaparams_default_t)(regaparams_t *params);
+static tre_regaparams_default_t dltre_regaparams_default = 0;
+typedef int (*tre_config_t)(int query, void *result);
+static tre_config_t dltre_config = 0;
+typedef int (*tre_have_backrefs_t)(const regex_t *preg);
+static tre_have_backrefs_t dltre_have_backrefs = 0;
+typedef int (*tre_have_approx_t)(const regex_t *preg);
+static tre_have_approx_t dltre_have_approx = 0;
+typedef size_t (*tre_regerror_t)(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
+static tre_regerror_t dltre_regerror = 0;
+typedef void (*tre_regfree_t)(regex_t *preg);
+static tre_regfree_t dltre_regfree = 0;
+typedef char * (*tre_version_t)(void);
+static tre_version_t dltre_version = 0;
+// generated-code:end
+
+static const char *dynamicLibName = DYNLIB_FOR_OS(libtre);
+
+static bool load_library(const char *libname)
+{
+    if(dltre_version) return true;
+    if(libdyn.open(libname))
+    {
+        //@write_library_functions_load();
+// generated-code:begin
+dltre_regncomp = (tre_regncomp_t) libdyn.dlsym("tre_regncomp");
+if(!dltre_regncomp) return false;
+dltre_regnexec = (tre_regnexec_t) libdyn.dlsym("tre_regnexec");
+if(!dltre_regnexec) return false;
+dltre_reganexec = (tre_reganexec_t) libdyn.dlsym("tre_reganexec");
+if(!dltre_reganexec) return false;
+dltre_regaparams_default = (tre_regaparams_default_t) libdyn.dlsym("tre_regaparams_default");
+if(!dltre_regaparams_default) return false;
+dltre_config = (tre_config_t) libdyn.dlsym("tre_config");
+if(!dltre_config) return false;
+dltre_have_backrefs = (tre_have_backrefs_t) libdyn.dlsym("tre_have_backrefs");
+if(!dltre_have_backrefs) return false;
+dltre_have_approx = (tre_have_approx_t) libdyn.dlsym("tre_have_approx");
+if(!dltre_have_approx) return false;
+dltre_regerror = (tre_regerror_t) libdyn.dlsym("tre_regerror");
+if(!dltre_regerror) return false;
+dltre_regfree = (tre_regfree_t) libdyn.dlsym("tre_regfree");
+if(!dltre_regfree) return false;
+dltre_version = (tre_version_t) libdyn.dlsym("tre_version");
+if(!dltre_version) return false;
+// generated-code:end
+
+        return true;
+    }
+    return false;
+}
+
+#endif // SQ_USE_TRE_STATIC
+
+static SQInteger calc_new_size_by_max_len(SQInteger start_pos, SQInteger max_len, SQInteger curr_size)
+{
+    SQInteger new_size;
+    if(start_pos < 0)
+    {
+        new_size = curr_size + start_pos;
+        start_pos = new_size < 0 ? 0 : new_size;
+    }
+    if(max_len > 0) new_size = start_pos + max_len;
+    else new_size = curr_size + max_len;
+    if( (new_size < curr_size) && (new_size > start_pos) )
+    {
+        return new_size;
+    }
+    return curr_size;
+}
+
+struct sqtre_st {
+    regex_t re;
+    regamatch_t amatch;
+    regaparams_t aparams;
+
+    /* associated squirrel vm */
+    //HSQUIRRELVM v;
+};
+
+static const SQChar TRE_Tag[]   = _SC("sqtre");
+#define GET_tre_INSTANCE() SQ_GET_INSTANCE(v, 1, sqtre_st, TRE_Tag) \
+	if(self == NULL) return sq_throwerror(v, _SC("sqtre object already closed"));
+
+static SQRESULT generate_error (HSQUIRRELVM v, const sqtre_st *sqtre, int errcode) {
+    char errbuf[80];
+    tre_regerror (errcode, &sqtre->re, errbuf, sizeof (errbuf));
+    return sq_throwerror(v, _SC("%s"), errbuf);
+}
+
+static SQRESULT sq_tre_releasehook(SQUserPointer p, SQInteger /*size*/, void */*ep*/)
+{
+	sqtre_st *self = ((sqtre_st *)p);
+	if(self)
+    {
+        if(self->amatch.pmatch)
+        {
+            sq_free(self->amatch.pmatch, self->amatch.nmatch * sizeof(*self->amatch.pmatch));
+        }
+        dltre_regfree(&self->re);
+        sq_free(self, sizeof(*self));
+    }
+	return 1;
+}
+
+static SQRESULT sq_tre_constructor(HSQUIRRELVM v)
+{
+    if(!load_library(dynamicLibName)) return sq_throwerror(v, _SC("Failed to load libtre !"));
+	SQ_FUNC_VARS(v);
+	SQ_GET_STRING(v, 2, pattern);
+	SQ_OPT_INTEGER(v, 3, eflags, REG_EXTENDED);
+
+	sqtre_st *sqtre = (sqtre_st *)sq_malloc(sizeof(*sqtre));
+	memset(sqtre, 0, sizeof(sqtre_st));
+	//sqtre->v = v;
+
+	int rc = dltre_regncomp(
+            &sqtre->re,
+            pattern,              /* the pattern */
+            pattern_size,
+            eflags);              /* 0 = default eflags */
+
+	if(rc)
+    {
+        SQRESULT res = generate_error(v, sqtre, rc);
+        sq_free(sqtre, sizeof(sqtre_st));
+        return res;
+    }
+
+    if (eflags & REG_NOSUB) sqtre->re.re_nsub = 0;
+    else if(sqtre->re.re_nsub)
+    {
+        sqtre->amatch.nmatch = sqtre->re.re_nsub+1; //+1 fror the whole match at 0
+        sqtre->amatch.pmatch = (regmatch_t *) sq_malloc(sqtre->amatch.nmatch * sizeof (regmatch_t));
+    }
+
+    /*
+    sq_resetobject(&sqtre->callout_cb);
+    sq_resetobject(&sqtre->callout_cb_udata);
+    */
+
+	sq_setinstanceup(v,1,sqtre);
+	sq_setreleasehook(v,1,sq_tre_releasehook);
+	return 0;
+}
+
+static SQRESULT sq_tre_exec(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS(v);
+    GET_tre_INSTANCE();
+    SQ_GET_STRING(v, 2, subject);
+    SQ_OPT_INTEGER(v, 4, start_offset, 0);
+    SQ_OPT_INTEGER(v, 5, eflags, 0);
+    SQ_OPT_INTEGER(v, 6, max_len, 0);
+
+    if(max_len)
+    {
+        subject_size = calc_new_size_by_max_len(start_offset, max_len, subject_size);
+    }
+
+    int rc = dltre_reganexec(
+        &self->re,             /* the compiled pattern */
+        subject+start_offset, /* the subject string */
+        subject_size,         /* the length of the subject */
+        &self->amatch,
+        self->aparams,
+        eflags);             /* 0 = default eflags */
+
+    const int array_pos = 3;
+    SQInteger rtype = sq_gettype(v, array_pos);
+
+    if (rc == 0)
+    {
+        if(rtype == OT_ARRAY)
+        {
+            int nelms = self->amatch.nmatch;
+            regmatch_t *pmatch = self->amatch.pmatch;
+            sq_clear(v, array_pos);
+            for (int i = 0; i < nelms; i++)
+            {
+                SQInteger pos = pmatch[i].rm_so;
+                sq_pushinteger(v, pos);
+                sq_arrayappend(v, array_pos);
+                pos = pmatch[i].rm_eo;
+                sq_pushinteger(v, pos);
+                sq_arrayappend(v, array_pos);
+            }
+        }
+    }
+
+    sq_pushinteger(v, rc);
+    return 1;
+}
+
+static SQRESULT sq_tre_match(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS(v);
+    GET_tre_INSTANCE();
+    SQ_GET_STRING(v, 2, subject);
+    SQ_OPT_INTEGER(v, 3, start_offset, 0);
+    SQ_OPT_INTEGER(v, 4, eflags, 0);
+    SQ_OPT_INTEGER(v, 5, max_len, 0);
+
+    if(max_len)
+    {
+        subject_size = calc_new_size_by_max_len(start_offset, max_len, subject_size);
+    }
+
+    int rc = dltre_reganexec(
+        &self->re,             /* the compiled pattern */
+        subject+start_offset, /* the subject string */
+        subject_size,         /* the length of the subject */
+        &self->amatch,
+        self->aparams,
+        eflags);             /* 0 = default eflags */
+
+    if(rc == 0)
+    {
+        regmatch_t *pmatch = self->amatch.pmatch;
+        SQInteger start_pos = pmatch[0].rm_so, end_pos = pmatch[0].rm_eo;
+        if(start_pos == end_pos) sq_pushinteger(v, start_pos); //empty match return it's position
+        else sq_pushstring(v, subject + start_pos, end_pos - start_pos);
+        return 1;
+    }
+    if(rc == REG_ESPACE) //only no matching errore
+    {
+        return sq_throwerror(v, _SC("tre_match error %d"), (int)rc);
+    }
+    return 0;
+}
+
+static SQRESULT sq_tre_gmatch(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS(v);
+    GET_tre_INSTANCE();
+    SQ_GET_STRING(v, 2, subject);
+    SQ_OPT_INTEGER(v, 4, start_offset, 0);
+    SQ_OPT_INTEGER(v, 5, eflags, 0);
+    SQ_OPT_INTEGER(v, 6, max_len, 0);
+
+    SQInteger rc;
+    bool isFirst = true;
+
+    if(max_len)
+    {
+        subject_size = calc_new_size_by_max_len(start_offset, max_len, subject_size);
+    }
+
+    regmatch_t *pmatch = self->amatch.pmatch;
+    SQInteger nmatch = self->amatch.nmatch;
+
+    while( (rc = dltre_reganexec(
+        &self->re,             /* the compiled pattern */
+        subject+start_offset, /* the subject string */
+        subject_size,         /* the length of the subject */
+        &self->amatch,
+        self->aparams,
+        eflags)) == 0)           /* use default match context */
+    {
+        if(isFirst)
+        {
+            sq_push(v, 3); //push the function
+            isFirst = false;
+        }
+        sq_pushroottable(v); //this
+        SQInteger start_pos, end_pos, i = 0,
+            param_count = 1; //root table already on the stack
+        for(;i < nmatch; i++) {
+            start_pos = pmatch[i].rm_so;
+            end_pos = pmatch[i].rm_eo;
+            if(start_pos == end_pos) sq_pushinteger(v, start_pos); //empty match return it's position
+            else sq_pushstring(v, subject + start_offset + start_pos, end_pos - start_pos);
+            ++param_count;
+        }
+        i = sq_call(v, param_count, SQTrue, SQTrue);
+        if(i < 0) return i;
+        SQObjectType rtype = sq_gettype(v, -1);
+        SQBool keep_matching = SQFalse;
+        if(rtype == OT_BOOL) {
+            sq_getbool(v, -1, &keep_matching);
+        }
+        sq_poptop(v); //remove return parameter
+
+        if(!keep_matching) break;
+
+        start_offset += pmatch[nmatch-1].rm_eo; //the last match + 1
+    }
+    if(rc == REG_ESPACE) //only no matching errore
+    {
+        return sq_throwerror(v, _SC("tre_match error %d"), (int)rc);
+    }
+    return 0;
+}
+
+#include "sqstdblobimpl.h"
+static SQRESULT sq_tre_gsub(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS(v);
+    GET_tre_INSTANCE();
+    SQ_GET_STRING(v, 2, subject);
+    SQ_OPT_INTEGER(v, 4, start_offset, 0);
+    SQ_OPT_INTEGER(v, 5, eflags, 0);
+    SQ_OPT_INTEGER(v, 6, max_len, 0);
+
+    if(max_len)
+    {
+        subject_size = calc_new_size_by_max_len(start_offset, max_len, subject_size);
+    }
+
+	SQBlob blob(0,8192);
+	const int replacement_idx = 3;
+	SQObjectType ptype = sq_gettype(v, replacement_idx);
+    const SQChar *replacement;
+    SQInteger replacement_size;
+
+    SQInteger rc;
+    bool isFirst = true;
+    regmatch_t *pmatch = self->amatch.pmatch;
+    SQInteger nmatch = self->amatch.nmatch;
+    if(ptype == OT_STRING)
+    {
+        sq_getstr_and_size(v, replacement_idx, &replacement, &replacement_size);
+    }
+
+    while( (rc = dltre_reganexec(
+        &self->re,             /* the compiled pattern */
+        subject+start_offset, /* the subject string */
+        subject_size,         /* the length of the subject */
+        &self->amatch,
+        self->aparams,
+        eflags)) == 0)           /* use default match context */
+    {
+        SQInteger i, start_pos, end_pos;
+	    blob.Write(subject+start_offset, pmatch[0].rm_so);
+	    switch(ptype){
+	        case OT_CLOSURE:{
+                if(isFirst)
+                {
+                    sq_push(v, replacement_idx); //push the function
+                    isFirst = false;
+                }
+                sq_pushroottable(v); //this
+                SQInteger param_count = 1; //root table
+                for(i=0; i < nmatch; i++) {
+                    start_pos = pmatch[i].rm_so;
+                    end_pos = pmatch[i].rm_eo;
+                    if(start_pos == end_pos) sq_pushinteger(v, start_pos);
+                    else sq_pushstring(v, subject + start_offset + start_pos, end_pos - start_pos);
+                    ++param_count;
+                }
+                i = sq_call(v, param_count, SQTrue, SQTrue);
+                if(i < 0) return i;
+                if(sq_gettype(v, -1) == OT_STRING){
+                    const SQChar *svalue;
+                    sq_getstring(v, -1, &svalue);
+                    blob.Write(svalue, sq_getsize(v, -1));
+                }
+                sq_poptop(v);
+	        }
+	        break;
+	        case OT_ARRAY:{
+                SQInteger array_idx = 0;
+                for(i=0; i < nmatch; i++) {
+                    sq_pushinteger(v, array_idx++);
+                    if(SQ_SUCCEEDED(sq_get(v, replacement_idx)) &&
+                            SQ_SUCCEEDED(sq_getstr_and_size(v, -1, &replacement, &replacement_size))){
+                        blob.Write(replacement, replacement_size);
+                        sq_pop(v, 1); //remove value
+                    }
+                }
+	        }
+	        break;
+	        case OT_TABLE:{
+                for(i=0; i < nmatch; i++) {
+                    start_pos = pmatch[i].rm_so;
+                    end_pos = pmatch[i].rm_eo;
+                    sq_pushstring(v, subject + start_offset + start_pos, end_pos - start_pos);
+                    if(SQ_SUCCEEDED(sq_get(v, replacement_idx)) &&
+                            SQ_SUCCEEDED(sq_getstr_and_size(v, -1, &replacement, &replacement_size))){
+                        blob.Write(replacement, replacement_size);
+                        sq_pop(v, 1); //remove value
+                    }
+                }
+	        }
+	        break;
+	        case OT_STRING:{
+                for(i=0; i < replacement_size; i++) {
+                    SQInteger c = replacement[i];
+                    switch(c)
+                    {
+                    case '$':
+                        ++i;
+                        if(i < replacement_size)
+                        {
+                            SQInteger idx = replacement[i] - '0', match_idx = 0;
+                            for(int j=0; j < nmatch; j++) {
+                                if(match_idx == idx)
+                                {
+                                    start_pos = pmatch[j].rm_so;
+                                    end_pos = pmatch[j].rm_eo;
+                                    blob.Write(subject+start_offset+start_pos, end_pos-start_pos);
+                                    break;
+                                }
+                                ++match_idx;
+                            }
+                            if(idx != match_idx)
+                            {
+                                return sq_throwerror(v, _SC("there is no match for replacement $%d"), idx);
+                            }
+                            continue;
+                        }
+                        else
+                        {
+                            return sq_throwerror(v, _SC("unexpected end of replacement string"));
+                        }
+                        break;
+                    case '\\':
+                        ++i;
+                        if(i < replacement_size)
+                        {
+                            blob.WriteChar(replacement[i]);
+                            continue;
+                        }
+                        //falthrough last character on replacement string
+                    default:
+                        blob.WriteChar(c);
+                    }
+                }
+	        }
+	        break;
+	        default:
+                return sq_throwerror(v, _SC("gsub only works with closure, array, table for replacement"));
+	    }
+		start_offset += pmatch[nmatch-1].rm_eo; //the last match + 1
+	}
+
+    if(rc == REG_ESPACE) //only no matching errore
+    {
+        return sq_throwerror(v, _SC("tre_match error %d"), (int)rc);
+    }
+
+    if(subject_size) blob.Write(subject+start_offset, subject_size-start_offset);
+	sq_pushstring(v, (const SQChar *)blob.GetBuf(), blob.Len());
+	return 1;
+}
+
+static SQRESULT sq_tre_have_backrefs(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_tre_INSTANCE();
+    sq_pushinteger(v, dltre_have_backrefs(&self->re));
+	return 1;
+}
+
+static SQRESULT sq_tre_have_approx(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_tre_INSTANCE();
+    sq_pushinteger(v, dltre_have_approx(&self->re));
+	return 1;
+}
+
+static SQRESULT sq_tre__typeof(HSQUIRRELVM v)
+{
+	sq_pushstring(v,_SC(TRE_Tag),-1);
+	return 1;
+}
+
+static SQRESULT sq_tre_version(HSQUIRRELVM v)
+{
+    const char *buf = dltre_version();
+	sq_pushstring(v, (const SQChar*)buf, -1);
+	return 1;
+}
+
+static SQRESULT sq_tre_loadlib(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    SQ_GET_STRING(v, 2, libname);
+    sq_pushbool(v, load_library(libname));
+	return 1;
+}
+
+static SQRESULT sq_tre_regaparams_default(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_tre_INSTANCE();
+    dltre_regaparams_default(&self->aparams);
+	return 0;
+}
+
+static SQRESULT sq_tre_regamatch(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_tre_INSTANCE();
+    SQ_GET_STRING(v, 2, pkey);
+
+#define GET_PKEY(skey) \
+    else if(strcmp(pkey, #skey) == 0) \
+    { \
+        sq_pushinteger(v, self->amatch.skey); \
+    }
+
+    if(0){}
+    GET_PKEY(cost)
+    GET_PKEY(num_ins)
+    GET_PKEY(num_del)
+    GET_PKEY(num_subst)
+    GET_PKEY(nmatch)
+    else return sq_throwerror(v, _SC("unknown parameter '%s'"), pkey);
+	return 1;
+}
+
+static SQRESULT sq_tre_regaparams(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS(v);
+    GET_tre_INSTANCE();
+    SQ_GET_STRING(v, 2, pkey);
+    SQ_OPT_INTEGER(v, 3, pvalue, 0);
+    SQBool doSet = (_top_ == 3);
+#define GET_SET_PKEY(skey) \
+    else if(strcmp(pkey, #skey) == 0) \
+    { \
+        sq_pushinteger(v, self->aparams.skey); \
+        if(doSet) self->aparams.skey = pvalue; \
+    }
+
+    if(0){}
+    GET_SET_PKEY(max_cost)
+    GET_SET_PKEY(cost_ins)
+    GET_SET_PKEY(cost_del)
+    GET_SET_PKEY(cost_subst)
+    GET_SET_PKEY(max_ins)
+    GET_SET_PKEY(max_del)
+    GET_SET_PKEY(max_subst)
+    GET_SET_PKEY(max_err)
+    else return sq_throwerror(v, _SC("unknown parameter '%s'"), pkey);
+	return 1;
+}
+
+#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),sq_tre_##name,nparams,tycheck}
+static SQRegFunction sq_tre_methods[] =
+{
+	_DECL_FUNC(constructor,-2,_SC(".sn")),
+	_DECL_FUNC(regaparams_default,1,_SC("x")),
+	_DECL_FUNC(regaparams,-2,_SC("xsi")),
+	_DECL_FUNC(regamatch,2,_SC("xs")),
+	_DECL_FUNC(exec,-3,_SC("xsannn")),
+	_DECL_FUNC(match,-2,_SC("xsnnn")),
+	_DECL_FUNC(gmatch,-3,_SC("xscnnn")),
+	_DECL_FUNC(gsub,-3,_SC("xs s|c|a|t nnn")),
+	_DECL_FUNC(_typeof,1,_SC("x")),
+    _DECL_FUNC(version,1,_SC(".")),
+	_DECL_FUNC(have_approx,1,_SC("x")),
+	_DECL_FUNC(have_backrefs,1,_SC("x")),
+    _DECL_FUNC(loadlib,2,_SC(".s")),
+    {0,0}
+};
+#undef _DECL_FUNC
+
+typedef struct {
+  const SQChar *Str;
+  SQInteger Val;
+} KeyIntType, * KeyIntPtrType;
+
+static KeyIntType sqtre_constants[] = {
+    #define MK_CONST(c) {_SC(#c), TRE_##c}
+    #define MK_CONST2(c) {_SC(#c), (SQInteger)TRE_##c}
+    #define MK_CONST_REG(c) {_SC(#c), (SQInteger)REG_##c}
+    //MK_CONST(SSL_SESSION_ID_SIZE),
+
+	MK_CONST2(CONFIG_VERSION),
+	MK_CONST2(CONFIG_APPROX),
+	MK_CONST2(CONFIG_WCHAR),
+	MK_CONST2(CONFIG_MULTIBYTE),
+	MK_CONST2(CONFIG_SYSTEM_ABI),
+
+	MK_CONST_REG(OK),
+	MK_CONST_REG(NOMATCH),
+	MK_CONST_REG(BADPAT),
+	MK_CONST_REG(ECOLLATE),
+	MK_CONST_REG(ECTYPE),
+	MK_CONST_REG(EESCAPE),
+	MK_CONST_REG(ESUBREG),
+	MK_CONST_REG(EBRACK),
+	MK_CONST_REG(EPAREN),
+	MK_CONST_REG(EBRACE),
+	MK_CONST_REG(BADBR),
+	MK_CONST_REG(ERANGE),
+	MK_CONST_REG(ESPACE),
+	MK_CONST_REG(BADRPT),
+
+	MK_CONST_REG(EXTENDED),
+	MK_CONST_REG(ICASE),
+	MK_CONST_REG(NEWLINE),
+	MK_CONST_REG(NOSUB),
+	MK_CONST_REG(BASIC),
+	MK_CONST_REG(LITERAL),
+	MK_CONST_REG(RIGHT_ASSOC),
+	MK_CONST_REG(UNGREEDY),
+	MK_CONST_REG(NOTBOL),
+	MK_CONST_REG(NOTEOL),
+	MK_CONST_REG(APPROX_MATCHER),
+	MK_CONST_REG(BACKTRACKING_MATCHER),
+    {0,0}
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SQRESULT sqext_register_tre(HSQUIRRELVM v)
+{
+    sq_pushstring(v,TRE_Tag,-1);
+    sq_newclass(v,SQFalse);
+    sq_settypetag(v,-1,(void*)TRE_Tag);
+    sq_insert_reg_funcs(v, sq_tre_methods);
+
+	//add constants
+	KeyIntPtrType KeyIntPtr;
+	for (KeyIntPtr = sqtre_constants; KeyIntPtr->Str; KeyIntPtr++) {
+		sq_pushstring(v, KeyIntPtr->Str, -1);    //first the key
+		sq_pushinteger(v, KeyIntPtr->Val);       //then the value
+		sq_newslot(v, -3, SQFalse);              //store then
+	}
+
+    sq_newslot(v,-3,SQTrue);
+
+    return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //SQ_USE_TRE
+

+ 8 - 0
SquiLu/sq/sq.c

@@ -592,6 +592,8 @@ SQRESULT sqext_register_sq_blosc(HSQUIRRELVM v);
 SQRESULT sqext_register_pcre(HSQUIRRELVM v);
 SQRESULT sqext_register_pcre2(HSQUIRRELVM v);
 SQRESULT sqext_register_freetype(HSQUIRRELVM v);
+SQRESULT sqext_register_tre(HSQUIRRELVM v);
+SQRESULT sqext_register_hunspell(HSQUIRRELVM v);
 
 static sq_modules_preload_st modules_preload[] = {
     {"blob", sqstd_register_bloblib},
@@ -621,6 +623,12 @@ static sq_modules_preload_st modules_preload[] = {
 #if defined(SQ_USE_PCRE2) || defined(SQ_USE_PCRE2_STATIC)
     {"pcre2", sqext_register_pcre2},
 #endif // SQ_USE_PCRE2
+#if defined(SQ_USE_TRE) || defined(SQ_USE_TRE_STATIC)
+    {"sqtre", sqext_register_tre},
+#endif // SQ_USE_PCRE2
+#if defined(SQ_USE_HUNSPELL) || defined(SQ_USE_HUNSPELL_STATIC)
+    {"sqhunspell", sqext_register_hunspell},
+#endif // SQ_USE_PCRE2
 #ifdef SQ_USE_FREETYPE
     {"freetype", sqext_register_freetype},
 #endif // SQ_USE_FREETYPE