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 211           void add_entry(char *fname, STRLEN fnamelen, char *sname, STRLEN snamelen) {
26             fetch_report;
27 211           HV *file = NULL;
28 211           SV **existing_file = hv_fetch(report, fname, fnamelen, 0);
29 211 100         if (existing_file) {
30 73           file = (HV *)SvRV(*existing_file);
31             }
32             else {
33 138           file = newHV();
34 138           hv_store(report, fname, fnamelen, newRV_inc((SV *)file), 0);
35             }
36              
37 211           HV *sub = NULL;
38 211           SV **existing_sub = hv_fetch(file, sname, snamelen, 0);
39 211 100         if (existing_sub) {
40 59           sub = (HV *)SvRV(*existing_sub);
41             }
42             else {
43 152           sub = newHV();
44 152           hv_store(file, sname, snamelen, newRV_inc((SV *)sub), 0);
45             }
46              
47 211           fetch_from;
48 211 50         if (!(from && SvOK(from))) {
    50          
    0          
    0          
49 0           from = newSVpv("*", 1);
50             }
51             else {
52 211           from = sv_mortalcopy(from);
53 211           SvREFCNT_inc(from);
54             }
55              
56 211 100         if (!hv_exists_ent(sub, from, 0)) {
57 159           hv_store_ent(sub, from, from, 0);
58             }
59              
60 211           return;
61             }
62              
63 14033           static OP* my_subhandler(pTHX) {
64 14033           dSP;
65 14033           OP* out = orig_subhandler(aTHX);
66              
67 14033           fetch_enabled;
68 14033 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 13995 100         if (out != NULL && (out->op_type == OP_NEXTSTATE || out->op_type == OP_DBSTATE)) {
    100          
    50          
73 11752 50         char *fname = CopFILE(cCOPx(out));
74 11752           STRLEN namelen = strlen(fname);
75              
76             // Check for absolute paths and reject them. This is a very
77             // unix-oriented optimization.
78 11752 100         if (!strncmp(fname, "/", 1)) {
79 11616           fetch_root;
80              
81 11616 50         if (root != NULL && SvPOK(root)) {
    50          
82             STRLEN len;
83 11616           char *rt = NULL;
84 11616 50         rt = SvPV(root, len);
85              
86 19804 100         if (namelen < len) return out;
87              
88 8251 100         if (strncmp(fname, rt, len)) {
89 8251           return out;
90             }
91             }
92             }
93              
94 199           char *subname = NULL;
95 199           STRLEN sublen = 0;
96              
97 199           GV *my_gv = sub_to_gv(aTHX_ *SP);
98 199 50         if (my_gv != NULL) {
99 199           subname = GvNAME(my_gv);
100 199           sublen = strlen(subname);
101             }
102             else {
103 0           subname = "*";
104 0           sublen = 1;
105             }
106              
107 199           add_entry(fname, namelen, subname, sublen);
108             }
109              
110 2442           return out;
111             }
112              
113             // Copied and modified from Devel::NYTProf
114 199           static GV *sub_to_gv(pTHX_ SV *sv) {
115 199           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 199           switch (SvTYPE(sv)) {
121             default:
122 9 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 9           SV **sp = &sv; /* Used in tryAMAGICunDEREF macro. */
149 9           tryAMAGICunDEREF(to_cv);
150             }
151 9           cv = (CV*)SvRV(sv);
152 9 50         if (SvTYPE(cv) == SVt_PVCV)
153 9           break;
154              
155             /* FALL THROUGH */
156             case SVt_PVHV:
157             case SVt_PVAV:
158 0           return NULL;
159              
160             case SVt_PVCV:
161 190           cv = (CV*)sv;
162 190           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 199 50         if (cv) {
183 199           GV *out = CvGV(cv);
184 199 50         if (out && isGV_with_GP(out)) {
    50          
    50          
    0          
185 199           return out;
186             }
187             }
188              
189 0           return NULL;
190             }
191              
192 13           void _sv_file_handler(SV *filename) {
193 14 50         if (filename == NULL) return;
194 13 100         if (!SvPOKp(filename)) return;
195              
196 12           STRLEN namelen = 0;
197 12 50         char *fname = SvPV(filename, namelen);
198              
199 12           add_entry(fname, namelen, "<>", 2);
200             }
201              
202 14           static OP* my_openhandler(pTHX) {
203 14           dSP;
204              
205 14           fetch_enabled;
206 14 50         if (SvTRUE(enabled)) {
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
207 14           SV **mark = PL_stack_base + TOPMARK;
208 14           I32 items = (I32)(sp - mark);
209              
210             // Only grab for 2-arg or 3-arg form
211 14 100         if (items == 2 || items == 3) {
    100          
212 13           _sv_file_handler(TOPs);
213             }
214             }
215              
216 14           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 6           report = get_hv("Test2::Plugin::Cover::REPORT", GV_ADDMULTI);
245 6           SvREFCNT_inc(report);
246             #endif
247              
248 6           orig_subhandler = PL_ppaddr[OP_ENTERSUB];
249 6           PL_ppaddr[OP_ENTERSUB] = my_subhandler;
250              
251 6           orig_openhandler = PL_ppaddr[OP_OPEN];
252 6           PL_ppaddr[OP_OPEN] = my_openhandler;
253              
254             //orig_sysopenhandler = PL_ppaddr[OP_SYSOPEN];
255             //PL_ppaddr[OP_SYSOPEN] = my_sysopenhandler;
256             }