File Coverage

Cover.xs
Criterion Covered Total %
statement 81 109 74.3
branch 57 156 36.5
condition n/a
subroutine n/a
pod n/a
total 138 265 52.0


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include
4             #include
5              
6             static GV *sub_to_gv(pTHX_ SV *sv);
7             Perl_ppaddr_t orig_subhandler;
8             Perl_ppaddr_t orig_openhandler;
9             //Perl_ppaddr_t orig_sysopenhandler;
10              
11             // If we do not use threads we will make this global
12             // The performance impact of fetching it each time is significant, so avoid it
13             // if we can.
14             #ifdef USE_ITHREADS
15             #define fetch_report HV *report = get_hv("Test2::Plugin::Cover::REPORT", GV_ADDMULTI);
16             #else
17             HV *report;
18             #define fetch_report NOOP
19             #endif
20              
21             #define fetch_from SV *from = get_sv("Test2::Plugin::Cover::FROM", 0);
22             #define fetch_root SV *root = get_sv("Test2::Plugin::Cover::ROOT", 0);
23             #define fetch_enabled SV *enabled = get_sv("Test2::Plugin::Cover::ENABLED", 0);
24              
25 251           void add_entry(char *fname, STRLEN fnamelen, char *sname, STRLEN snamelen) {
26             fetch_report;
27 251           HV *file = NULL;
28 251           SV **existing_file = hv_fetch(report, fname, fnamelen, 0);
29 251 100         if (existing_file) {
30 88           file = (HV *)SvRV(*existing_file);
31             }
32             else {
33 163           file = newHV();
34 163           hv_store(report, fname, fnamelen, newRV_inc((SV *)file), 0);
35             }
36              
37 251           HV *sub = NULL;
38 251           SV **existing_sub = hv_fetch(file, sname, snamelen, 0);
39 251 100         if (existing_sub) {
40 69           sub = (HV *)SvRV(*existing_sub);
41             }
42             else {
43 182           sub = newHV();
44 182           hv_store(file, sname, snamelen, newRV_inc((SV *)sub), 0);
45             }
46              
47 251           fetch_from;
48 251 50         if (!(from && SvOK(from))) {
    50          
    0          
    0          
49 0           from = newSVpv("*", 1);
50             }
51             else {
52 251           from = sv_mortalcopy(from);
53 251           SvREFCNT_inc(from);
54             }
55              
56 251 100         if (!hv_exists_ent(sub, from, 0)) {
57 194           hv_store_ent(sub, from, from, 0);
58             }
59              
60 251           return;
61             }
62              
63 16951           static OP* my_subhandler(pTHX) {
64 16951           dSP;
65 16951           OP* out = orig_subhandler(aTHX);
66              
67 16951           fetch_enabled;
68 16951 50         if (!SvTRUE(enabled)) {
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    0          
    100          
    0          
69 38           return out;
70             }
71              
72 16913 100         if (out != NULL && (out->op_type == OP_NEXTSTATE || out->op_type == OP_DBSTATE)) {
    100          
    50          
73 14003 50         char *fname = CopFILE(cCOPx(out));
74 14003           STRLEN namelen = strlen(fname);
75              
76             // Check for absolute paths and reject them. This is a very
77             // unix-oriented optimization.
78 14003 100         if (!strncmp(fname, "/", 1)) {
79 13844           fetch_root;
80              
81 13844 50         if (root != NULL && SvPOK(root)) {
    50          
82             STRLEN len;
83 13844           char *rt = NULL;
84 13844 50         rt = SvPV(root, len);
85              
86 23629 100         if (namelen < len) return out;
87              
88 9864 100         if (strncmp(fname, rt, len)) {
89 9864           return out;
90             }
91             }
92             }
93              
94 238           char *subname = NULL;
95 238           STRLEN sublen = 0;
96              
97 238           GV *my_gv = sub_to_gv(aTHX_ *SP);
98 238 50         if (my_gv != NULL) {
99 238           subname = GvNAME(my_gv);
100 238           sublen = strlen(subname);
101             }
102             else {
103 0           subname = "*";
104 0           sublen = 1;
105             }
106              
107 238           add_entry(fname, namelen, subname, sublen);
108             }
109              
110 3148           return out;
111             }
112              
113             // Copied and modified from Devel::NYTProf
114 238           static GV *sub_to_gv(pTHX_ SV *sv) {
115 238           CV *cv = NULL;
116              
117             /* copied from top of perl's pp_entersub */
118             /* modified to return either CV or else a GV */
119             /* or a NULL in cases that pp_entersub would croak */
120 238           switch (SvTYPE(sv)) {
121             default:
122 11 50         if (!SvROK(sv)) {
123 0           char *sym = NULL;
124              
125 0 0         if (sv == &PL_sv_yes) { /* unfound import, ignore */
126 0           return NULL;
127             }
128 0 0         if (SvGMAGICAL(sv)) {
129 0           mg_get(sv);
130 0 0         if (SvROK(sv))
131 0           goto got_rv;
132 0 0         sym = SvPOKp(sv) ? SvPVX(sv) : Nullch;
133             }
134             // else {
135             // This causes the warnings from issue #2 https://github.com/Test-More/Test2-Plugin-Cover/issues/2
136             //sym = SvPV_nolen(sv);
137             // }
138              
139 0 0         if (!sym)
140 0           return NULL;
141 0 0         if (PL_op->op_private & HINT_STRICT_REFS)
142 0           return NULL;
143 0           cv = get_cv(sym, TRUE);
144 0           break;
145             }
146             got_rv:
147             {
148 11           SV **sp = &sv; /* Used in tryAMAGICunDEREF macro. */
149 11           tryAMAGICunDEREF(to_cv);
150             }
151 11           cv = (CV*)SvRV(sv);
152 11 50         if (SvTYPE(cv) == SVt_PVCV)
153 11           break;
154              
155             /* FALL THROUGH */
156             case SVt_PVHV:
157             case SVt_PVAV:
158 0           return NULL;
159              
160             case SVt_PVCV:
161 227           cv = (CV*)sv;
162 227           break;
163              
164             case SVt_PVGV:
165 0 0         if (!(isGV_with_GP(sv) && (cv = GvCVu((GV*)sv)))) {
    0          
    0          
    0          
    0          
166 0           HV *stash = NULL;
167 0           GV *gv = NULL;
168 0           cv = sv_2cv(sv, &stash, &gv, FALSE);
169              
170 0 0         if (gv) {
171 0           return gv;
172             }
173             }
174              
175 0 0         if (!cv) { /* would autoload in this situation */
176 0           return NULL;
177             }
178              
179 0           break;
180             }
181              
182 238 50         if (cv) {
183 238           GV *out = CvGV(cv);
184 238 50         if (out && isGV_with_GP(out)) {
    50          
    50          
    0          
185 238           return out;
186             }
187             }
188              
189 0           return NULL;
190             }
191              
192 14           void _sv_file_handler(SV *filename) {
193 15 50         if (filename == NULL) return;
194 14 100         if (!SvPOKp(filename)) return;
195              
196 13           STRLEN namelen = 0;
197 13 50         char *fname = SvPV(filename, namelen);
198              
199 13           add_entry(fname, namelen, "<>", 2);
200             }
201              
202 15           static OP* my_openhandler(pTHX) {
203 15           dSP;
204              
205 15           fetch_enabled;
206 15 50         if (SvTRUE(enabled)) {
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
207 15           SV **mark = PL_stack_base + TOPMARK;
208 15           I32 items = (I32)(sp - mark);
209              
210             // Only grab for 2-arg or 3-arg form
211 15 100         if (items == 2 || items == 3) {
    100          
212 14           _sv_file_handler(TOPs);
213             }
214             }
215              
216 15           return orig_openhandler(aTHX);
217             }
218              
219             //static OP* my_sysopenhandler(pTHX) {
220             // dSP;
221             //
222             // fetch_enabled;
223             // if (SvTRUE(enabled)) {
224             // SV **mark = PL_stack_base + TOPMARK;
225             // I32 ax = (I32)(mark - PL_stack_base + 1);
226             // I32 items = (I32)(sp - mark);
227             //
228             // if (items >= 2) {
229             // _sv_file_handler(PL_stack_base[ax + (1)]);
230             // }
231             // }
232             //
233             // return orig_sysopenhandler(aTHX);
234             //}
235              
236             MODULE = Test2::Plugin::Cover PACKAGE = Test2::Plugin::Cover
237              
238             PROTOTYPES: ENABLE
239              
240             BOOT:
241             {
242             //Initialize the global files HV, but only if we are not a threaded perl
243             #ifndef USE_ITHREADS
244 7           report = get_hv("Test2::Plugin::Cover::REPORT", GV_ADDMULTI);
245 7           SvREFCNT_inc(report);
246             #endif
247              
248 7           orig_subhandler = PL_ppaddr[OP_ENTERSUB];
249 7           PL_ppaddr[OP_ENTERSUB] = my_subhandler;
250              
251 7           orig_openhandler = PL_ppaddr[OP_OPEN];
252 7           PL_ppaddr[OP_OPEN] = my_openhandler;
253              
254             //orig_sysopenhandler = PL_ppaddr[OP_SYSOPEN];
255             //PL_ppaddr[OP_SYSOPEN] = my_sysopenhandler;
256             }