File Coverage

signatures.xs
Criterion Covered Total %
statement 144 159 90.5
branch 67 100 67.0
condition n/a
subroutine n/a
pod n/a
total 211 259 81.4


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4              
5             #define NEED_PL_parser
6             #include "ppport.h"
7              
8             /* this should go into ppport */
9             #if PERL_BCDVERSION >= 0x5009005
10             #define PL_oldbufptr D_PPP_my_PL_parser_var(oldbufptr)
11             #endif
12              
13             #if PERL_REVISION == 5 && PERL_VERSION >= 10
14             #define HAS_HINTS_HASH
15             #endif
16              
17             #include "hook_op_check.h"
18             #include "hook_op_ppaddr.h"
19             #include "hook_parser.h"
20              
21             typedef struct userdata_St {
22             char *f_class;
23             SV *class;
24             hook_op_check_id eval_hook;
25             hook_op_check_id parser_id;
26             } userdata_t;
27              
28             STATIC void
29 18           call_to_perl (SV *class, UV offset, char *proto) {
30 18           dSP;
31              
32 18           ENTER;
33 18           SAVETMPS;
34              
35 18 50         PUSHMARK (SP);
36 18 50         EXTEND (SP, 3);
37 18           PUSHs (class);
38 18           mPUSHu (offset);
39 18           mPUSHp (proto, strlen (proto));
40 18           PUTBACK;
41              
42 18           call_method ("callback", G_VOID|G_DISCARD);
43              
44 18 50         FREETMPS;
45 18           LEAVE;
46 18           }
47              
48             STATIC SV *
49 17           qualify_func_name (const char *s) {
50 17           SV *ret = newSVpvs ("");
51              
52 17 100         if (strstr (s, ":") == NULL) {
53 16           sv_catpv (ret, SvPVX (PL_curstname));
54 16           sv_catpvs (ret, "::");
55             }
56              
57 17           sv_catpv (ret, s);
58              
59 17           return ret;
60             }
61              
62             STATIC int
63 270           enabled (SV *class) {
64             STRLEN len;
65             char *key;
66 270           HV *hints = GvHV (PL_hintgv);
67 270           SV **sv, *tmp = newSVsv (class);
68              
69 270           sv_catpv (tmp, "::enabled");
70 270 50         key = SvPV (tmp, len);
71              
72 270 50         if (!hints) {
73 0           return 0;
74             }
75              
76 270           sv = hv_fetch (hints, key, len, 0);
77 270           SvREFCNT_dec (tmp);
78              
79 270 100         if (!sv || !*sv) {
    50          
80 6           return 0;
81             }
82              
83 270 50         return SvOK (*sv);
    0          
    0          
84             }
85              
86             STATIC OP *
87 398           handle_proto (pTHX_ OP *op, void *user_data) {
88             OP *ret;
89             SV *op_sv, *name;
90             char *s, *tmp, *tmp2;
91             char tmpbuf[sizeof (PL_tokenbuf)], proto[sizeof (PL_tokenbuf)];
92 398           STRLEN retlen = 0;
93 398           userdata_t *ud = (userdata_t *)user_data;
94              
95 398 100         if (strNE (ud->f_class, SvPVX (PL_curstname))) {
96 131           return op;
97             }
98              
99 267 100         if (!enabled (ud->class)) {
100 6           return op;
101             }
102              
103 261 50         if (!PL_parser) {
104 0           return op;
105             }
106              
107 261 50         if (!PL_lex_stuff) {
    100          
108 230           return op;
109             }
110              
111 31           op_sv = cSVOPx (op)->op_sv;
112              
113 31 50         if (!SvPOK (op_sv)) {
114 0           return op;
115             }
116              
117             /* sub $name */
118 31 50         s = PL_oldbufptr;
119 31           s = hook_toke_skipspace (aTHX_ s);
120              
121 31 100         if (strnNE (s, "sub", 3)) {
122 12           return op;
123             }
124              
125 19 50         if (!isSPACE (s[3])) {
126 0           return op;
127             }
128              
129 19           s = hook_toke_skipspace (aTHX_ s + 4);
130              
131 19 100         if (strNE (SvPVX (PL_subname), "?")) {
132 17 50         (void)hook_toke_scan_word (aTHX_ (s - SvPVX (PL_linestr)), 1, tmpbuf, sizeof (tmpbuf), &retlen);
133              
134 17 50         if (retlen < 1) {
135 0           return op;
136             }
137              
138 17           name = qualify_func_name (tmpbuf);
139              
140 17 50         if (!sv_eq (PL_subname, name)) {
141 0           SvREFCNT_dec (name);
142 0           return op;
143             }
144              
145 17           SvREFCNT_dec (name);
146             }
147              
148             /* ($proto) */
149 19           s = hook_toke_skipspace (aTHX_ s + retlen);
150 19 50         if (s[0] != '(') {
151 0           return op;
152             }
153              
154             assert(PL_lex_stuff == op_sv);
155 19 50         PL_lex_stuff = NULL;
156              
157 19           tmp = hook_toke_scan_str (aTHX_ s);
158 19           tmp2 = hook_parser_get_lex_stuff (aTHX);
159 19           hook_parser_clear_lex_stuff (aTHX);
160              
161 19 50         if (s == tmp || !tmp2) {
    50          
162 0           return op;
163             }
164              
165 19           strncpy (proto, s + 1, tmp - s - 2);
166 19           proto[tmp - s - 2] = '\0';
167              
168 19           s++;
169              
170 174 100         while (tmp > s + 1) {
171 155 100         if (isSPACE (s[0])) {
172 11           s++;
173 11           continue;
174             }
175              
176 144 100         if (isSPACE (tmp2[0])) {
177 11           tmp2++;
178 11           continue;
179             }
180              
181 133 50         if (*tmp2 != *s) {
182 0           return op;
183             }
184              
185 133           tmp2++;
186 133           s++;
187             }
188              
189 19           ret = NULL;
190              
191 19           s = hook_toke_skipspace (aTHX_ s + 1);
192 19 100         if (s[0] == ':') {
193 5           s++;
194 11 100         while (s[0] != '{') {
195             char *attr_start;
196 7           s = hook_toke_skipspace (aTHX_ s);
197 7           attr_start = s;
198 7 50         (void)hook_toke_scan_word (aTHX_ (s - SvPVX (PL_linestr)), 0, tmpbuf, sizeof (tmpbuf), &retlen);
199              
200 7 50         if (retlen < 1) {
201 0           return op;
202             }
203              
204 7           s += retlen;
205 7 100         if (s[0] == '(') {
206 4           tmp = hook_toke_scan_str (aTHX_ s);
207 4           tmp2 = hook_parser_get_lex_stuff (aTHX);
208 4           hook_parser_clear_lex_stuff (aTHX);
209              
210 4 50         if (s == tmp) {
211 0           return op;
212             }
213              
214 4           s = tmp;
215              
216 4 100         if (strEQ (tmpbuf, "proto")) {
217 34 100         while (attr_start < tmp) {
218 31           *attr_start = ' ';
219 31           attr_start++;
220             }
221              
222 3           ret = newSVOP (OP_CONST, 0, newSVpvn (tmp2, strlen (tmp2)));
223 3           op_free (op);
224 4           op = ret;
225             }
226             }
227 3 100         else if (strEQ (tmpbuf, "proto")) {
228 1           croak ("proto attribute requires argument");
229             }
230              
231 6           s = hook_toke_skipspace (aTHX_ s);
232              
233 6 50         if (s[0] == ':') {
234 0           s++;
235             }
236             }
237             }
238              
239 18 50         if (s[0] != '{') {
240             /* croak as we already messed with op when :proto is given? */
241 0           return op;
242             }
243              
244 18           call_to_perl (ud->class, s - hook_parser_get_linestr (aTHX), proto);
245              
246 18 100         if (!ret) {
247 15           op_free (op);
248             }
249              
250 397           return ret;
251             }
252              
253             /* block_start conflicts with the perl API function exposed in 5.21.6. */
254             #undef block_start
255             #if PERL_BCDVERSION >= 0x5013006
256             STATIC void
257 1942           block_start (pTHX_ int full) {
258             PERL_UNUSED_VAR (full);
259              
260 1942 50         if (SvLEN (PL_linestr) < 16384)
    100          
261 185           lex_grow_linestr (16384);
262 1942           }
263             #endif
264              
265             STATIC OP *
266 3           before_eval (pTHX_ OP *op, void *user_data) {
267 3           dSP;
268             SV *sv, **stack;
269 3           SV *class = (SV *)user_data;
270              
271             #ifdef HAS_HINTS_HASH
272 3 50         if (PL_op->op_private & OPpEVAL_HAS_HH) {
273 3           stack = &SP[-1];
274             }
275             else {
276 0           stack = &SP[0];
277             }
278             #else
279             stack = &SP[0];
280             #endif
281              
282 3           sv = *stack;
283              
284 3 50         if (SvPOK (sv)) {
285             /* FIXME: this leaks the new scalar */
286 3           SV *new = newSVpvs ("use ");
287 3           sv_catsv (new, class);
288 3           sv_catpvs (new, ";");
289 3           sv_catsv (new, sv);
290 3           *stack = new;
291             }
292              
293 3           return op;
294             }
295              
296             STATIC OP *
297 3           handle_eval (pTHX_ OP *op, void *user_data) {
298 3           userdata_t *ud = (userdata_t *)user_data;
299              
300 3 50         if (enabled (ud->class)) {
301 3           hook_op_ppaddr_around (op, before_eval, NULL, newSVsv (ud->class));
302             }
303              
304 3           return op;
305             }
306              
307             MODULE = signatures PACKAGE = signatures
308              
309             PROTOTYPES: DISABLE
310              
311             UV
312             setup (class, f_class)
313             SV *class
314             char *f_class
315             PREINIT:
316             userdata_t *ud;
317             #if PERL_BCDVERSION >= 0x5013006
318             static BHK bhk;
319             #endif
320             INIT:
321 14           Newx (ud, 1, userdata_t);
322 14           ud->class = newSVsv (class);
323 14           ud->f_class = f_class;
324             CODE:
325 14           ud->parser_id = hook_parser_setup ();
326             #if PERL_BCDVERSION >= 0x5013006
327 14           BhkENTRY_set (&bhk, bhk_start, block_start);
328 14           Perl_blockhook_register (aTHX_ &bhk);
329             #endif
330 14           ud->eval_hook = hook_op_check (OP_ENTEREVAL, handle_eval, ud);
331 14           RETVAL = (UV)hook_op_check (OP_CONST, handle_proto, ud);
332             OUTPUT:
333             RETVAL
334              
335             void
336             teardown (class, id)
337             UV id
338             PREINIT:
339             userdata_t *ud;
340             CODE:
341 16           ud = (userdata_t *)hook_op_check_remove (OP_CONST, id);
342              
343 16 100         if (ud) {
344 14           hook_op_check_remove (OP_ENTEREVAL, ud->eval_hook);
345 14           hook_parser_teardown (ud->parser_id);
346 14           SvREFCNT_dec (ud->class);
347 14           Safefree (ud);
348             }
349             # # vim: ts=4 sts=4 sw=4 noet :