| 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 |  |  |  |  |  |  | } |