]> git.vpit.fr Git - perl/modules/re-engine-Hooks.git/blob - Hooks.xs
eddf6ad62bbeac7ebc1e97bad99b2d24426faf3e
[perl/modules/re-engine-Hooks.git] / Hooks.xs
1 /* This file is part of the re::engine::Hooks Perl module.
2  * See http://search.cpan.org/dist/re-engine-Hooks/ */
3
4 #define PERL_NO_GET_CONTEXT
5 #include "EXTERN.h"
6 #include "perl.h"
7 #include "XSUB.h"
8
9 #define __PACKAGE__     "re::engine::Hooks"
10 #define __PACKAGE_LEN__ (sizeof(__PACKAGE__)-1)
11
12 /* --- Compatibility wrappers ---------------------------------------------- */
13
14 #define REH_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
15
16 #ifndef SvPV_const
17 # define SvPV_const(S, L) SvPV(S, L)
18 #endif
19
20 #ifdef USE_ITHREADS
21 # define REH_LOCK(M)   MUTEX_LOCK(M)
22 # define REH_UNLOCK(M) MUTEX_UNLOCK(M)
23 #else
24 # define REH_LOCK(M)   NOOP
25 # define REH_UNLOCK(M) NOOP
26 #endif
27
28 /* --- Lexical hints ------------------------------------------------------- */
29
30 STATIC U32 reh_hash = 0;
31
32 STATIC SV *reh_hint(pTHX) {
33 #define reh_hint() reh_hint(aTHX)
34  SV *hint;
35
36 #ifdef cop_hints_fetch_pvn
37  hint = cop_hints_fetch_pvn(PL_curcop, __PACKAGE__, __PACKAGE_LEN__,
38                                        reh_hash, 0);
39 #elif REH_HAS_PERL(5, 9, 5)
40  hint = Perl_refcounted_he_fetch(aTHX_ PL_curcop->cop_hints_hash,
41                                        NULL,
42                                        __PACKAGE__, __PACKAGE_LEN__,
43                                        0,
44                                        reh_hash);
45 #else
46  SV **val = hv_fetch(GvHV(PL_hintgv), __PACKAGE__, __PACKAGE_LEN__, 0);
47  if (!val)
48   return 0;
49  hint = *val;
50 #endif
51
52  return hint;
53 }
54
55 /* --- Public API ---------------------------------------------------------- */
56
57 #include "re_engine_hooks.h"
58
59 typedef struct reh_action {
60  struct reh_action *next;
61  reh_comp_hook      comp;
62  reh_exec_hook      exec;
63  const char        *key;
64  STRLEN             klen;
65 } reh_action;
66
67 STATIC reh_action *reh_action_list = 0;
68
69 #ifdef USE_ITHREADS
70
71 STATIC perl_mutex reh_action_list_mutex;
72
73 #endif /* USE_ITHREADS */
74
75 #undef reh_register
76 void reh_register(pTHX_ const char *key, reh_comp_hook comp, reh_exec_hook exec) {
77  reh_action *a;
78  char       *key_dup;
79  STRLEN      i, len;
80
81  len = strlen(key);
82  for (i = 0; i < len; ++i)
83   if (!isALNUM(key[i]) && key[i] != ':')
84    croak("Invalid key");
85  key_dup = PerlMemShared_malloc(len + 1);
86  memcpy(key_dup, key, len);
87  key_dup[len] = '\0';
88
89  a       = PerlMemShared_malloc(sizeof *a);
90  a->comp = comp;
91  a->exec = exec;
92  a->key  = key_dup;
93  a->klen = len;
94
95  REH_LOCK(&reh_action_list_mutex);
96  a->next         = reh_action_list;
97  reh_action_list = a;
98  REH_UNLOCK(&reh_action_list_mutex);
99
100  return;
101 }
102
103 /* --- Private API --------------------------------------------------------- */
104
105 void reh_call_comp_hook(pTHX_ regexp *rx, regnode *node) {
106  SV *hint = reh_hint();
107
108  if (hint && SvPOK(hint)) {
109   STRLEN      len;
110   const char *keys = SvPV_const(hint, len);
111   reh_action *a;
112
113   REH_LOCK(&reh_action_list_mutex);
114   a = reh_action_list;
115   REH_UNLOCK(&reh_action_list_mutex);
116
117   for (; a; a = a->next) {
118    if (a->comp) {
119     char *p = strstr(keys, a->key);
120
121     if (p && (p + a->klen <= keys + len) && p[a->klen] == ' ')
122      a->comp(aTHX_ rx, node);
123    }
124   }
125  }
126 }
127
128 void reh_call_exec_hook(pTHX_ regexp *rx, regnode *node, regmatch_info *reginfo, regmatch_state *st) {
129  SV *hint = reh_hint();
130
131  if (hint && SvPOK(hint)) {
132   STRLEN      len;
133   const char *keys = SvPV_const(hint, len);
134   reh_action *a;
135
136   REH_LOCK(&reh_action_list_mutex);
137   a = reh_action_list;
138   REH_UNLOCK(&reh_action_list_mutex);
139
140   for (; a; a = a->next) {
141    if (a->exec) {
142     char *p = strstr(keys, a->key);
143
144     if (p && (p + a->klen <= keys + len) && p[a->klen] == ' ')
145      a->exec(aTHX_ rx, node, reginfo, st);
146    }
147   }
148  }
149 }
150
151 /* --- Custom regexp engine ------------------------------------------------ */
152
153 #if PERL_VERSION <= 10
154 # define rxREGEXP(RX)  (RX)
155 #else
156 # define rxREGEXP(RX)  (SvANY(RX))
157 #endif
158
159 #if PERL_VERSION <= 10
160 EXTERN_C REGEXP *reh_regcomp(pTHX_ const SV * const, const U32);
161 #else
162 EXTERN_C REGEXP *reh_regcomp(pTHX_ SV * const, U32);
163 #endif
164 EXTERN_C I32     reh_regexec(pTHX_ REGEXP * const, char *, char *,
165                                    char *, I32, SV *, void *, U32);
166 EXTERN_C char *  reh_re_intuit_start(pTHX_ REGEXP * const, SV *, char *,
167                                            char *, U32, re_scream_pos_data *);
168 EXTERN_C SV *    reh_re_intuit_string(pTHX_ REGEXP * const);
169 EXTERN_C void    reh_regfree(pTHX_ REGEXP * const);
170 EXTERN_C void    reh_reg_numbered_buff_fetch(pTHX_ REGEXP * const,
171                                                    const I32, SV * const);
172 EXTERN_C void    reh_reg_numbered_buff_store(pTHX_ REGEXP * const,
173                                                    const I32, SV const * const);
174 EXTERN_C I32     reh_reg_numbered_buff_length(pTHX_ REGEXP * const,
175                                                    const SV * const, const I32);
176 EXTERN_C SV *    reh_reg_named_buff(pTHX_ REGEXP * const, SV * const,
177                                           SV * const, const U32);
178 EXTERN_C SV *    reh_reg_named_buff_iter(pTHX_ REGEXP * const,
179                                                const SV * const, const U32);
180 EXTERN_C SV *    reh_reg_qr_package(pTHX_ REGEXP * const);
181 #ifdef USE_ITHREADS
182 EXTERN_C void *  reh_regdupe(pTHX_ REGEXP * const, CLONE_PARAMS *);
183 #endif
184
185 EXTERN_C const struct regexp_engine reh_regexp_engine;
186
187 REGEXP *
188 #if PERL_VERSION <= 10
189 reh_re_compile(pTHX_ const SV * const pattern, const U32 flags)
190 #else
191 reh_re_compile(pTHX_ SV * const pattern, U32 flags)
192 #endif
193 {
194  struct regexp *rx;
195  REGEXP        *RX;
196
197  RX = reh_regcomp(aTHX_ pattern, flags);
198  rx = rxREGEXP(RX);
199
200  rx->engine = &reh_regexp_engine;
201
202  return RX;
203 }
204
205 const struct regexp_engine reh_regexp_engine = { 
206  reh_re_compile, 
207  reh_regexec, 
208  reh_re_intuit_start, 
209  reh_re_intuit_string, 
210  reh_regfree, 
211  reh_reg_numbered_buff_fetch,
212  reh_reg_numbered_buff_store,
213  reh_reg_numbered_buff_length,
214  reh_reg_named_buff,
215  reh_reg_named_buff_iter,
216  reh_reg_qr_package,
217 #if defined(USE_ITHREADS)
218  reh_regdupe 
219 #endif
220 };
221
222 /* --- XS ------------------------------------------------------------------ */
223
224 MODULE = re::engine::Hooks          PACKAGE = re::engine::Hooks
225
226 PROTOTYPES: ENABLE
227
228 BOOT:
229 {
230 #ifdef USE_ITHREADS
231  MUTEX_INIT(&reh_action_list_mutex);
232 #endif
233 }
234
235 void
236 _ENGINE()
237 PROTOTYPE:
238 PPCODE:
239  XPUSHs(sv_2mortal(newSViv(PTR2IV(&reh_regexp_engine))));
240
241 void
242 _registered(SV *key)
243 PROTOTYPE: $
244 PREINIT:
245  SV         *ret = NULL;
246  reh_action *a;
247  STRLEN      len;
248  const char *s;
249 PPCODE:
250  REH_LOCK(&reh_action_list_mutex);
251  a = reh_action_list;
252  REH_UNLOCK(&reh_action_list_mutex);
253  s = SvPV_const(key, len);
254  while (a && !ret) {
255   if (a->klen == len && memcmp(a->key, s, len) == 0)
256    ret = &PL_sv_yes;
257   a = a->next;
258  }
259  if (!ret)
260   ret = &PL_sv_no;
261  EXTEND(SP, 1);
262  PUSHs(ret);
263  XSRETURN(1);