sq_pcre2.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. #if defined(SQ_USE_PCRE2) || defined(SQ_USE_PCRE2_STATIC)
  2. #include <ctype.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include "squirrel.h"
  6. #include "sqstdblobimpl.h"
  7. #define PCRE2_CODE_UNIT_WIDTH 8
  8. #include <pcre2.h>
  9. ////////
  10. #include "dynamic_library.h"
  11. /*SquiLu
  12. local library_functions = [
  13. ["pcre2_code *", "pcre2_compile", "PCRE2_SPTR, PCRE2_SIZE, uint32_t, int *, PCRE2_SIZE *, pcre2_compile_context *"],
  14. ["int", "pcre2_jit_compile", "pcre2_code *, uint32_t"],
  15. ["void", "pcre2_code_free", "pcre2_code *"],
  16. ["pcre2_match_data *", "pcre2_match_data_create_from_pattern", "const pcre2_code *, pcre2_general_context *"],
  17. ["PCRE2_SIZE *", "pcre2_get_ovector_pointer", "pcre2_match_data *match_data"],
  18. ["uint32_t", "pcre2_get_ovector_count", "pcre2_match_data *match_data"],
  19. ["void", "pcre2_match_data_free", "pcre2_match_data *"],
  20. ["int", "pcre2_match", "const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, uint32_t, pcre2_match_data *, pcre2_match_context *"],
  21. ["int", "pcre2_dfa_match", "const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length, PCRE2_SIZE startoffset, uint32_t options, pcre2_match_data *match_data, pcre2_match_context *mcontext, int *workspace, PCRE2_SIZE wscount"],
  22. ["int", "pcre2_get_error_message", "int, PCRE2_UCHAR *, PCRE2_SIZE"],
  23. ["pcre2_match_context *", "pcre2_match_context_create", "pcre2_general_context *gcontext"],
  24. ["pcre2_match_context *", "pcre2_match_context_copy", "pcre2_match_context *"],
  25. ["void", "pcre2_match_context_free", "pcre2_match_context *"],
  26. ["int", "pcre2_set_match_limit", "pcre2_match_context *mcontext, uint32_t value"],
  27. ["int", "pcre2_set_recursion_limit", "pcre2_match_context *mcontext, uint32_t value"],
  28. ["int", "pcre2_set_callout", "pcre2_match_context *, int (*)(pcre2_callout_block *, void *), void *"],
  29. ["int", "pcre2_substitute", "const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, uint32_t, pcre2_match_data *, pcre2_match_context *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_UCHAR *, PCRE2_SIZE *"],
  30. //next entry should be the last one
  31. //to make valid the test made on load_library function
  32. ["int", "pcre2_config", "uint32_t what, void *where"],
  33. ];
  34. function write_library_functions_declaration(){
  35. foreach(k,v in library_functions) {
  36. putsnl("typedef " + v[0] + " (*" + v[1] + "_t)(" + v[2] + ");");
  37. putsnl("static " + v[1] + "_t dl" + v[1] + " = 0;");
  38. }
  39. }
  40. function write_library_functions_load(chsz){
  41. foreach(k,v in library_functions){
  42. putsnl("dl" + v[1] + " = (" + v[1] + "_t) libdyn.dlsym(\"" + v[1] + chsz + "\");");
  43. putsnl("if(!dl" + v[1] + ") return false;");
  44. }
  45. }
  46. function write_library_functions_static_defines(){
  47. foreach(k,v in library_functions){
  48. putsnl("#define dl" + v[1] + " " + v[1]);
  49. }
  50. }
  51. SquiLu*/
  52. #ifdef SQ_USE_PCRE2_STATIC
  53. #define load_library(x) true
  54. //@write_library_functions_static_defines()
  55. // generated-code:begin
  56. #define dlpcre2_compile pcre2_compile
  57. #define dlpcre2_jit_compile pcre2_jit_compile
  58. #define dlpcre2_code_free pcre2_code_free
  59. #define dlpcre2_match_data_create_from_pattern pcre2_match_data_create_from_pattern
  60. #define dlpcre2_get_ovector_pointer pcre2_get_ovector_pointer
  61. #define dlpcre2_get_ovector_count pcre2_get_ovector_count
  62. #define dlpcre2_match_data_free pcre2_match_data_free
  63. #define dlpcre2_match pcre2_match
  64. #define dlpcre2_dfa_match pcre2_dfa_match
  65. #define dlpcre2_get_error_message pcre2_get_error_message
  66. #define dlpcre2_match_context_create pcre2_match_context_create
  67. #define dlpcre2_match_context_copy pcre2_match_context_copy
  68. #define dlpcre2_match_context_free pcre2_match_context_free
  69. #define dlpcre2_set_match_limit pcre2_set_match_limit
  70. #define dlpcre2_set_recursion_limit pcre2_set_recursion_limit
  71. #define dlpcre2_set_callout pcre2_set_callout
  72. #define dlpcre2_substitute pcre2_substitute
  73. #define dlpcre2_config pcre2_config
  74. // generated-code:end
  75. #else
  76. static DynamicLibrary libdyn;
  77. //@write_library_functions_declaration();
  78. // generated-code:begin
  79. typedef pcre2_code * (*pcre2_compile_t)(PCRE2_SPTR, PCRE2_SIZE, uint32_t, int *, PCRE2_SIZE *, pcre2_compile_context *);
  80. static pcre2_compile_t dlpcre2_compile = 0;
  81. typedef int (*pcre2_jit_compile_t)(pcre2_code *, uint32_t);
  82. static pcre2_jit_compile_t dlpcre2_jit_compile = 0;
  83. typedef void (*pcre2_code_free_t)(pcre2_code *);
  84. static pcre2_code_free_t dlpcre2_code_free = 0;
  85. typedef pcre2_match_data * (*pcre2_match_data_create_from_pattern_t)(const pcre2_code *, pcre2_general_context *);
  86. static pcre2_match_data_create_from_pattern_t dlpcre2_match_data_create_from_pattern = 0;
  87. typedef PCRE2_SIZE * (*pcre2_get_ovector_pointer_t)(pcre2_match_data *match_data);
  88. static pcre2_get_ovector_pointer_t dlpcre2_get_ovector_pointer = 0;
  89. typedef uint32_t (*pcre2_get_ovector_count_t)(pcre2_match_data *match_data);
  90. static pcre2_get_ovector_count_t dlpcre2_get_ovector_count = 0;
  91. typedef void (*pcre2_match_data_free_t)(pcre2_match_data *);
  92. static pcre2_match_data_free_t dlpcre2_match_data_free = 0;
  93. typedef int (*pcre2_match_t)(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, uint32_t, pcre2_match_data *, pcre2_match_context *);
  94. static pcre2_match_t dlpcre2_match = 0;
  95. typedef int (*pcre2_dfa_match_t)(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length, PCRE2_SIZE startoffset, uint32_t options, pcre2_match_data *match_data, pcre2_match_context *mcontext, int *workspace, PCRE2_SIZE wscount);
  96. static pcre2_dfa_match_t dlpcre2_dfa_match = 0;
  97. typedef int (*pcre2_get_error_message_t)(int, PCRE2_UCHAR *, PCRE2_SIZE);
  98. static pcre2_get_error_message_t dlpcre2_get_error_message = 0;
  99. typedef pcre2_match_context * (*pcre2_match_context_create_t)(pcre2_general_context *gcontext);
  100. static pcre2_match_context_create_t dlpcre2_match_context_create = 0;
  101. typedef pcre2_match_context * (*pcre2_match_context_copy_t)(pcre2_match_context *);
  102. static pcre2_match_context_copy_t dlpcre2_match_context_copy = 0;
  103. typedef void (*pcre2_match_context_free_t)(pcre2_match_context *);
  104. static pcre2_match_context_free_t dlpcre2_match_context_free = 0;
  105. typedef int (*pcre2_set_match_limit_t)(pcre2_match_context *mcontext, uint32_t value);
  106. static pcre2_set_match_limit_t dlpcre2_set_match_limit = 0;
  107. typedef int (*pcre2_set_recursion_limit_t)(pcre2_match_context *mcontext, uint32_t value);
  108. static pcre2_set_recursion_limit_t dlpcre2_set_recursion_limit = 0;
  109. typedef int (*pcre2_set_callout_t)(pcre2_match_context *, int (*)(pcre2_callout_block *, void *), void *);
  110. static pcre2_set_callout_t dlpcre2_set_callout = 0;
  111. typedef int (*pcre2_substitute_t)(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, uint32_t, pcre2_match_data *, pcre2_match_context *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_UCHAR *, PCRE2_SIZE *);
  112. static pcre2_substitute_t dlpcre2_substitute = 0;
  113. typedef int (*pcre2_config_t)(uint32_t what, void *where);
  114. static pcre2_config_t dlpcre2_config = 0;
  115. // generated-code:end
  116. static const char *dynamicLibName = DYNLIB_FOR_OS(libpcre2-8);
  117. static bool load_library(const char *libname)
  118. {
  119. if(dlpcre2_config) return true;
  120. if(libdyn.open(libname))
  121. {
  122. //@write_library_functions_load("_8");
  123. // generated-code:begin
  124. dlpcre2_compile = (pcre2_compile_t) libdyn.dlsym("pcre2_compile_8");
  125. if(!dlpcre2_compile) return false;
  126. dlpcre2_jit_compile = (pcre2_jit_compile_t) libdyn.dlsym("pcre2_jit_compile_8");
  127. if(!dlpcre2_jit_compile) return false;
  128. dlpcre2_code_free = (pcre2_code_free_t) libdyn.dlsym("pcre2_code_free_8");
  129. if(!dlpcre2_code_free) return false;
  130. dlpcre2_match_data_create_from_pattern = (pcre2_match_data_create_from_pattern_t) libdyn.dlsym("pcre2_match_data_create_from_pattern_8");
  131. if(!dlpcre2_match_data_create_from_pattern) return false;
  132. dlpcre2_get_ovector_pointer = (pcre2_get_ovector_pointer_t) libdyn.dlsym("pcre2_get_ovector_pointer_8");
  133. if(!dlpcre2_get_ovector_pointer) return false;
  134. dlpcre2_get_ovector_count = (pcre2_get_ovector_count_t) libdyn.dlsym("pcre2_get_ovector_count_8");
  135. if(!dlpcre2_get_ovector_count) return false;
  136. dlpcre2_match_data_free = (pcre2_match_data_free_t) libdyn.dlsym("pcre2_match_data_free_8");
  137. if(!dlpcre2_match_data_free) return false;
  138. dlpcre2_match = (pcre2_match_t) libdyn.dlsym("pcre2_match_8");
  139. if(!dlpcre2_match) return false;
  140. dlpcre2_dfa_match = (pcre2_dfa_match_t) libdyn.dlsym("pcre2_dfa_match_8");
  141. if(!dlpcre2_dfa_match) return false;
  142. dlpcre2_get_error_message = (pcre2_get_error_message_t) libdyn.dlsym("pcre2_get_error_message_8");
  143. if(!dlpcre2_get_error_message) return false;
  144. dlpcre2_match_context_create = (pcre2_match_context_create_t) libdyn.dlsym("pcre2_match_context_create_8");
  145. if(!dlpcre2_match_context_create) return false;
  146. dlpcre2_match_context_copy = (pcre2_match_context_copy_t) libdyn.dlsym("pcre2_match_context_copy_8");
  147. if(!dlpcre2_match_context_copy) return false;
  148. dlpcre2_match_context_free = (pcre2_match_context_free_t) libdyn.dlsym("pcre2_match_context_free_8");
  149. if(!dlpcre2_match_context_free) return false;
  150. dlpcre2_set_match_limit = (pcre2_set_match_limit_t) libdyn.dlsym("pcre2_set_match_limit_8");
  151. if(!dlpcre2_set_match_limit) return false;
  152. dlpcre2_set_recursion_limit = (pcre2_set_recursion_limit_t) libdyn.dlsym("pcre2_set_recursion_limit_8");
  153. if(!dlpcre2_set_recursion_limit) return false;
  154. dlpcre2_set_callout = (pcre2_set_callout_t) libdyn.dlsym("pcre2_set_callout_8");
  155. if(!dlpcre2_set_callout) return false;
  156. dlpcre2_substitute = (pcre2_substitute_t) libdyn.dlsym("pcre2_substitute_8");
  157. if(!dlpcre2_substitute) return false;
  158. dlpcre2_config = (pcre2_config_t) libdyn.dlsym("pcre2_config_8");
  159. if(!dlpcre2_config) return false;
  160. // generated-code:end
  161. return true;
  162. }
  163. return false;
  164. }
  165. #endif // SQ_USE_PCRE2_STATIC
  166. typedef int (*pre2_callout_func_t)(pcre2_callout_block *, void *);
  167. struct sqpcre2_st {
  168. pcre2_code *re;
  169. pcre2_match_context *match_context;
  170. pcre2_match_data *match_data;
  171. PCRE2_SIZE *ovector;
  172. /* associated squirrel vm */
  173. HSQUIRRELVM v;
  174. HSQOBJECT callout_cb;
  175. HSQOBJECT callout_cb_udata;
  176. };
  177. static const SQChar PCRE2_Tag[] = _SC("sqpcre2");
  178. #define GET_pcre2_INSTANCE() SQ_GET_INSTANCE(v, 1, sqpcre2_st, PCRE2_Tag) \
  179. if(self == NULL) return sq_throwerror(v, _SC("sqpcre2 object already closed"));
  180. static SQRESULT sq_pcre2_releasehook(SQUserPointer p, SQInteger /*size*/, void */*ep*/)
  181. {
  182. sqpcre2_st *self = ((sqpcre2_st *)p);
  183. if(self)
  184. {
  185. if(self->match_data) dlpcre2_match_data_free(self->match_data);
  186. dlpcre2_code_free(self->re);
  187. if(self->match_context)
  188. {
  189. sq_release(self->v, &self->callout_cb);
  190. sq_release(self->v, &self->callout_cb_udata);
  191. dlpcre2_match_context_free(self->match_context);
  192. }
  193. sq_free(self, sizeof(*self));
  194. }
  195. return 1;
  196. }
  197. static SQRESULT sq_pcre2_constructor(HSQUIRRELVM v)
  198. {
  199. if(!load_library(dynamicLibName)) return sq_throwerror(v, _SC("Failed to load libpcre !"));
  200. SQ_FUNC_VARS(v);
  201. SQ_GET_STRING(v, 2, pattern);
  202. SQ_OPT_INTEGER(v, 3, options, 0);
  203. PCRE2_SIZE erroroffset;
  204. int errornumber;
  205. pcre2_code *re = dlpcre2_compile(
  206. (PCRE2_SPTR)pattern, /* the pattern */
  207. PCRE2_ZERO_TERMINATED, /* indicates pattern is zero-terminated */
  208. options, /* 0 = default options */
  209. &errornumber, /* for error message */
  210. &erroroffset, /* for error offset */
  211. NULL); /* use default character tables */
  212. if(!re)
  213. {
  214. PCRE2_UCHAR buffer[256];
  215. dlpcre2_get_error_message(errornumber, buffer, sizeof(buffer));
  216. return sq_throwerror(v,_SC("PCRE compilation failed at offset %d: %s"), (int)erroroffset, buffer);
  217. }
  218. sqpcre2_st *sqpcre2 = (sqpcre2_st *)sq_malloc(sizeof(*sqpcre2));
  219. sqpcre2->re = re;
  220. sqpcre2->match_data = dlpcre2_match_data_create_from_pattern(re, NULL);
  221. sqpcre2->ovector = dlpcre2_get_ovector_pointer(sqpcre2->match_data);
  222. sqpcre2->v = v;
  223. sqpcre2->match_context = NULL;
  224. /*
  225. sq_resetobject(&sqpcre2->callout_cb);
  226. sq_resetobject(&sqpcre2->callout_cb_udata);
  227. */
  228. sq_setinstanceup(v,1,sqpcre2);
  229. sq_setreleasehook(v,1,sq_pcre2_releasehook);
  230. return 0;
  231. }
  232. static SQRESULT sq_pcre2_exec(HSQUIRRELVM v)
  233. {
  234. SQ_FUNC_VARS(v);
  235. GET_pcre2_INSTANCE();
  236. SQ_GET_STRING(v, 2, subject);
  237. SQ_OPT_INTEGER(v, 4, start_offset, 0);
  238. SQ_OPT_INTEGER(v, 5, options, 0);
  239. int rc = dlpcre2_match(
  240. self->re, /* the compiled pattern */
  241. (PCRE2_SPTR)subject, /* the subject string */
  242. subject_size, /* the length of the subject */
  243. start_offset, /* start at offset 0 in the subject */
  244. options, /* 0 = default options */
  245. self->match_data, /* block for storing the result */
  246. self->match_context); /* use default match context */
  247. const int array_pos = 3;
  248. SQInteger rtype = sq_gettype(v, array_pos);
  249. /* The output vector wasn't big enough */
  250. if (rc > 0)
  251. {
  252. if(rtype == OT_ARRAY)
  253. {
  254. int nelms = rc*2;
  255. sq_clear(v, array_pos);
  256. for (int i = 0; i < nelms; i++)
  257. {
  258. SQInteger pos = self->ovector[i];
  259. if(pos < 0) continue; //forget defined subroutines
  260. sq_pushinteger(v, pos);
  261. sq_arrayappend(v, array_pos);
  262. }
  263. }
  264. }
  265. sq_pushinteger(v, rc);
  266. return 1;
  267. }
  268. static SQRESULT sq_pcre2_match(HSQUIRRELVM v)
  269. {
  270. SQ_FUNC_VARS(v);
  271. GET_pcre2_INSTANCE();
  272. SQ_GET_STRING(v, 2, subject);
  273. SQ_OPT_INTEGER(v, 3, start_offset, 0);
  274. SQ_OPT_INTEGER(v, 4, options, 0);
  275. int rc = dlpcre2_match(
  276. self->re, /* the compiled pattern */
  277. (PCRE2_SPTR)subject, /* the subject string */
  278. subject_size, /* the length of the subject */
  279. start_offset, /* start at offset 0 in the subject */
  280. options, /* 0 = default options */
  281. self->match_data, /* block for storing the result */
  282. self->match_context); /* use default match context */
  283. if(rc > 0)
  284. {
  285. SQInteger start_pos = self->ovector[0], end_pos = self->ovector[1];
  286. if(start_pos == end_pos) sq_pushinteger(v, start_pos);
  287. else sq_pushstring(v, subject + start_pos, end_pos - start_pos);
  288. return 1;
  289. }
  290. sq_pushbool(v,SQFalse);
  291. return 1;
  292. }
  293. static SQRESULT sq_pcre2_gmatch(HSQUIRRELVM v)
  294. {
  295. SQ_FUNC_VARS(v);
  296. GET_pcre2_INSTANCE();
  297. SQ_GET_STRING(v, 2, subject);
  298. SQ_OPT_INTEGER(v, 4, start_offset, 0);
  299. SQ_OPT_INTEGER(v, 5, options, 0);
  300. SQInteger rc;
  301. bool isFirst = true;
  302. while( (rc = dlpcre2_match(
  303. self->re, /* the compiled pattern */
  304. (PCRE2_SPTR)subject, /* the subject string */
  305. subject_size, /* the length of the subject */
  306. start_offset, /* start at offset 0 in the subject */
  307. options, /* 0 = default options */
  308. self->match_data, /* block for storing the result */
  309. self->match_context)) > 0) /* use default match context */
  310. {
  311. if(isFirst)
  312. {
  313. sq_push(v, 3); //push the function
  314. isFirst = false;
  315. }
  316. sq_pushroottable(v); //this
  317. SQInteger start_pos, end_pos, ov_offset = 0, i = 0,
  318. param_count = 1; //root table already on the stack
  319. for(;i < rc; i++) {
  320. ov_offset = i*2;
  321. start_pos = self->ovector[ov_offset];
  322. if(start_pos < 0) continue;
  323. end_pos = self->ovector[ov_offset+1];
  324. if(start_pos == end_pos) sq_pushinteger(v, start_pos);
  325. else sq_pushstring(v, subject + start_pos, end_pos - start_pos);
  326. ++param_count;
  327. }
  328. i = sq_call(v, param_count, SQFalse, SQTrue);
  329. if(i < 0) return i;
  330. start_offset = self->ovector[(rc*2)-1]; //the last match + 1
  331. }
  332. sq_pushbool(v,SQFalse);
  333. return 1;
  334. }
  335. #include "sqstdblobimpl.h"
  336. static SQRESULT sq_pcre2_gsub(HSQUIRRELVM v)
  337. {
  338. SQ_FUNC_VARS(v);
  339. GET_pcre2_INSTANCE();
  340. SQ_GET_STRING(v, 2, str);
  341. SQ_OPT_INTEGER(v, 4, start_offset, 0);
  342. SQ_OPT_INTEGER(v, 5, options, 0);
  343. SQBlob blob(0,8192);
  344. const int replacement_idx = 3;
  345. SQObjectType ptype = sq_gettype(v, replacement_idx);
  346. const SQChar *replacement;
  347. SQInteger replacement_size;
  348. SQInteger rc;
  349. bool isFirst = true;
  350. while( (rc = dlpcre2_match(
  351. self->re, /* the compiled pattern */
  352. (PCRE2_SPTR)str, /* the subject string */
  353. str_size, /* the length of the subject */
  354. start_offset, /* start at offset 0 in the subject */
  355. options, /* 0 = default options */
  356. self->match_data, /* block for storing the result */
  357. self->match_context)) > 0) /* use default match context */
  358. {
  359. SQInteger i, ov_offset, start_pos, end_pos;
  360. blob.Write(str+start_offset, self->ovector[0]-start_offset);
  361. switch(ptype){
  362. case OT_CLOSURE:{
  363. if(isFirst)
  364. {
  365. sq_push(v, replacement_idx); //push the function
  366. isFirst = false;
  367. }
  368. sq_pushroottable(v); //this
  369. SQInteger param_count = 1; //root table
  370. for(i=0; i < rc; i++) {
  371. ov_offset = i*2;
  372. start_pos = self->ovector[ov_offset];
  373. if(start_pos < 0) continue; //defined subroutines not pushed as parameter
  374. end_pos = self->ovector[ov_offset+1];
  375. if(start_pos == end_pos) sq_pushinteger(v, start_pos);
  376. else sq_pushstring(v, str + start_pos, end_pos - start_pos);
  377. ++param_count;
  378. }
  379. i = sq_call(v, param_count, SQTrue, SQTrue);
  380. if(i < 0) return i;
  381. if(sq_gettype(v, -1) == OT_STRING){
  382. const SQChar *svalue;
  383. sq_getstring(v, -1, &svalue);
  384. blob.Write(svalue, sq_getsize(v, -1));
  385. }
  386. sq_poptop(v);
  387. }
  388. break;
  389. case OT_ARRAY:{
  390. SQInteger array_idx = 0;
  391. for(i=0; i < rc; i++) {
  392. ov_offset = i*2;
  393. SQInteger pos = self->ovector[ov_offset];
  394. if(pos < 0) continue; //forget defined subroutines
  395. sq_pushinteger(v, array_idx++);
  396. if(SQ_SUCCEEDED(sq_get(v, replacement_idx)) &&
  397. SQ_SUCCEEDED(sq_getstr_and_size(v, -1, &replacement, &replacement_size))){
  398. blob.Write(replacement, replacement_size);
  399. sq_pop(v, 1); //remove value
  400. }
  401. }
  402. }
  403. break;
  404. case OT_TABLE:{
  405. for(i=0; i < rc; i++) {
  406. ov_offset = i*2;
  407. start_pos = self->ovector[ov_offset];
  408. if(start_pos < 0) continue;
  409. end_pos = self->ovector[ov_offset+1];
  410. sq_pushstring(v, str + start_pos, end_pos - start_pos);
  411. if(SQ_SUCCEEDED(sq_get(v, replacement_idx)) &&
  412. SQ_SUCCEEDED(sq_getstr_and_size(v, -1, &replacement, &replacement_size))){
  413. blob.Write(replacement, replacement_size);
  414. sq_pop(v, 1); //remove value
  415. }
  416. }
  417. }
  418. break;
  419. case OT_STRING:{
  420. sq_getstr_and_size(v, replacement_idx, &replacement, &replacement_size);
  421. for(i=0; i < replacement_size; i++) {
  422. SQInteger c = replacement[i];
  423. switch(c)
  424. {
  425. case '$':
  426. ++i;
  427. if(i < replacement_size)
  428. {
  429. SQInteger idx = replacement[i] - '0', match_idx = 0;
  430. for(int j=0; j < rc; j++) {
  431. ov_offset = j*2;
  432. start_pos = self->ovector[ov_offset];
  433. if(start_pos < 0) continue;
  434. if(match_idx == idx)
  435. {
  436. end_pos = self->ovector[ov_offset+1];
  437. blob.Write(str+start_pos, end_pos-start_pos);
  438. break;
  439. }
  440. ++match_idx;
  441. }
  442. if(idx != match_idx)
  443. {
  444. return sq_throwerror(v, _SC("there is no match for replacement $%d"), idx);
  445. }
  446. continue;
  447. }
  448. else
  449. {
  450. return sq_throwerror(v, _SC("unexpected end of replacement string"));
  451. }
  452. break;
  453. case '\\':
  454. ++i;
  455. if(i < replacement_size)
  456. {
  457. blob.WriteChar(replacement[i]);
  458. continue;
  459. }
  460. //falthrough last character on replacement string
  461. default:
  462. blob.WriteChar(c);
  463. }
  464. }
  465. }
  466. break;
  467. default:
  468. return sq_throwerror(v, _SC("gsub only works with closure, array, table for replacement"));
  469. }
  470. start_offset = self->ovector[(rc*2)-1]; //the last match + 1
  471. }
  472. if(str_size) blob.Write(str+start_offset, str_size-start_offset);
  473. sq_pushstring(v, (const SQChar *)blob.GetBuf(), blob.Len());
  474. return 1;
  475. }
  476. static SQRESULT sq_pcre2_jit_compile(HSQUIRRELVM v)
  477. {
  478. SQ_FUNC_VARS(v);
  479. GET_pcre2_INSTANCE();
  480. SQ_OPT_INTEGER(v, 2, options, 0);
  481. sq_pushinteger(v, dlpcre2_jit_compile(self->re, options));
  482. return 1;
  483. }
  484. static SQRESULT sq_pcre2__typeof(HSQUIRRELVM v)
  485. {
  486. sq_pushstring(v,_SC(PCRE2_Tag),-1);
  487. return 1;
  488. }
  489. static SQRESULT sq_pcre2_version(HSQUIRRELVM v)
  490. {
  491. PCRE2_UCHAR8 buf[32];
  492. int rc = dlpcre2_config(PCRE2_CONFIG_VERSION, buf);
  493. sq_pushstring(v, (const SQChar*)buf, -1);
  494. return 1;
  495. }
  496. static SQRESULT sq_pcre2_loadlib(HSQUIRRELVM v)
  497. {
  498. SQ_FUNC_VARS_NO_TOP(v);
  499. SQ_GET_STRING(v, 2, libname);
  500. sq_pushbool(v, load_library(libname));
  501. return 1;
  502. }
  503. /*
  504. The external callout function returns an integer to PCRE2.
  505. If the value is zero, matching proceeds as normal.
  506. If the value is greater than zero, matching fails at the current point,
  507. but the testing of other matching possibilities goes ahead,
  508. just as if a lookahead assertion had failed.
  509. If the value is less than zero, the match is abandoned,
  510. and the matching function returns the negative value.
  511. */
  512. static int sq_pcre2_callout_callback(pcre2_callout_block *pcb, void *udata)
  513. {
  514. SQInteger result = -1; /* abort by default */
  515. sqpcre2_st *sqpcre2 = (sqpcre2_st*)udata;
  516. HSQUIRRELVM v = sqpcre2->v;
  517. int top = sq_gettop(v);
  518. sq_pushobject(v, sqpcre2->callout_cb);
  519. sq_pushroottable(v); //this
  520. sq_pushinteger(v, pcb->callout_number);
  521. if(pcb->callout_string_length) sq_pushstring(v,
  522. (const SQChar*)pcb->callout_string, pcb->callout_string_length);
  523. else sq_pushnull(v);
  524. sq_pushinteger(v, pcb->start_match);
  525. sq_pushinteger(v, pcb->current_position);
  526. sq_pushobject(v, sqpcre2->callout_cb_udata);
  527. /* call squilu function */
  528. if (sq_call(v, 6, SQTrue, SQFalse) == SQ_OK)
  529. sq_getinteger(v, -1, &result);
  530. sq_settop(v, top);
  531. return result;
  532. }
  533. static SQRESULT sq_pcre2_set_callout(HSQUIRRELVM v)
  534. {
  535. SQ_FUNC_VARS(v);
  536. GET_pcre2_INSTANCE();
  537. if(!self->match_context)
  538. {
  539. self->match_context = dlpcre2_match_context_create(NULL);
  540. sq_resetobject(&self->callout_cb);
  541. sq_resetobject(&self->callout_cb_udata);
  542. }
  543. else
  544. {
  545. /* clear progress handler */
  546. dlpcre2_set_callout(self->match_context, NULL, NULL);
  547. }
  548. sq_release(v, &self->callout_cb);
  549. sq_release(v, &self->callout_cb_udata);
  550. sq_resetobject(&self->callout_cb);
  551. sq_resetobject(&self->callout_cb_udata);
  552. SQObjectType otype = sq_gettype(v, 2);
  553. if (_top_ > 1 && (otype != OT_NULL))
  554. {
  555. if(sq_gettype(v, 2) != OT_CLOSURE)
  556. return sq_throwerror(v, _SC("invalid second parameter expected closure"));
  557. sq_getstackobj(v, 2, &self->callout_cb);
  558. sq_addref(v, &self->callout_cb);
  559. if(_top_ > 2)
  560. {
  561. sq_getstackobj(v, 3, &self->callout_cb_udata);
  562. sq_addref(v, &self->callout_cb_udata);
  563. }
  564. /* set progress callback */
  565. dlpcre2_set_callout(self->match_context, sq_pcre2_callout_callback, self);
  566. }
  567. return 0;
  568. }
  569. static SQRESULT sq_pcre2_set_callout_param(HSQUIRRELVM v)
  570. {
  571. SQ_FUNC_VARS(v);
  572. GET_pcre2_INSTANCE();
  573. if(!self->match_context) return sq_throwerror(v, _SC("callout not set till now"));
  574. sq_release(v, &self->callout_cb_udata);
  575. sq_resetobject(&self->callout_cb_udata);
  576. SQObjectType otype = sq_gettype(v, 2);
  577. if (_top_ > 1 && (otype != OT_NULL))
  578. {
  579. sq_getstackobj(v, 2, &self->callout_cb_udata);
  580. sq_addref(v, &self->callout_cb_udata);
  581. }
  582. return 0;
  583. }
  584. #if 0
  585. static SQRESULT sq_pcre2_substitute(HSQUIRRELVM v)
  586. {
  587. SQ_FUNC_VARS(v);
  588. GET_pcre2_INSTANCE();
  589. SQ_GET_STRING(v, 2, subject);
  590. SQ_GET_STRING(v, 3, replacement);
  591. PCRE2_UCHAR *out_str;
  592. PCRE2_SIZE out_str_size;
  593. int rc = dlpcre2_substitute(
  594. self->re, /* the compiled pattern */
  595. (PCRE2_SPTR)subject, /* the subject string */
  596. str_size, /* the length of the subject */
  597. start_offset, /* start at offset 0 in the subject */
  598. options, /* 0 = default options */
  599. self->match_data, /* block for storing the result */
  600. self->match_context, /* use default match context */
  601. (PCRE2_SPTR)replacement,
  602. replacement_size,
  603. out_str,
  604. &out_str_size);
  605. if(rc)
  606. {
  607. sq_pushstring(v, (const SQChar*)out_str, out_str_size);
  608. }
  609. else sq_pushnull(v);
  610. return 1;
  611. }
  612. #endif
  613. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),sq_pcre2_##name,nparams,tycheck}
  614. static SQRegFunction sq_pcre2_methods[] =
  615. {
  616. _DECL_FUNC(constructor,-2,_SC(".sn")),
  617. _DECL_FUNC(jit_compile,-1,_SC("xi")),
  618. _DECL_FUNC(exec,-3,_SC("xsann")),
  619. _DECL_FUNC(match,-2,_SC("xsnn")),
  620. _DECL_FUNC(gmatch,-3,_SC("xscnn")),
  621. _DECL_FUNC(gsub,-3,_SC("xs s|c|a|t nn")),
  622. _DECL_FUNC(_typeof,1,_SC("x")),
  623. _DECL_FUNC(version,1,_SC(".")),
  624. _DECL_FUNC(loadlib,2,_SC(".s")),
  625. _DECL_FUNC(set_callout,-2,_SC("xc.")),
  626. _DECL_FUNC(set_callout_param,-1,_SC("x.")),
  627. {0,0}
  628. };
  629. #undef _DECL_FUNC
  630. typedef struct {
  631. const SQChar *Str;
  632. SQInteger Val;
  633. } KeyIntType, * KeyIntPtrType;
  634. static KeyIntType sqpcre2_constants[] = {
  635. #define MK_CONST(c) {_SC(#c), PCRE2_##c}
  636. #define MK_CONST2(c) {_SC(c), (SQInteger)PCRE2_##c}
  637. //MK_CONST(SSL_SESSION_ID_SIZE),
  638. MK_CONST(ANCHORED),
  639. MK_CONST(NOTBOL),
  640. MK_CONST(NOTEOL),
  641. MK_CONST(NOTEMPTY),
  642. MK_CONST(NOTEMPTY_ATSTART),
  643. MK_CONST(NO_START_OPTIMIZE),
  644. MK_CONST(PARTIAL_HARD),
  645. MK_CONST(PARTIAL_SOFT),
  646. MK_CONST(NO_AUTO_POSSESS),
  647. MK_CONST(NO_START_OPTIMIZE),
  648. MK_CONST(NO_DOTSTAR_ANCHOR),
  649. MK_CONST(DOTALL),
  650. MK_CONST(CASELESS),
  651. MK_CONST(MULTILINE),
  652. MK_CONST(EXTENDED),
  653. MK_CONST(NEWLINE_CR),
  654. MK_CONST(NEWLINE_LF),
  655. MK_CONST(NEWLINE_CRLF),
  656. MK_CONST(NEWLINE_ANYCRLF),
  657. MK_CONST(NEWLINE_ANY),
  658. MK_CONST(INFO_NEWLINE),
  659. MK_CONST(INFO_ALLOPTIONS),
  660. MK_CONST(CONFIG_VERSION),
  661. MK_CONST(UTF),
  662. MK_CONST(NO_UTF_CHECK),
  663. MK_CONST(ERROR_UTF8_ERR1),
  664. MK_CONST(CONFIG_JIT),
  665. MK_CONST(JIT_COMPLETE),
  666. MK_CONST(JIT_PARTIAL_HARD),
  667. MK_CONST(JIT_PARTIAL_SOFT),
  668. MK_CONST(AUTO_CALLOUT),
  669. MK_CONST(SUBSTITUTE_GLOBAL),
  670. {0,0}
  671. };
  672. #ifdef __cplusplus
  673. extern "C" {
  674. #endif
  675. SQRESULT sqext_register_pcre2(HSQUIRRELVM v)
  676. {
  677. sq_pushstring(v,PCRE2_Tag,-1);
  678. sq_newclass(v,SQFalse);
  679. sq_settypetag(v,-1,(void*)PCRE2_Tag);
  680. sq_insert_reg_funcs(v, sq_pcre2_methods);
  681. //add constants
  682. KeyIntPtrType KeyIntPtr;
  683. for (KeyIntPtr = sqpcre2_constants; KeyIntPtr->Str; KeyIntPtr++) {
  684. sq_pushstring(v, KeyIntPtr->Str, -1); //first the key
  685. sq_pushinteger(v, KeyIntPtr->Val); //then the value
  686. sq_newslot(v, -3, SQFalse); //store then
  687. }
  688. sq_newslot(v,-3,SQTrue);
  689. return 0;
  690. }
  691. #ifdef __cplusplus
  692. }
  693. #endif
  694. #endif //SQ_USE_PCRE2